Mention support for BSD/OS 5.0.
[bpt/emacs.git] / lisp / tmm.el
CommitLineData
be010748 1;;; tmm.el --- text mode access to menu-bar
20062d6b 2
0595722b
GM
3;; Copyright (C) 1994, 1995, 1996, 2000, 2001
4;; Free Software Foundation, Inc.
20062d6b
RS
5
6;; Author: Ilya Zakharevich <ilya@math.mps.ohio-state.edu>
fc225f66 7;; Maintainer: FSF
20062d6b 8
d440e474 9;; This file is part of GNU Emacs.
20062d6b
RS
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation; either version 2, or (at your option)
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
b578f267
EN
22;; along with GNU Emacs; see the file COPYING. If not, write to the
23;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24;; Boston, MA 02111-1307, USA.
20062d6b 25
b578f267 26;;; Commentary:
20062d6b 27
b578f267 28;; To use this package add
20062d6b 29
b578f267
EN
30;; (autoload 'tmm-menubar 'tmm "Text mode substitute for menubar" t)
31;; (global-set-key [f10] 'tmm-menubar)
32;; to your .emacs file. You can also add your own access to different
33;; menus available in Window System Emacs modeling definition after
34;; tmm-menubar.
20062d6b 35
b578f267 36;;; Code:
20062d6b
RS
37
38(require 'electric)
20062d6b 39
4bef9110
SE
40(defgroup tmm nil
41 "Text mode access to menu-bar."
42 :prefix "tmm-"
43 :group 'menu)
44
20062d6b
RS
45;;; The following will be localized, added only to pacify the compiler.
46(defvar tmm-short-cuts)
fc225f66 47(defvar tmm-old-mb-map nil)
20062d6b
RS
48(defvar tmm-old-comp-map)
49(defvar tmm-c-prompt)
50(defvar tmm-km-list)
670ce6ea 51(defvar tmm-next-shortcut-digit)
20062d6b
RS
52(defvar tmm-table-undef)
53
e6a5c7de 54;;;###autoload (define-key global-map "\M-`" 'tmm-menubar)
b46324e6 55;;;###autoload (define-key global-map [f10] 'tmm-menubar)
77cc5db0 56;;;###autoload (define-key global-map [menu-bar mouse-1] 'tmm-menubar-mouse)
afb1835e 57
20062d6b 58;;;###autoload
77cc5db0 59(defun tmm-menubar (&optional x-position)
20062d6b 60 "Text-mode emulation of looking and choosing from a menubar.
77cc5db0
RS
61See the documentation for `tmm-prompt'.
62X-POSITION, if non-nil, specifies a horizontal position within the menu bar;
63we make that menu bar item (the one at that position) the default choice."
20062d6b
RS
64 (interactive)
65 (run-hooks 'menu-bar-update-hook)
fc225f66 66 ;; Obey menu-bar-final-items; put those items last.
77cc5db0
RS
67 (let ((menu-bar (tmm-get-keybind [menu-bar]))
68 menu-bar-item)
fc225f66
RS
69 (let ((list menu-bar-final-items))
70 (while list
71 (let ((item (car list)))
72 ;; ITEM is the name of an item that we want to put last.
73 ;; Find it in MENU-BAR and move it to the end.
74 (let ((this-one (assq item menu-bar)))
75 (setq menu-bar (append (delq this-one menu-bar)
76 (list this-one)))))
77 (setq list (cdr list))))
77cc5db0
RS
78 (if x-position
79 (let ((tail menu-bar)
80 this-one
81 (column 0))
82 (while (and tail (< column x-position))
83 (setq this-one (car tail))
84 (if (and (consp (car tail))
85 (consp (cdr (car tail)))
86 (stringp (nth 1 (car tail))))
87 (setq column (+ column
88 (length (nth 1 (car tail)))
89 1)))
90 (setq tail (cdr tail)))
91 (setq menu-bar-item (car this-one))))
92 (tmm-prompt menu-bar nil menu-bar-item)))
93
8e735883 94;;;###autoload
77cc5db0
RS
95(defun tmm-menubar-mouse (event)
96 "Text-mode emulation of looking and choosing from a menubar.
97This command is used when you click the mouse in the menubar
98on a console which has no window system but does have a mouse.
99See the documentation for `tmm-prompt'."
100 (interactive "e")
101 (tmm-menubar (car (posn-x-y (event-start event)))))
20062d6b 102
4bef9110 103(defcustom tmm-mid-prompt "==>"
670ce6ea
RS
104 "*String to insert between shortcut and menu item.
105If nil, there will be no shortcuts. It should not consist only of spaces,
4bef9110
SE
106or else the correct item might not be found in the `*Completions*' buffer."
107 :type 'string
108 :group 'tmm)
20062d6b
RS
109
110(defvar tmm-mb-map nil
111 "A place to store minibuffer map.")
112
4bef9110 113(defcustom tmm-completion-prompt
20062d6b
RS
114 "Press PageUp Key to reach this buffer from the minibuffer.
115Alternatively, you can use Up/Down keys (or your History keys) to change
116the item in the minibuffer, and press RET when you are done, or press the
10fe2d38 117marked letters to pick up your choice. Type C-g or ESC ESC ESC to cancel.
20062d6b 118"
670ce6ea
RS
119 "*Help text to insert on the top of the completion buffer.
120To save space, you can set this to nil,
4bef9110
SE
121in which case the standard introduction text is deleted too."
122 :type '(choice string (const nil))
123 :group 'tmm)
670ce6ea 124
4bef9110 125(defcustom tmm-shortcut-style '(downcase upcase)
670ce6ea
RS
126 "*What letters to use as menu shortcuts.
127Must be either one of the symbols `downcase' or `upcase',
4bef9110
SE
128or else a list of the two in the order you prefer."
129 :type '(choice (const downcase)
130 (const upcase)
131 (repeat (choice (const downcase) (const upcase))))
132 :group 'tmm)
670ce6ea 133
4bef9110 134(defcustom tmm-shortcut-words 2
670ce6ea
RS
135 "*How many successive words to try for shortcuts, nil means all.
136If you use only one of `downcase' or `upcase' for `tmm-shortcut-style',
4bef9110
SE
137specify nil for this variable."
138 :type '(choice integer (const nil))
139 :group 'tmm)
20062d6b
RS
140
141;;;###autoload
bdbc7685 142(defun tmm-prompt (menu &optional in-popup default-item)
20062d6b 143 "Text-mode emulation of calling the bindings in keymap.
77cc5db0
RS
144Creates a text-mode menu of possible choices. You can access the elements
145in the menu in two ways:
146 *) via history mechanism from minibuffer;
20062d6b
RS
147 *) Or via completion-buffer that is automatically shown.
148The last alternative is currently a hack, you cannot use mouse reliably.
bdbc7685
RS
149
150MENU is like the MENU argument to `x-popup-menu': either a
151keymap or an alist of alists.
152DEFAULT-ITEM, if non-nil, specifies an initial default choice.
153Its value should be an event that has a binding in MENU."
154 ;; If the optional argument IN-POPUP is t,
155 ;; then MENU is an alist of elements of the form (STRING . VALUE).
156 ;; That is used for recursive calls only.
157 (let ((gl-str "Menu bar") ;; The menu bar itself is not a menu keymap
158 ; so it doesn't have a name.
159 tmm-km-list out history history-len tmm-table-undef tmm-c-prompt
160 tmm-old-mb-map tmm-old-comp-map tmm-short-cuts
161 chosen-string choice
162 (not-menu (not (keymapp menu))))
20062d6b 163 (run-hooks 'activate-menubar-hook)
bdbc7685
RS
164 ;; Compute tmm-km-list from MENU.
165 ;; tmm-km-list is an alist of (STRING . MEANING).
166 ;; It has no other elements.
167 ;; The order of elements in tmm-km-list is the order of the menu bar.
e07436e1
DL
168 (mapc (lambda (elt)
169 (if (stringp elt)
170 (setq gl-str elt)
171 (and (listp elt) (tmm-get-keymap elt not-menu))))
bdbc7685
RS
172 menu)
173 ;; Choose an element of tmm-km-list; put it in choice.
174 (if (and not-menu (= 1 (length tmm-km-list)))
175 ;; If this is the top-level of an x-popup-menu menu,
176 ;; and there is just one pane, choose that one silently.
177 ;; This way we only ask the user one question,
178 ;; for which element of that pane.
179 (setq choice (cdr (car tmm-km-list)))
ae3f2f3c
RS
180 (unless tmm-km-list
181 (error "Empty menu reached"))
bdbc7685
RS
182 (and tmm-km-list
183 (let ((index-of-default 0))
184 (if tmm-mid-prompt
185 (setq tmm-km-list (tmm-add-shortcuts tmm-km-list))
186 t)
187 ;; Find the default item's index within the menu bar.
188 ;; We use this to decide the initial minibuffer contents
189 ;; and initial history position.
190 (if default-item
191 (let ((tail menu))
192 (while (and tail
193 (not (eq (car-safe (car tail)) default-item)))
194 ;; Be careful to count only the elements of MENU
195 ;; that actually constitute menu bar items.
196 (if (and (consp (car tail))
d0bca3c9
GM
197 (or (stringp (car-safe (cdr (car tail))))
198 (eq (car-safe (cdr (car tail))) 'menu-item)))
bdbc7685
RS
199 (setq index-of-default (1+ index-of-default)))
200 (setq tail (cdr tail)))))
201 (setq history (reverse (mapcar 'car tmm-km-list)))
202 (setq history-len (length history))
203 (setq history (append history history history history))
204 (setq tmm-c-prompt (nth (- history-len 1 index-of-default) history))
205 (add-hook 'minibuffer-setup-hook 'tmm-add-prompt)
ca85cf8a
RS
206 (save-excursion
207 (unwind-protect
208 (setq out
209 (completing-read
210 (concat gl-str " (up/down to change, PgUp to menu): ")
211 tmm-km-list nil t nil
212 (cons 'history (- (* 2 history-len) index-of-default))))
213 (save-excursion
214 (remove-hook 'minibuffer-setup-hook 'tmm-add-prompt)
215 (if (get-buffer "*Completions*")
216 (progn
217 (set-buffer "*Completions*")
218 (use-local-map tmm-old-comp-map)
219 (bury-buffer (current-buffer)))))
220 ))))
bdbc7685
RS
221 (setq choice (cdr (assoc out tmm-km-list)))
222 (and (null choice)
223 (> (length out) (length tmm-c-prompt))
224 (string= (substring out 0 (length tmm-c-prompt)) tmm-c-prompt)
225 (setq out (substring out (length tmm-c-prompt))
226 choice (cdr (assoc out tmm-km-list))))
ae3f2f3c 227 (and (null choice) out
bdbc7685
RS
228 (setq out (try-completion out tmm-km-list)
229 choice (cdr (assoc out tmm-km-list)))))
230 ;; CHOICE is now (STRING . MEANING). Separate the two parts.
231 (setq chosen-string (car choice))
232 (setq choice (cdr choice))
233 (cond (in-popup
234 ;; We just did the inner level of a -popup menu.
235 choice)
236 ;; We just did the outer level. Do the inner level now.
237 (not-menu (tmm-prompt choice t))
238 ;; We just handled a menu keymap and found another keymap.
239 ((keymapp choice)
240 (if (symbolp choice)
241 (setq choice (indirect-function choice)))
242 (condition-case nil
243 (require 'mouse)
244 (error nil))
245 (condition-case nil
246 (x-popup-menu nil choice) ; Get the shortcuts
247 (error nil))
248 (tmm-prompt choice))
249 ;; We just handled a menu keymap and found a command.
250 (choice
251 (if chosen-string
3132f319
KH
252 (progn
253 (setq last-command-event chosen-string)
254 (call-interactively choice))
bdbc7685 255 choice)))))
20062d6b 256
20062d6b
RS
257(defun tmm-add-shortcuts (list)
258 "Adds shortcuts to cars of elements of the list.
259Takes a list of lists with a string as car, returns list with
fc225f66
RS
260shortcuts added to these cars.
261Stores a list of all the shortcuts in the free variable `tmm-short-cuts'."
670ce6ea
RS
262 (let ((tmm-next-shortcut-digit ?0))
263 (mapcar 'tmm-add-one-shortcut (reverse list))))
20062d6b 264
670ce6ea
RS
265(defsubst tmm-add-one-shortcut (elt)
266;; uses the free vars tmm-next-shortcut-digit and tmm-short-cuts
267 (let* ((str (car elt))
268 (paren (string-match "(" str))
269 (pos 0) (word 0) char)
270 (catch 'done ; ??? is this slow?
271 (while (and (or (not tmm-shortcut-words) ; no limit on words
272 (< word tmm-shortcut-words)) ; try n words
273 (setq pos (string-match "\\w+" str pos)) ; get next word
274 (not (and paren (> pos paren)))) ; don't go past "(binding.."
275 (if (or (= pos 0)
276 (/= (aref str (1- pos)) ?.)) ; avoid file extensions
277 (let ((shortcut-style
278 (if (listp tmm-shortcut-style) ; convert to list
279 tmm-shortcut-style
280 (list tmm-shortcut-style))))
281 (while shortcut-style ; try upcase and downcase variants
282 (setq char (funcall (car shortcut-style) (aref str pos)))
283 (if (not (memq char tmm-short-cuts)) (throw 'done char))
284 (setq shortcut-style (cdr shortcut-style)))))
285 (setq word (1+ word))
286 (setq pos (match-end 0)))
287 (while (<= tmm-next-shortcut-digit ?9) ; no letter shortcut, pick a digit
288 (setq char tmm-next-shortcut-digit)
289 (setq tmm-next-shortcut-digit (1+ tmm-next-shortcut-digit))
290 (if (not (memq char tmm-short-cuts)) (throw 'done char)))
291 (setq char nil))
292 (if char (setq tmm-short-cuts (cons char tmm-short-cuts)))
293 (cons (concat (if char (concat (char-to-string char) tmm-mid-prompt)
294 ;; keep them lined up in columns
295 (make-string (1+ (length tmm-mid-prompt)) ?\ ))
296 str)
297 (cdr elt))))
298
299;; This returns the old map.
fe03654a 300(defun tmm-define-keys (minibuffer)
670ce6ea
RS
301 (let ((map (make-sparse-keymap)))
302 (suppress-keymap map t)
e07436e1
DL
303 (mapc
304 (lambda (c)
305 (if (listp tmm-shortcut-style)
306 (define-key map (char-to-string c) 'tmm-shortcut)
307 ;; only one kind of letters are shortcuts, so map both upcase and
308 ;; downcase input to the same
309 (define-key map (char-to-string (downcase c)) 'tmm-shortcut)
310 (define-key map (char-to-string (upcase c)) 'tmm-shortcut)))
670ce6ea
RS
311 tmm-short-cuts)
312 (if minibuffer
313 (progn
314 (define-key map [pageup] 'tmm-goto-completions)
315 (define-key map [prior] 'tmm-goto-completions)
316 (define-key map "\ev" 'tmm-goto-completions)
317 (define-key map "\C-n" 'next-history-element)
318 (define-key map "\C-p" 'previous-history-element)))
319 (prog1 (current-local-map)
320 (use-local-map (append map (current-local-map))))))
321
322(defun tmm-completion-delete-prompt ()
323 (set-buffer standard-output)
324 (goto-char 1)
325 (delete-region 1 (search-forward "Possible completions are:\n")))
b46324e6 326
20062d6b
RS
327(defun tmm-add-prompt ()
328 (remove-hook 'minibuffer-setup-hook 'tmm-add-prompt)
afb1835e 329 (add-hook 'minibuffer-exit-hook 'tmm-delete-map nil t)
b46324e6 330 (let ((win (selected-window)))
670ce6ea 331 (setq tmm-old-mb-map (tmm-define-keys t))
20062d6b
RS
332 ;; Get window and hide it for electric mode to get correct size
333 (save-window-excursion
fc225f66
RS
334 (let ((completions
335 (mapcar 'car minibuffer-completion-table)))
670ce6ea
RS
336 (or tmm-completion-prompt
337 (add-hook 'completion-setup-hook
338 'tmm-completion-delete-prompt 'append))
fc225f66 339 (with-output-to-temp-buffer "*Completions*"
670ce6ea
RS
340 (display-completion-list completions))
341 (remove-hook 'completion-setup-hook 'tmm-completion-delete-prompt))
0595722b
GM
342 (when tmm-completion-prompt
343 (set-buffer "*Completions*")
344 (let ((buffer-read-only nil))
345 (goto-char (point-min))
346 (insert tmm-completion-prompt))))
ca85cf8a 347 (save-selected-window
20062d6b
RS
348 (other-window 1) ; Electric-pop-up-window does
349 ; not work in minibuffer
ca85cf8a
RS
350 (Electric-pop-up-window "*Completions*")
351 (with-current-buffer "*Completions*"
352 (setq tmm-old-comp-map (tmm-define-keys nil))))
670ce6ea 353
20062d6b
RS
354 (insert tmm-c-prompt)))
355
356(defun tmm-delete-map ()
afb1835e 357 (remove-hook 'minibuffer-exit-hook 'tmm-delete-map t)
fc225f66
RS
358 (if tmm-old-mb-map
359 (use-local-map tmm-old-mb-map)))
20062d6b
RS
360
361(defun tmm-shortcut ()
fc225f66 362 "Choose the shortcut that the user typed."
20062d6b 363 (interactive)
670ce6ea
RS
364 (let ((c last-command-char) s)
365 (if (symbolp tmm-shortcut-style)
366 (setq c (funcall tmm-shortcut-style c)))
367 (if (memq c tmm-short-cuts)
fc225f66
RS
368 (if (equal (buffer-name) "*Completions*")
369 (progn
370 (beginning-of-buffer)
371 (re-search-forward
670ce6ea 372 (concat "\\(^\\|[ \t]\\)" (char-to-string c) tmm-mid-prompt))
fc225f66 373 (choose-completion))
c2a8d4a7
GM
374 ;; In minibuffer
375 (delete-region (minibuffer-prompt-end) (point-max))
e07436e1
DL
376 (mapc (lambda (elt)
377 (if (string=
378 (substring (car elt) 0
379 (min (1+ (length tmm-mid-prompt))
380 (length (car elt))))
381 (concat (char-to-string c) tmm-mid-prompt))
382 (setq s (car elt))))
fc225f66
RS
383 tmm-km-list)
384 (insert s)
385 (exit-minibuffer)))))
20062d6b
RS
386
387(defun tmm-goto-completions ()
388 (interactive)
fbe91bbd
GM
389 (let ((prompt-end (minibuffer-prompt-end)))
390 (setq tmm-c-prompt (buffer-substring prompt-end (point-max)))
391 (delete-region prompt-end (point-max)))
fc225f66 392 (switch-to-buffer-other-window "*Completions*")
20062d6b
RS
393 (search-forward tmm-c-prompt)
394 (search-backward tmm-c-prompt))
395
20062d6b
RS
396(defun tmm-get-keymap (elt &optional in-x-menu)
397 "Prepends (DOCSTRING EVENT BINDING) to free variable `tmm-km-list'.
398The values are deduced from the argument ELT, that should be an
fc225f66 399element of keymap, an `x-popup-menu' argument, or an element of
20062d6b 400`x-popup-menu' argument (when IN-X-MENU is not-nil).
77cc5db0
RS
401This function adds the element only if it is not already present.
402It uses the free variable `tmm-table-undef' to keep undefined keys."
dd81ca0d 403 (let (km str cache plist filter (event (car elt)))
20062d6b
RS
404 (setq elt (cdr elt))
405 (if (eq elt 'undefined)
406 (setq tmm-table-undef (cons (cons event nil) tmm-table-undef))
42d140b4
KH
407 (unless (assoc event tmm-table-undef)
408 (cond ((if (listp elt)
409 (or (keymapp elt) (eq (car elt) 'lambda))
410 (fboundp elt))
411 (setq km elt))
0595722b 412
42d140b4
KH
413 ((if (listp (cdr-safe elt))
414 (or (keymapp (cdr-safe elt))
415 (eq (car (cdr-safe elt)) 'lambda))
416 (fboundp (cdr-safe elt)))
417 (setq km (cdr elt))
418 (and (stringp (car elt)) (setq str (car elt))))
0595722b 419
42d140b4
KH
420 ((if (listp (cdr-safe (cdr-safe elt)))
421 (or (keymapp (cdr-safe (cdr-safe elt)))
422 (eq (car (cdr-safe (cdr-safe elt))) 'lambda))
423 (fboundp (cdr-safe (cdr-safe elt))))
424 (setq km (cdr (cdr elt)))
425 (and (stringp (car elt)) (setq str (car elt)))
426 (and str
427 (stringp (cdr (car (cdr elt)))) ; keyseq cache
428 (setq cache (cdr (car (cdr elt))))
429 cache (setq str (concat str cache))))
0595722b 430
42d140b4 431 ((eq (car-safe elt) 'menu-item)
0595722b 432 ;; (menu-item TITLE COMMAND KEY ...)
dd81ca0d 433 (setq plist (cdr-safe (cdr-safe (cdr-safe elt))))
0595722b
GM
434 (when (consp (car-safe plist))
435 (setq plist (cdr-safe plist)))
42d140b4 436 (setq km (nth 2 elt))
c19cc275 437 (setq str (eval (nth 1 elt)))
dd81ca0d
RS
438 (setq filter (plist-get plist :filter))
439 (if filter
440 (setq km (funcall filter km)))
42d140b4 441 (and str
ae3f2f3c 442 (consp (nth 3 elt))
437d9247
RS
443 (stringp (cdr (nth 3 elt))) ; keyseq cache
444 (setq cache (cdr (nth 3 elt)))
42d140b4
KH
445 cache
446 (setq str (concat str cache))))
0595722b 447
42d140b4
KH
448 ((if (listp (cdr-safe (cdr-safe (cdr-safe elt))))
449 (or (keymapp (cdr-safe (cdr-safe (cdr-safe elt))))
450 (eq (car (cdr-safe (cdr-safe (cdr-safe elt)))) 'lambda))
451 (fboundp (cdr-safe (cdr-safe (cdr-safe elt)))))
452 ; New style of easy-menu
453 (setq km (cdr (cdr (cdr elt))))
454 (and (stringp (car elt)) (setq str (car elt)))
455 (and str
456 (stringp (cdr (car (cdr (cdr elt))))) ; keyseq cache
457 (setq cache (cdr (car (cdr (cdr elt)))))
458 cache (setq str (concat str cache))))
0595722b 459
42d140b4
KH
460 ((stringp event) ; x-popup or x-popup element
461 (if (or in-x-menu (stringp (car-safe elt)))
462 (setq str event event nil km elt)
463 (setq str event event nil km (cons 'keymap elt))
464 ))))
20062d6b 465 (and km (stringp km) (setq str km))
2a9f2437
RS
466 ;; Verify that the command is enabled;
467 ;; if not, don't mention it.
468 (when (and km (symbolp km) (get km 'menu-enable))
469 (unless (eval (get km 'menu-enable))
470 (setq km nil)))
20062d6b
RS
471 (and km str
472 (or (assoc str tmm-km-list)
c19cc275 473 (push (cons str (cons event km)) tmm-km-list))))))
20062d6b 474
20062d6b 475(defun tmm-get-keybind (keyseq)
fc225f66 476 "Return the current binding of KEYSEQ, merging prefix definitions.
91a5e367 477If KEYSEQ is a prefix key that has local and global bindings,
fc225f66
RS
478we merge them into a single keymap which shows the proper order of the menu.
479However, for the menu bar itself, the value does not take account
480of `menu-bar-final-items'."
20062d6b 481 (let (allbind bind)
fc225f66
RS
482 (setq bind (key-binding keyseq))
483 ;; If KEYSEQ is a prefix key, then BIND is either nil
484 ;; or a symbol defined as a keymap (which satisfies keymapp).
485 (if (keymapp bind)
486 (setq bind nil))
487 ;; If we have a non-keymap definition, return that.
488 (or bind
489 (progn
490 ;; Otherwise, it is a prefix, so make a list of the subcommands.
491 ;; Make a list of all the bindings in all the keymaps.
492 (setq allbind (mapcar 'cdr (minor-mode-key-binding keyseq)))
493 (setq allbind (cons (local-key-binding keyseq) allbind))
494 (setq allbind (cons (global-key-binding keyseq) allbind))
495 ;; Merge all the elements of ALLBIND into one keymap.
e07436e1
DL
496 (mapc (lambda (in)
497 (if (and (symbolp in) (keymapp in))
498 (setq in (symbol-function in)))
499 (and in (keymapp in)
500 (if (keymapp bind)
501 (setq bind (nconc bind (copy-sequence (cdr in))))
502 (setq bind (copy-sequence in)))))
fc225f66
RS
503 allbind)
504 ;; Return that keymap.
505 bind))))
20062d6b
RS
506
507(add-hook 'calendar-load-hook (lambda () (require 'cal-menu)))
508
20062d6b
RS
509(provide 'tmm)
510
20062d6b 511;;; tmm.el ends here