aboutsummaryrefslogtreecommitdiff
path: root/emacs/.emacs.d/lisp/my/generic-search.el
blob: 3db5b08d15b25184d24aab581365722a1c6801ad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
;;; generic-search.el -- A search result UI -*- lexical-binding: t -*-

;; Copyright (C) 2023 Free Software Foundation.

;; Author: Yuchen Pei <id@ypei.org>
;; Package-Requires: ((emacs "28.2"))

;; This file is part of dotfiles.

;; dotfiles is free software: you can redistribute it and/or modify it
;; under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.

;; dotfiles is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; Affero General Public License for more details.

;; You should have received a copy of the GNU Affero General Public
;; License along with dotfiles.  If not, see
;; <https://www.gnu.org/licenses/>.

;;; Commentary:

;; A search result UI. A generic search result mode displaying a list
;; of things, and action on an item


;;; Code:

(defvar-local generic-search-transformer nil)
(defvar-local generic-search-formatter nil)
(defvar-local generic-search-default-action nil)
(defvar-local generic-search-results nil)
(defvar-local generic-search-keymap nil)

(defvar generic-search-default-transformer 'identity)
(defvar generic-search-default-formatter 'pp)
(defvar generic-search-default-default-action 'generic-search-message-pp)
(defvar generic-search-default-keymap button-map)

(defun generic-search-message-pp (data)
  (interactive)
  (message (pp data)))

(define-derived-mode generic-search-mode special-mode "Generic search"
  "Search results.")

(defun generic-search-buffer-name (name)
  (format "*generic-search %s*" name))

(defun generic-search-open (results name &optional display-options)
  (let ((buffer-name (generic-search-buffer-name name)))
    (with-current-buffer (get-buffer-create buffer-name)
      (generic-search-mode)
      (setq generic-search-results results
            generic-search-formatter
            (or (alist-get 'formatter display-options)
                generic-search-default-formatter)
            generic-search-default-action
            (or (alist-get 'default-action display-options)
                generic-search-default-default-action)
            generic-search-keymap
            (or (alist-get 'keymap display-options)
                generic-search-default-keymap)
            generic-search-transformer
            (or (alist-get 'transfomer display-options
                           generic-search-default-transformer)))
      (generic-search-update)
      (switch-to-buffer-other-window buffer-name))))

(defun generic-search-update ()
  (let ((inhibit-read-only t))
    (erase-buffer)
    (insert (format "%s Results:" (length generic-search-results)))
    (seq-do (lambda (result)
              (insert "\n----\n")
              (let ((start (point)))
                (insert
                 (funcall generic-search-formatter result))
                (make-text-button start (point)
                                  'action generic-search-default-action
                                  'button-data
                                  (funcall generic-search-transformer result)
                                  'keymap generic-search-keymap)))
            generic-search-results)
    (goto-char (point-min))
    (forward-button 1)))

(defun generic-search-refresh ()
  (interactive)
  (generic-search-update))

(define-key generic-search-mode-map "\t" 'forward-button)
(define-key generic-search-mode-map [backtab] 'backward-button)
(define-key generic-search-mode-map "g" 'generic-search-refresh)

(provide 'generic-search)