Mercurial > emacs
comparison lisp/tmm.el @ 10955:1bbdc8c907ea
Initial revision
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Sat, 11 Mar 1995 03:57:25 +0000 |
parents | |
children | 40810ac8d212 |
comparison
equal
deleted
inserted
replaced
10954:d9ab06338f6a | 10955:1bbdc8c907ea |
---|---|
1 ;;; tmm.el - text mode access to menu-bar | |
2 | |
3 ;; Copyright (C) 1994, 1995 Free Software Foundation, Inc. | |
4 | |
5 ;; Author: Ilya Zakharevich <ilya@math.mps.ohio-state.edu> | |
6 | |
7 ;; This file will soon be a part of GNU Emacs, and is made available under | |
8 ;; the same conditions. | |
9 | |
10 ;; GNU Emacs is free software; you can redistribute it and/or modify | |
11 ;; it under the terms of the GNU General Public License as published by | |
12 ;; the Free Software Foundation; either version 2, or (at your option) | |
13 ;; any later version. | |
14 | |
15 ;; GNU Emacs is distributed in the hope that it will be useful, | |
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 ;; GNU General Public License for more details. | |
19 | |
20 ;; You should have received a copy of the GNU General Public License | |
21 ;; along with GNU Emacs; see the file COPYING. If not, write to | |
22 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
23 | |
24 ;;; Commentary ============================================================ | |
25 | |
26 ;;; To use this package add | |
27 | |
28 ;;; (autoload 'tmm-menubar 'tmm "Text mode substitute for menubar" t) | |
29 ;;; (global-set-key [f10] 'tmm-menubar) | |
30 | |
31 ;;; to your .emacs file. You can also add your own access to different | |
32 ;;; menus available in Window System Emacs modelling definition after | |
33 ;;; tmm-menubar. | |
34 | |
35 (require 'electric) | |
36 (define-key completion-list-mode-map "\e\e" 'abort-recursive-edit) | |
37 (define-key completion-list-mode-map [left] 'backward-word) | |
38 (define-key completion-list-mode-map [right] 'forward-word) | |
39 ;(define-key minibuffer-local-must-match-map [pageup] 'tmm-goto-completions) | |
40 ;(define-key minibuffer-local-must-match-map [prior] 'tmm-goto-completions) | |
41 ;(define-key minibuffer-local-must-match-map "\ev" 'tmm-goto-completions) | |
42 (define-key minibuffer-local-must-match-map [up] 'previous-history-element) | |
43 (define-key minibuffer-local-must-match-map [down] 'next-history-element) | |
44 | |
45 ;;; The following will be localized, added only to pacify the compiler. | |
46 (defvar tmm-short-cuts) | |
47 (defvar tmm-old-mb-map) | |
48 (defvar tmm-old-comp-map) | |
49 (defvar tmm-c-prompt) | |
50 (defvar tmm-km-list) | |
51 (defvar tmm-table-undef) | |
52 | |
53 ;;;###autoload | |
54 (defun tmm-menubar () | |
55 "Text-mode emulation of looking and choosing from a menubar. | |
56 See the documentation for `tmm-prompt'." | |
57 (interactive) | |
58 (run-hooks 'menu-bar-update-hook) | |
59 (tmm-prompt (tmm-get-keybind [menu-bar]))) | |
60 | |
61 (defvar tmm-mid-prompt "==>" | |
62 "String to insert between shortcut and menu item or nil.") | |
63 | |
64 (defvar tmm-mb-map nil | |
65 "A place to store minibuffer map.") | |
66 | |
67 (defvar tmm-completion-prompt | |
68 "Press PageUp Key to reach this buffer from the minibuffer. | |
69 Alternatively, you can use Up/Down keys (or your History keys) to change | |
70 the item in the minibuffer, and press RET when you are done, or press the | |
71 marked letters to pick up your choice. ESC ESC to cancel. | |
72 " | |
73 "What insert on top of completion buffer.") | |
74 | |
75 ;;;###autoload | |
76 (defun tmm-prompt (bind &optional in-popup) | |
77 "Text-mode emulation of calling the bindings in keymap. | |
78 Creates a text-mode menu of possible choices. You can access the elements | |
79 in the menu: | |
80 *) Either via history mechanism from minibuffer; | |
81 *) Or via completion-buffer that is automatically shown. | |
82 The last alternative is currently a hack, you cannot use mouse reliably. | |
83 If the optional argument IN-POPUP is set, is argument-compatible with | |
84 `x-popup-menu', otherwise the argument BIND should be a cdr of sparse keymap." | |
85 (if in-popup (if bind (setq bind in-popup) (x-popup-menu nil in-popup))) | |
86 (let (gl-str tmm-km-list out compl-list compl-list-l tmm-table-undef tmm-c-prompt | |
87 tmm-old-mb-map tmm-old-comp-map tmm-short-cuts) | |
88 (run-hooks 'activate-menubar-hook) | |
89 (mapcar (function (lambda (elt) | |
90 (if (stringp elt) | |
91 (setq gl-str elt) | |
92 (and (listp elt) (tmm-get-keymap elt in-popup))) | |
93 )) bind) | |
94 (and tmm-km-list | |
95 (if tmm-mid-prompt | |
96 (setq tmm-km-list (reverse (tmm-add-shortcuts tmm-km-list))) | |
97 t) | |
98 (setq compl-list (mapcar 'car tmm-km-list)) | |
99 (setq compl-list-l (length compl-list)) | |
100 (setq compl-list (append compl-list compl-list compl-list compl-list)) | |
101 (setq tmm-c-prompt (nth (1- compl-list-l) compl-list)) | |
102 (add-hook 'minibuffer-setup-hook 'tmm-add-prompt) | |
103 (unwind-protect | |
104 (setq out | |
105 (completing-read | |
106 (concat gl-str " (up/down to change, PgUp to menu): ") | |
107 tmm-km-list nil t nil | |
108 (cons 'compl-list (* 2 compl-list-l)))) | |
109 ;;(add-hook 'minibuffer-setup-hook 'tmm-remove-shortcuts) | |
110 ;;(save-excursion | |
111 ;; (set-buffer "*Completions*") | |
112 ;; (use-local-map tmm-old-mb-map)) | |
113 (save-excursion | |
114 (set-buffer "*Completions*") | |
115 (use-local-map tmm-old-comp-map) | |
116 (bury-buffer (current-buffer))) | |
117 )) | |
118 (setq bind (cdr (assoc out tmm-km-list))) | |
119 (and (null bind) | |
120 (> (length out) (length tmm-c-prompt)) | |
121 (string= (substring out 0 (length tmm-c-prompt)) tmm-c-prompt) | |
122 (setq out (substring out (length tmm-c-prompt)) | |
123 bind (cdr (assoc out tmm-km-list)))) | |
124 (setq last-command-event (car bind)) | |
125 (setq bind (cdr bind)) | |
126 (if bind | |
127 (if in-popup (tmm-prompt t bind) | |
128 (if (keymapp bind) | |
129 (if (listp bind) | |
130 (progn | |
131 (condition-case nil | |
132 (require 'mouse) | |
133 (error nil)) | |
134 (condition-case nil | |
135 (x-popup-menu nil bind) ; Get the shortcuts | |
136 (error nil)) | |
137 (tmm-prompt bind)) | |
138 (tmm-prompt (symbol-value bind)) | |
139 ) | |
140 (if last-command-event | |
141 (call-interactively bind) | |
142 bind))) | |
143 gl-str))) | |
144 | |
145 (defun tmm-remove-shortcuts () | |
146 (use-local-map tmm-mb-map)) | |
147 | |
148 (defun tmm-add-shortcuts (list) | |
149 "Adds shortcuts to cars of elements of the list. | |
150 Takes a list of lists with a string as car, returns list with | |
151 shortcuts added to these cars. Adds the shortcuts to a free variable | |
152 `tmm-short-cuts'." | |
153 (mapcar (lambda (elt) | |
154 (let ((str (car elt)) f b) | |
155 (setq f (upcase (substring str 0 1))) | |
156 ;; If does not work, try beginning of the other word | |
157 (if (and (member f tmm-short-cuts) | |
158 (string-match " \\([^ ]\\)" str)) | |
159 (setq f (upcase (substring | |
160 str | |
161 (setq b (match-beginning 1)) (1+ b))))) | |
162 (if (member f tmm-short-cuts) | |
163 elt | |
164 (setq tmm-short-cuts (cons f tmm-short-cuts)) | |
165 (cons (concat f tmm-mid-prompt str) (cdr elt))))) | |
166 (reverse list))) | |
167 | |
168 (defun tmm-add-prompt () | |
169 (remove-hook 'minibuffer-setup-hook 'tmm-add-prompt) | |
170 (add-hook 'minibuffer-exit-hook 'tmm-delete-map) | |
171 (let ((map (make-sparse-keymap)) (win (selected-window))) | |
172 (mapcar (lambda (str) | |
173 (define-key map str 'tmm-shortcut) | |
174 (define-key map (downcase str) 'tmm-shortcut)) | |
175 tmm-short-cuts) | |
176 (define-key map [pageup] 'tmm-goto-completions) | |
177 (define-key map [prior] 'tmm-goto-completions) | |
178 (define-key map "\ev" 'tmm-goto-completions) | |
179 (define-key map "\e\e" 'abort-recursive-edit) | |
180 (setq tmm-old-mb-map (current-local-map)) | |
181 (use-local-map (append map (cdr tmm-old-mb-map))) | |
182 ;; Get window and hide it for electric mode to get correct size | |
183 (save-window-excursion | |
184 (minibuffer-completion-help) | |
185 (set-buffer "*Completions*") | |
186 (goto-char 1) | |
187 (insert tmm-completion-prompt) | |
188 ) | |
189 (save-excursion | |
190 (other-window 1) ; Electric-pop-up-window does | |
191 ; not work in minibuffer | |
192 (set-buffer (window-buffer (Electric-pop-up-window "*Completions*"))) | |
193 (setq tmm-old-comp-map (current-local-map)) | |
194 (use-local-map (append map (cdr tmm-old-comp-map))) | |
195 (select-window win) ; Cannot use | |
196 ; save-window-excursion, since | |
197 ; it restores the size | |
198 ) | |
199 (insert tmm-c-prompt))) | |
200 | |
201 (defun tmm-delete-map () | |
202 (remove-hook 'minibuffer-exit-hook 'tmm-delete-map) | |
203 (use-local-map tmm-old-mb-map)) | |
204 | |
205 (defun tmm-shortcut () | |
206 (interactive) | |
207 (let ((c (upcase (char-to-string last-command-char))) s) | |
208 (if (member c tmm-short-cuts) | |
209 (if (equal (buffer-name) "*Completions*") | |
210 (progn | |
211 (beginning-of-buffer) | |
212 (re-search-forward | |
213 (concat "\\(^\\|[ \t]\\)" c tmm-mid-prompt)) | |
214 (choose-completion)) | |
215 (erase-buffer) ; In minibuffer | |
216 (mapcar (lambda (elt) | |
217 (if (string= | |
218 (substring (car elt) 0 | |
219 (min (1+ (length tmm-mid-prompt)) | |
220 (length (car elt)))) | |
221 (concat c tmm-mid-prompt)) | |
222 (setq s (car elt)))) | |
223 tmm-km-list) | |
224 (insert s) | |
225 (exit-minibuffer))))) | |
226 | |
227 (defun tmm-goto-completions () | |
228 (interactive) | |
229 (setq tmm-c-prompt (buffer-string)) | |
230 (erase-buffer) | |
231 (switch-to-buffer-other-window | |
232 "*Completions*") | |
233 (search-forward tmm-c-prompt) | |
234 (search-backward tmm-c-prompt)) | |
235 | |
236 | |
237 (defun tmm-get-keymap (elt &optional in-x-menu) | |
238 "Prepends (DOCSTRING EVENT BINDING) to free variable `tmm-km-list'. | |
239 The values are deduced from the argument ELT, that should be an | |
240 element of keymap, on `x-popup-menu' argument, or an element of | |
241 `x-popup-menu' argument (when IN-X-MENU is not-nil). | |
242 Does it only if it is not already there. Uses free variable | |
243 `tmm-table-undef' to keep undefined keys." | |
244 (let (km str cache (event (car elt))) | |
245 (setq elt (cdr elt)) | |
246 (if (eq elt 'undefined) | |
247 (setq tmm-table-undef (cons (cons event nil) tmm-table-undef)) | |
248 (or | |
249 (assoc event tmm-table-undef) | |
250 (and (if (listp elt) | |
251 (keymapp elt) | |
252 (fboundp elt)) | |
253 (setq km elt)) | |
254 (and (if (listp (cdr-safe elt)) | |
255 (keymapp (cdr-safe elt)) | |
256 (fboundp (cdr-safe elt))) | |
257 (setq km (cdr elt)) | |
258 (and (stringp (car elt)) (setq str (car elt)))) | |
259 (and (if (listp (cdr-safe (cdr-safe elt))) | |
260 (keymapp (cdr-safe (cdr-safe elt))) | |
261 (fboundp (cdr-safe (cdr-safe elt)))) | |
262 (setq km (cdr (cdr elt))) | |
263 (and (stringp (car elt)) (setq str (car elt))) | |
264 (or (and str | |
265 (stringp (cdr (car (cdr elt)))) ; keyseq cache | |
266 (setq cache (cdr (car (cdr elt)))) | |
267 cache (setq str (concat str cache))) str)) | |
268 (and (if (listp (cdr-safe (cdr-safe (cdr-safe elt)))) | |
269 (keymapp (cdr-safe (cdr-safe (cdr-safe elt)))) | |
270 (fboundp (cdr-safe (cdr-safe (cdr-safe elt))))) | |
271 ; New style of easy-menu | |
272 (setq km (cdr (cdr (cdr elt)))) | |
273 (and (stringp (car elt)) (setq str (car elt))) | |
274 (or (and str | |
275 (stringp (cdr (car (cdr (cdr elt))))) ; keyseq cache | |
276 (setq cache (cdr (car (cdr (cdr elt))))) | |
277 cache (setq str (concat str cache))) | |
278 str)) | |
279 (and (stringp event) ; x-popup or x-popup element | |
280 (if (or in-x-menu (stringp (car-safe elt))) | |
281 (setq str event event nil km elt) | |
282 (setq str event event nil km (cons 'keymap elt)) | |
283 ))) | |
284 (and km (stringp km) (setq str km)) | |
285 (and km str | |
286 (or (assoc str tmm-km-list) | |
287 (setq tmm-km-list | |
288 (cons (cons str (cons event km)) tmm-km-list))) | |
289 )))) | |
290 | |
291 | |
292 (defun tmm-get-keybind (keyseq) | |
293 "Gets binding from all the tables, can have some junk inside." | |
294 (let (allbind bind) | |
295 (setq allbind (mapcar 'cdr (minor-mode-key-binding keyseq))) | |
296 (setq allbind (append allbind (list (local-key-binding keyseq)))) | |
297 (setq allbind (append allbind (list (global-key-binding keyseq)))) | |
298 ; list of bindings | |
299 (mapcar (lambda (in) | |
300 (if (and (symbolp in) (keymapp in)) | |
301 (setq in (symbol-value in))) | |
302 (and in | |
303 (or (eq bind 'undefined) (not bind) | |
304 (and (keymapp bind) (keymapp in))) | |
305 (if (keymapp bind) | |
306 (setq bind (append bind (cdr in))) | |
307 (setq bind in) | |
308 ) | |
309 ) | |
310 ) | |
311 allbind) | |
312 bind)) | |
313 | |
314 (add-hook 'calendar-load-hook (lambda () (require 'cal-menu))) | |
315 | |
316 | |
317 (provide 'tmm) | |
318 | |
319 | |
320 ;;; tmm.el ends here |