-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathpopper-echo.el
266 lines (224 loc) · 10.5 KB
/
popper-echo.el
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
;;; popper-echo.el --- Show a popup list in the echo area when cycling them -*- lexical-binding: t -*-
;; Copyright (C) 2023 Free Software Foundation, Inc.
;; Author: Karthik Chikmagalur <[email protected]>
;; Version: 0.45
;; Package-Requires: ((emacs "26.1"))
;; Keywords: convenience
;; URL: https://github.com/karthink/popper
;; This file is NOT part of GNU Emacs.
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This program 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 General Public License for more details.
;; For a full copy of the GNU General Public License
;; see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Popper-echo is a minor-mode to display a list of popup names in the echo area
;; when toggling or cycling popups. These popups can be accessed directly using
;; dispatch keybinds. See Popper for how to classify a buffer as a popup.
;; COMMANDS:
;; popper-echo-mode : Turn on the echo area display
;; CUSTOMIZATION:
;; `popper-echo-lines': The number of echo area/minibuffer lines to use when
;; showing a list of popups
;;
;; `popper-echo-dispatch-keys': A list of strings or characters representing the
;; keybindings to access popups shown in the echo area.
;;
;; `popper-echo-dispatch-persist': A boolean to control whether the dispatch
;; menu stays open after choosing a popup.
;;
;; `popper-echo-transform-function': A function to transform the display of
;; these popups, such as by truncating buffer names, etc.
;;; Code:
(require 'popper)
(defcustom popper-echo-transform-function nil
"Function to transform buffer names.
This is called on buffer-names displayed by `popper-echo'.
This function should accept a
string (the buffer name) and return a transformed string."
:type 'function
:group 'popper)
(defcustom popper-echo-lines 2
"Number of minibuffer lines used to show popup buffer names by `popper-echo'.
This has no effect when popper-echo-mode is turned off."
:type 'integer
:group 'popper)
(defcustom popper-echo-dispatch-persist t
"Controls whether the `popper-echo' dispatch menu is persistent."
:type 'boolean
:group 'popper)
(defcustom popper-echo-dispatch-actions nil
"Controls whether `popper-echo' dispatch actions are bound.
When true, you can
- Kill popup buffers with k
- Raise popup buffers with ^
when using the dispatch menu by prefixing the dispatch keys with them.
NOTE: This feature is experimental."
:type 'boolean
:group 'popper)
(defcustom popper-echo-dispatch-keys '("M-0" "M-1" "M-2" "M-3" "M-4"
"M-5" "M-6" "M-7" "M-8" "M-9")
"List of keys used for dispatching to popup buffers.
The first element is bound to the currently open popup.
Each entry in the list can be a character or a string suitable
for the kbd macro. These keys are available when using
popper-echo-mode.
Examples:
\\='(?q ?w ?e ?r ?t ?y ?u ?i ?o ?p)
\\='(\"M-1\" \"M-2\" \"M-3\" \"M-4\" \"M-5\")
This variable has no effect when popper-echo-mode is turned
off."
:type '(group character string)
:group 'popper)
(defface popper-echo-area-buried
'((t :inherit shadow))
"Echo area face for buried popups."
:group 'popper)
(defface popper-echo-area
'((t :inverse-video t
:weight bold))
"Echo area face for opened popup."
:group 'popper)
(defface popper-echo-dispatch-hint
'((t :inherit bold))
"Echo area face for popper dispatch key hints."
:group 'popper)
;; Notify in echo area:
(defun popper-echo ()
"Show popup list in the echo area when cycling popups."
(let* ((message-log-max nil)
(grp-symb (when popper-group-function
(funcall popper-group-function)))
(buried-popups (thread-last (alist-get grp-symb popper-buried-popup-alist nil nil 'equal)
(mapcar #'cdr)
(cl-remove-if-not #'buffer-live-p)
(mapcar #'buffer-name)
(delete-dups)))
(group (and grp-symb (concat "Group ("
(truncate-string-to-width (format "%S" grp-symb) 20 nil nil t)
"): ")))
(open-popup (buffer-name))
(dispatch-keys-extended (append (cdr popper-echo-dispatch-keys)
(make-list (max 0 (- (length buried-popups)
(1- (length popper-echo-dispatch-keys))))
nil)))
(popup-strings
(cl-reduce #'concat
(cons
(if-let ((transform popper-echo-transform-function))
(funcall transform open-popup)
(propertize open-popup 'face 'popper-echo-area))
(cl-mapcar (lambda (key buf)
(concat
(propertize ", " 'face 'popper-echo-area-buried)
(propertize "[" 'face 'popper-echo-area-buried)
(and key
(concat
(propertize (if (characterp key)
(char-to-string key)
key)
'face 'popper-echo-dispatch-hint)
(propertize ":" 'face 'popper-echo-area-buried)))
(if-let ((transform popper-echo-transform-function))
(funcall transform buf)
(concat
(propertize buf 'face 'popper-echo-area-buried)))
(propertize "]" 'face 'popper-echo-area-buried)))
dispatch-keys-extended
buried-popups)))))
(let* ((max-width (- (* popper-echo-lines (frame-width)) (if group (length group) 11)))
(plen (length popup-strings))
(space-p (> max-width plen)))
(message "%s"
(concat
(or group "Popups: ")
(substring popup-strings 0 (if space-p plen max-width))
(unless space-p
(propertize "..." 'face 'popper-echo-area-buried)))))
(set-transient-map (let ((map (make-sparse-keymap))
(i 0))
(dolist (keybind popper-echo-dispatch-keys map)
(define-key map (cond
((characterp keybind)
(make-vector 1 keybind))
((stringp keybind)
(kbd keybind)))
(popper-echo--dispatch-toggle i (cons open-popup
buried-popups)))
(when popper-echo-dispatch-actions
(define-key map
(kbd
(concat "k " (cond
((characterp keybind)
(char-to-string keybind))
((stringp keybind)
keybind))))
(popper-echo--dispatch-kill i (cons open-popup
buried-popups)))
(define-key map
(kbd
(concat "^ " (cond
((characterp keybind)
(char-to-string keybind))
((stringp keybind)
keybind))))
(popper-echo--dispatch-raise i (cons open-popup
buried-popups))))
(setq i (1+ i)))))))
(defun popper-echo--dispatch-toggle (i buf-list)
"Return a function to switch to buffer I in list BUF-LIST.
This is used to create functions for switching between popups
quickly."
(lambda (&optional arg)
(interactive "P")
(when-let ((buf (nth i buf-list)))
(unless arg (popper-close-latest))
(display-buffer buf)
(popper--update-popups))
(when popper-echo-dispatch-persist (popper-echo))))
(defun popper-echo--dispatch-kill (i buf-list)
"Return a function to Kill buffer I in list BUF-LIST."
(lambda ()
(interactive)
(let* ((buf (nth i buf-list))
(win (get-buffer-window buf)))
(kill-buffer buf)
(popper--delete-popup win))
(popper--update-popups)
(when (and popper-echo-dispatch-persist
popper-open-popup-alist)
(popper-echo))))
(defun popper-echo--dispatch-raise (i buf-list)
"Return a function to Kill buffer I in list BUF-LIST."
(lambda ()
(interactive)
(let* ((buf (nth i buf-list)))
(popper-toggle-type buf))
(popper--update-popups)
(when (and popper-echo-dispatch-persist
popper-open-popup-alist)
(popper-echo))))
;;;###autoload
(define-minor-mode popper-echo-mode
"Toggle Popper Echo mode.
Show popup names in cycling order in the echo area when
performing an action that involves showing a popup. These popups
can be accessed directly or acted upon by using quick keys (see
`popper-echo-dispatch-keys').
To define buffers as popups and customize popup display, see
`popper-mode'."
:global t
:lighter ""
:group 'popper
(if popper-echo-mode
(progn
(add-hook 'popper-open-popup-hook 'popper-echo)
(unless popper-mode (popper-mode 1)))
(remove-hook 'popper-open-popup-hook 'popper-echo)))
(provide 'popper-echo)
;;; popper-echo.el ends here