initial commit
[emacs-init.git] / auto-install / lacarte.el
1 ;;; lacarte.el --- Execute menu items as commands, with completion.
2 ;;
3 ;; Filename: lacarte.el
4 ;; Description: Execute menu items as commands, with completion.
5 ;; Author: Drew Adams
6 ;; Maintainer: Drew Adams
7 ;; Copyright (C) 2005-2011, Drew Adams, all rights reserved.
8 ;; Created: Fri Aug 12 17:18:02 2005
9 ;; Version: 22.0
10 ;; Last-Updated: Tue Jan  4 10:59:52 2011 (-0800)
11 ;;           By: dradams
12 ;;     Update #: 638
13 ;; URL: http://www.emacswiki.org/cgi-bin/wiki/lacarte.el
14 ;; Keywords: menu-bar, menu, command, help, abbrev, minibuffer, keys,
15 ;;           completion, matching, local, internal, extensions,
16 ;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x
17 ;;
18 ;; Features that might be required by this library:
19 ;;
20 ;;   None
21 ;;
22 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 ;;
24 ;;; Commentary:
25 ;;
26 ;;  Q. When is a menu not a menu?  A. When it's a la carte.
27 ;;
28 ;;  Library La Carte lets you execute menu items as commands, with
29 ;;  completion.  You can use it as an alternative to standard library
30 ;;  `tmm.el'.
31 ;;
32 ;;  Type a menu item.  Completion is available.  Completion candidates
33 ;;  are of the form menu > submenu > subsubmenu > ... > menu item.
34 ;;  For example:
35 ;;
36 ;;    File > Open Recent > Cleanup list
37 ;;    File > Open Recent > Edit list...
38 ;;
39 ;;  When you choose a menu-item candidate, the corresponding command
40 ;;  is executed.
41 ;;
42 ;;  Put this in your init file (~/.emacs):
43 ;;
44 ;;    (require 'lacarte)
45 ;;
46 ;;  Suggested key bindings:
47 ;;
48 ;;    (global-set-key [?\e ?\M-x] 'lacarte-execute-command)
49 ;;    (global-set-key [?\M-`]     'lacarte-execute-menu-command)
50 ;;    (global-set-key [f10]       'lacarte-execute-menu-command)
51 ;;
52 ;;  (The latter two replace standard bindings for `tmm-menubar'.  On
53 ;;  MS Windows, `f10' is normally bound to `menu-bar-open', which uses
54 ;;  the Windows native keyboard access to menus.)
55 ;;
56 ;;  To really take advantage of La Carte, use it together with
57 ;;  Icicles.  Icicles is not required to be able to use La Carte, but
58 ;;  it enhances the functionality of `lacarte.el' considerably.
59 ;;  (Note: `lacarte.el' was originally called `icicles-menu.el'.)
60 ;;
61 ;;  If you use MS Windows keyboard accelerators, consider using
62 ;;  `lacarte-remove-w32-keybd-accelerators' as the value of
63 ;;  `lacarte-convert-menu-item-function'.  It removes any unescaped
64 ;;  `&' characters (indicating an accelerator) from the menu items.
65 ;;  One library that adds keyboard accelerators to your menu items is
66 ;;  `menuacc.el', by Lennart Borgman (< l e n n a r t . b o r g m a n
67 ;;  @ g m a i l . c o m >).
68 ;;
69 ;;
70 ;;  Commands defined here:
71 ;;
72 ;;    `lacarte-execute-command', `lacarte-execute-menu-command'.
73 ;;
74 ;;  Options defined here: `lacarte-convert-menu-item-function'.
75 ;;
76 ;;  Non-interactive functions defined here:
77 ;;
78 ;;    `lacarte-escape-w32-accel', `lacarte-get-a-menu-item-alist',
79 ;;    `lacarte-get-a-menu-item-alist-1',
80 ;;    `lacarte-get-overall-menu-item-alist', `lacarte-menu-first-p',
81 ;;    `lacarte-remove-w32-keybd-accelerators'.
82 ;;
83 ;;  Internal variables defined here:
84 ;;
85 ;;    `lacarte-history', `lacarte-menu-items-alist'.
86 ;;
87 ;;
88 ;;  Getting Started
89 ;;  ---------------
90 ;;
91 ;;  In your init file (`~/.emacs'), bind `ESC M-x' as suggested above:
92 ;;
93 ;;    (global-set-key [?\e ?\M-x] 'lacarte-execute-command)
94 ;;
95 ;;  Type `ESC M-x' (or `ESC ESC x', which is the same thing).  You are
96 ;;  prompted for a command or menu command to execute.  Just start
97 ;;  typing its name.  Each menu item's full name, for completion, has
98 ;;  its parent menu names as prefixes.
99 ;;
100 ;;  ESC M-x
101 ;;  Command:
102 ;;  Command: t [TAB]
103 ;;  Command: Tools >
104 ;;  Command: Tools > Compa [TAB]
105 ;;  Command: Tools > Compare (Ediff) > Two F [TAB]
106 ;;  Command: Tools > Compare (Ediff) > Two Files... [RET]
107 ;;
108 ;;
109 ;;  Not Just for Wimps and Noobs Anymore
110 ;;  ------------------------------------
111 ;;
112 ;;  *You* don't use menus.  Nah, they're too slow!  Only newbies and
113 ;;  wimps use menus.  Well not any more.  Use the keyboard to access
114 ;;  any menu item, without knowing where it is or what its full name
115 ;;  is.  Type just part of its name and use completion to get the
116 ;;  rest: the complete path and item name.
117 ;;
118 ;;
119 ;;  Commands and Menu Commands
120 ;;  --------------------------
121 ;;
122 ;;  You can bind either `lacarte-execute-menu-command' or
123 ;;  `lacarte-execute-command' to a key such as `ESC M-x'.
124 ;;
125 ;;  `lacarte-execute-menu-command' uses only menu commands.
126 ;;  `lacarte-execute-command' lets you choose among ordinary Emacs
127 ;;  commands, in addition to menu commands.  You can use a prefix arg
128 ;;  with `lacarte-execute-command' to get the same effect as
129 ;;  `lacarte-execute-menu-command'.
130 ;;
131 ;;  Use `lacarte-execute-command' if you don't care whether a command
132 ;;  is on a menu.  Then, if you want a command that affects a buffer,
133 ;;  just type `buf'.  This is especially useful if you use Icicles -
134 ;;  see below.
135 ;;
136 ;;  By default, in Icicle mode, `ESC M-x' is bound to
137 ;;  `lacarte-execute-command', and `M-`' is bound to
138 ;;  `lacarte-execute-menu-command'.
139 ;;
140 ;;
141 ;;  Icicles Enhances Dining A La Carte
142 ;;  ----------------------------------
143 ;;
144 ;;  Use Icicles with La Carte to get more power and convenience.
145 ;;
146 ;;  It is Icicles that lets you choose menu items a la carte, in fact.
147 ;;  That is, you can access them directly, wherever they might be in
148 ;;  the menu hierachy.  Without Icicles, you are limited to choosing
149 ;;  items by their menu-hierarchy prefixes, and you must complete the
150 ;;  entire menu prefix to the item, from the top of the menu on down.
151 ;;  With Icicles, you can directly match any parts of a menu item and
152 ;;  its hierarchy path.  Icicles is here:
153 ;;  http://www.emacswiki.org/cgi-bin/wiki/Icicles.
154 ;;
155 ;;  Type any part of a menu-item, then use the Page Up and Page Down
156 ;;  keys (`prior' and `next') to cycle through all menu commands that
157 ;;  contain the text you typed somewhere in their name.  You can match
158 ;;  within any menu or within all menus; that is, you can match any
159 ;;  part(s) of the menu-hierachy prefix.
160 ;;
161 ;;  You can use `S-TAB' to show and choose from all such "apropos
162 ;;  completions", just as you normally use `TAB' to show all prefix
163 ;;  completions (that is, ordinary completions).  Vanilla, prefix
164 ;;  completion is still available using `TAB', and you can cycle
165 ;;  through the prefix completions using the arrow keys.
166 ;;
167 ;;  You can use Icicles "progressive completion" to match multiple
168 ;;  parts of a menu item separately, in any order.  For example, if
169 ;;  you want a menu command that has to do with buffers and
170 ;;  highlighting, type `buf M-SPC hig S-TAB'.
171 ;;
172 ;;  Icicles apropos completion also lets you type a regular expression
173 ;;  (regexp) - it is matched against all of the possible menu items.
174 ;;  So, for instance, you could type `^e.+buff [next] [next]...' to
175 ;;  quickly cycle to menu command `Edit > Go To > Goto End of Buffer'.
176 ;;  Or type `.*print.*buf S-TAB' to choose from the list of all menu
177 ;;  commands that match `print' followed somewhere by `buf'.
178 ;;
179 ;;  If you know how to use regexps, you can easily and quickly get to
180 ;;  a menu command you want, or at least narrow the list of candidates
181 ;;  for completion and cycling.
182 ;;
183 ;;  Additional benefits of using Icicles with La Carte:
184 ;;
185 ;;  * When you cycle to a candidate menu item, or you complete to one
186 ;;    (entirely), the Emacs command associated with the menu item is
187 ;;    shown in the mode line of buffer `*Completions*'.
188 ;;
189 ;;  * You can use `M-h' to complete your minibuffer input against
190 ;;    commands, including menu-item commands, that you have entered
191 ;;    previously.  You can also use the standard history keys
192 ;;    (e.g. `M-p', `M-r') to access these commands.
193 ;;
194 ;;
195 ;;  Menu Organization Helps You Find a Command
196 ;;  ------------------------------------------
197 ;;
198 ;;  Unlike commands listed in a flat `*Apropos*' page, menu items are
199 ;;  organized, grouped logically by common area of application
200 ;;  (`File', `Edit',...).  This grouping is also available when
201 ;;  cycling completion candidates using Icicles, and you can take
202 ;;  advantage of it to hasten your search for the right command.
203 ;;
204 ;;  You want to execute a command that puts the cursor at the end of a
205 ;;  buffer, but you don't remember its name, what menu it might be a
206 ;;  part of, or where it might appear in that (possibly complex) menu.
207 ;;  With Icicles and La Carte, you type `ESC M-x' and then type
208 ;;  `buffer' at the prompt.  You use the Page Up and Page Down keys to
209 ;;  cycle through all menu items that contain the word `buffer'.
210 ;;
211 ;;  There are lots of such menu items.  But all items from the same
212 ;;  menu (e.g. `File') are grouped together.  You cycle quickly (not
213 ;;  reading) to the `Edit' menu, because you guess that moving the
214 ;;  cursor has more to do with editing than with file operations, tool
215 ;;  use, buffer choice, help, etc.  Then you cycle more slowly among
216 ;;  the `buffer' menu items in the `Edit' menu.  You quickly find
217 ;;  `Edit > Go To > Goto End of Buffer'.  QED.
218 ;;
219 ;;
220 ;;  Learn About Menu Items By Exploring Them
221 ;;  ----------------------------------------
222 ;;
223 ;;  With Icicles, you can display the complete documentation (doc
224 ;;  string) for the command corresponding to each menu item, as the
225 ;;  item appears in the minibuffer.  To do this, just cycle menu-item
226 ;;  candidates using `C-down' or `C-next', instead of `[down]' or
227 ;;  `[next]'.  The documentation appears in buffer `*Help*'.
228 ;;
229 ;;  In sum, if you use La Carte, you will want to use it with Icicles
230 ;;  - enjoy!
231 ;;
232 ;;
233 ;;  To Do?
234 ;;  ------
235 ;;
236 ;;  1. Provide sorting by menu-bar order, instead of alphabetically.
237 ;;  2. Echo key bindings for each completed menu item.
238 ;;
239 ;;  3. Maybe use tmm-get-bind?
240  
241 ;;(@> "Index")
242 ;;
243 ;;  If you have library `linkd.el' and Emacs 22 or later, load
244 ;;  `linkd.el' and turn on `linkd-mode' now.  It lets you easily
245 ;;  navigate around the sections of this doc.  Linkd mode will
246 ;;  highlight this Index, as well as the cross-references and section
247 ;;  headings throughout this file.  You can get `linkd.el' here:
248 ;;  http://dto.freeshell.org/notebook/Linkd.html.
249 ;;
250 ;;  (@> "Change log")
251 ;;  (@> "User Options")
252 ;;  (@> "Internal Variables")
253 ;;  (@> "Functions")
254  
255 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
256 ;;
257 ;;; Change log:
258 ;;
259 ;;(@* "Change log")
260 ;;
261 ;; 2011/01/04 dadams
262 ;;     Added autoload cookies for defgroup, defcustom, and commands.
263 ;; 2010/06/26 dadams
264 ;;    lacarte-execute-command: Protected Icicles vars with boundp.  Thx to Alexey Romanov.
265 ;; 2010/05/11 dadams
266 ;;     lacarte-get-a-menu-item-alist-1: Add keyboard shortcuts to item names.
267 ;;     Applied Icicles renamings (belatedly):
268 ;;       icicle-sort-functions-alist to icicle-sort-orders-alist,
269 ;;       icicle-sort-function to icicle-sort-comparer.
270 ;; 2009/12/25 dadams
271 ;;     Added: lacarte-execute-command, lacarte-menu-first-p.
272 ;;     lacarte-get-a-menu-item-alist-1: Handle :filter (e.g. File > Open Recent submenus).
273 ;;     lacarte-execute-menu-command:
274 ;;       Just let-bind lacarte-menu-items-alist - don't use unwind-protect.
275 ;;     lacarte-get-overall-menu-item-alist: Reset lacarte-menu-items-alist to nil.
276 ;;     lacarte-get-a-menu-item-alist: Set to the return value.
277 ;; 2009/07/29 dadams
278 ;;     Added: lacarte-history.
279 ;;     lacarte-execute-menu-command:
280 ;;       Use lacarte-history as the history list.  Use strict completion.
281 ;; 2009/07/26 dadams
282 ;;     lacarte-execute-menu-command: Use icicle-interactive-history as the history list.
283 ;; 2008/08/28 dadams
284 ;;     Renamed from alacarte to lacarte.  Confusion with alacarte Ubuntu source package.
285 ;; 2008/05/21 dadams
286 ;;     Renamed library icicles-menu.el to alacarte.el.
287 ;;     alacarte-execute-menu-command: Case-insensitive completion, by default.
288 ;; 2008/05/20 dadams
289 ;;     icicle-get-a-menu-item-alist-1: Don't add non-selectable item to alist.
290 ;; 2006/12/22 dadams
291 ;;     icicle-convert-menu-item-function: Use choice as :type, allowing nil.
292 ;;     :group 'icicles -> :group 'Icicles.
293 ;; 2006/10/16 dadams
294 ;;     icicle-get-overall-menu-item-alist: Include minor-mode keymaps.
295 ;; 2006/03/16 dadams
296 ;;     Added to Commentary.
297 ;; 2006/02/18 dadams
298 ;;     icicle-execute-menu-command: \s -> \\s.  (Thx to dslcustomer-211-74.vivodi.gr.)
299 ;; 2006/01/07 dadams
300 ;;     Added :link for sending bug reports.
301 ;; 2006/01/06 dadams
302 ;;     Changed defgroup to icicles-menu from icicles.
303 ;;     Added :link.
304 ;; 2005/11/08 dadams
305 ;;     icicle-execute-menu-command:
306 ;;       Reset icicle-menu-items-alist in unwind-protect.
307 ;;       Fix for dynamic menus Select and Paste, Buffers, and Frames:
308 ;;         Treat special cases of last-command-event.
309 ;;     icicle-get-overall-menu-item-alist: setq result of sort.
310 ;; 2005/11/05 dadams
311 ;;     Replaced icicle-menu-items with icicle-menu-items-alist (no need for both).
312 ;;     icicle-execute-menu-command: Set, don't bind icicle-menu-items-alist.
313 ;; 2005/08/23 dadams
314 ;;     icicle-execute-menu-command: renamed alist to icicle-menu-items-alist, so can
315 ;;       refer to it unambiguously in icicle-help-on-candidate (in icicles.el).
316 ;; 2005/08/19 dadams
317 ;;     Added: icicle-convert-menu-item-function, icicle-remove-w32-keybd-accelerators,
318 ;;            icicle-escape-w32-accel.
319 ;;
320 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
321 ;;
322 ;; This program is free software; you can redistribute it and/or modify
323 ;; it under the terms of the GNU General Public License as published by
324 ;; the Free Software Foundation; either version 3, or (at your option)
325 ;; any later version.
326
327 ;; This program is distributed in the hope that it will be useful,
328 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
329 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
330 ;; GNU General Public License for more details.
331
332 ;; You should have received a copy of the GNU General Public License
333 ;; along with this program; see the file COPYING.  If not, write to
334 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
335 ;; Floor, Boston, MA 02110-1301, USA.
336 ;;
337 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
338 ;;
339 ;;; Code:
340
341 (unless (fboundp 'replace-regexp-in-string) (require 'subr-21 nil t))
342
343 ;;;;;;;;;;;;;;;;;;;;;;;;;
344  
345 ;;(@* "User Options")
346
347 ;;; User Options -------------------------------------------
348
349 ;;;###autoload
350 (defgroup lacarte nil
351   "Execute menu items as commands, with completion."
352   :prefix "lacarte-" :group 'menu
353   :link `(url-link :tag "Send Bug Report"
354           ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=
355 lacarte.el bug: \
356 &body=Describe bug here, starting with `emacs -q'.  \
357 Don't forget to mention your Emacs and library versions."))
358   :link '(url-link :tag "Other Libraries by Drew"
359           "http://www.emacswiki.org/cgi-bin/wiki/DrewsElispLibraries")
360   :link '(url-link :tag "Download" "http://www.emacswiki.org/cgi-bin/wiki/lacarte.el")
361   :link '(url-link :tag "Description" "http://www.emacswiki.org/cgi-bin/wiki/LaCarte")
362   :link '(emacs-commentary-link :tag "Commentary" "lacarte.el")
363   )
364
365 ;;;###autoload
366 (defcustom lacarte-convert-menu-item-function nil
367   "*Function to call to convert a menu item.
368 Used by `lacarte-execute-menu-command'.  A typical use would be to
369 remove the `&' characters used in MS Windows menus to define keyboard
370 accelerators.  See `lacarte-remove-w32-keybd-accelerators'."
371   :type '(choice (const :tag "None" nil) function) :group 'lacarte)
372
373 ;; $$$ NOT YET IMPLEMENTED
374 ;; (defcustom lacarte-sort-menu-bar-order-flag nil
375 ;;   "*Non-nil means that `lacarte-execute-menu-command' uses menu-bar order.
376 ;; Nil means use alphabetic order.
377 ;; The order is what is used for completion.
378 ;; Note: Using a non-nil value imposes an extra sorting operation, which
379 ;;       slows down the creation of the completion-candidates list."
380 ;;   :type 'boolean :group 'lacarte)
381  
382 ;;; Internal Variables -------------------------------------
383
384 (defvar lacarte-history nil "History for menu items read using La Carte completion.")
385
386 ;; This is used also in `icicle-help-on-candidate', which is defined in Icicles
387 ;; (library `icicles-mcmd.el').
388 (defvar lacarte-menu-items-alist nil
389   "Alist of pairs (MENU-ITEM . COMMAND).
390 The pairs are defined by the current local and global keymaps.
391 MENU-ITEM is a menu item, with ancestor-menu prefixes.
392   Example: `(\"Files > Insert File...\" . insert-file)'.
393 COMMAND is the command  bound to the menu item.")
394  
395 ;;; Functions -------------------------------
396
397 ;;;###autoload
398 (defun lacarte-execute-command (&optional no-commands-p)
399   "Execute a menu-bar menu command or an ordinary command.
400 Type a menu item or a command name.  Completion is available.
401 With a prefix arg, only menu items are available.
402 Completion is not case-sensitive.  However, if you use Icicles, then
403 you can use `C-A' in the minibuffer to toggle case-sensitivity.
404
405 If you use Icicles, then you can also sort the completion candidates
406 in different ways, using `C-,'.  With Icicles, by default menu items
407 are sorted before non-menu commands, and menu items are highlighted
408 using face `icicle-special-candidate'."
409   (interactive "P")
410   (let ((lacarte-menu-items-alist         (lacarte-get-overall-menu-item-alist))
411         (completion-ignore-case           t) ; Not case-sensitive, by default.
412         (icicle-special-candidate-regexp  (and (not no-commands-p) ".* > \\(.\\|\n\\)*"))
413         (icicle-sort-orders-alist         (and (boundp 'icicle-sort-orders-alist)
414                                                (if no-commands-p
415                                                    icicle-sort-orders-alist
416                                                  (cons '("menu items first"
417                                                          .  lacarte-menu-first-p)
418                                                        icicle-sort-orders-alist))))
419         (icicle-sort-comparer             (and (boundp 'icicle-sort-comparer)
420                                                (if no-commands-p
421                                                    icicle-sort-comparer
422                                                  'lacarte-menu-first-p)))
423         choice cmd)
424     (unless no-commands-p
425       (mapatoms (lambda (symb)
426                   (when (commandp symb)
427                     (push (cons (symbol-name symb) symb) lacarte-menu-items-alist)))))
428     (setq choice  (completing-read (if no-commands-p "Menu command: " "Command: ")
429                                    lacarte-menu-items-alist nil t nil 'lacarte-history)
430           cmd     (cdr (assoc choice lacarte-menu-items-alist)))
431     (unless cmd (error "No such menu command"))
432     ;; Treat special cases of `last-command-event', reconstructing it for
433     ;; menu items that get their meaning from the click itself.
434     (cond ((eq cmd 'menu-bar-select-buffer)
435            (string-match " >\\s-+\\(.+\\)\\s-+\\*?%?\\s-+\\S-*\\s-*$" choice)
436            (setq choice (substring choice (match-beginning 1) (match-end 1)))
437            (when (string-match "  \\*?%?" choice)
438              (setq choice (substring choice 0 (match-beginning 0))))
439            (setq last-command-event choice))
440           ((eq cmd 'menu-bar-select-yank)
441            (string-match "Edit > Select and Paste > \\(.*\\)$" choice)
442            (setq last-command-event
443                  (substring choice (match-beginning 1) (match-end 1))))
444           ((eq cmd 'menu-bar-select-frame)
445            (string-match " >\\s-[^>]+>\\s-+\\(.+\\)$" choice)
446            (setq choice (substring choice (match-beginning 1) (match-end 1)))
447            (setq last-command-event choice)))
448     (call-interactively cmd)))
449
450 (defun lacarte-menu-first-p (s1 s2)
451   "Return non-nil if S1 is a menu item and S2 is not."
452   (save-match-data
453     (and (string-match " > " s1) (not (string-match " > " s2)))))    
454
455 ;;;###autoload
456 (defun lacarte-execute-menu-command ()
457   "Execute a menu-bar menu command.
458 Type a menu item.  Completion is available.
459 Completion is not case-sensitive.  However, if you use Icicles, then
460 you can use `C-A' in the minibuffer to toggle case-sensitivity.
461 If you use Icicles, then you can also sort the completion candidates
462 in different ways, using `C-,'."
463   (interactive)
464   (let* ((lacarte-menu-items-alist  (lacarte-get-overall-menu-item-alist))
465          (completion-ignore-case    t) ; Not case-sensitive, by default.
466          (menu-item                 (completing-read "Menu command: "
467                                                      lacarte-menu-items-alist
468                                                      nil t nil 'lacarte-history))
469          (cmd                       (cdr (assoc menu-item lacarte-menu-items-alist))))
470     (unless cmd (error "No such menu command"))
471     ;; Treat special cases of `last-command-event', reconstructing it for
472     ;; menu items that get their meaning from the click itself.
473     (cond ((eq cmd 'menu-bar-select-buffer)
474            (string-match " >\\s-+\\(.+\\)\\s-+\\*?%?\\s-+\\S-*\\s-*$"
475                          menu-item)
476            (setq menu-item (substring menu-item (match-beginning 1) (match-end 1)))
477            (when (string-match "  \\*?%?" menu-item)
478              (setq menu-item (substring menu-item 0 (match-beginning 0))))
479            (setq last-command-event menu-item))
480           ((eq cmd 'menu-bar-select-yank)
481            (string-match "Edit > Select and Paste > \\(.*\\)$" menu-item)
482            (setq last-command-event
483                  (substring menu-item (match-beginning 1) (match-end 1))))
484           ((eq cmd 'menu-bar-select-frame)
485            (string-match " >\\s-[^>]+>\\s-+\\(.+\\)$" menu-item)
486            (setq menu-item (substring menu-item (match-beginning 1) (match-end 1)))
487            (setq last-command-event menu-item)))
488     (call-interactively cmd)))
489
490 (defun lacarte-get-overall-menu-item-alist ()
491   "Alist formed from menu items in current active keymaps.
492 See `lacarte-get-a-menu-item-alist' for the structure.
493 As a side effect, this modifies `lacarte-get-a-menu-item-alist' and
494 then resets it to ()"
495   (let ((alist
496          (apply #'nconc
497                 (lacarte-get-a-menu-item-alist (assq 'menu-bar (current-local-map)))
498                 (lacarte-get-a-menu-item-alist (assq 'menu-bar (current-global-map)))
499                 (mapcar (lambda (map) (lacarte-get-a-menu-item-alist (assq 'menu-bar map)))
500                         (current-minor-mode-maps)))))
501     (setq lacarte-menu-items-alist ())
502     (if nil;; `lacarte-sort-menu-bar-order-flag' ; Not yet implemented.
503         (setq alist (sort alist SOME-PREDICATE))
504       alist)))
505
506 (defun lacarte-get-a-menu-item-alist (keymap)
507   "Alist of pairs (MENU-ITEM . COMMAND) defined by KEYMAP.
508 KEYMAP is any keymap that has menu items.
509 MENU-ITEM is a menu item, with ancestor-menu prefixes.
510   Example: `(\"Files > Insert File...\" . insert-file)'.
511 COMMAND is the command  bound to the menu item.
512 Returns `lacarte-menu-items-alist' which it modifies."
513   (setq lacarte-menu-items-alist ())
514   (lacarte-get-a-menu-item-alist-1 keymap)
515   (setq lacarte-menu-items-alist (nreverse lacarte-menu-items-alist)))
516
517 (defun lacarte-get-a-menu-item-alist-1 (keymap &optional root)
518   "Helper function for `lacarte-get-a-menu-item-alist'.
519 This calls itself recursively, to process submenus.
520 Returns `lacarte-menu-items-alist', which it modifies."
521   (let ((scan keymap))
522     (setq root (or root))               ; nil, for top level.
523     (while (consp scan)
524       (if (atom (car scan))
525           (setq scan (cdr scan))
526         (let ((defn (cdr (car scan)))
527               composite-name)
528           ;; Get REAL-BINDING for the menu item.
529           (cond
530             ;; (menu-item ITEM-STRING): non-selectable item - skip it.
531             ((and (eq 'menu-item (car-safe defn))
532                   (null (cdr-safe (cdr-safe defn))))
533              (setq defn nil))           ; So `keymapp' test, below, fails.
534
535             ;; (ITEM-STRING): non-selectable item - skip it.
536             ((and (stringp (car-safe defn)) (null (cdr-safe defn)))
537              (setq defn nil))           ; So `keymapp' test, below, fails.
538
539             ;; (menu-item ITEM-STRING REAL-BINDING . PROPERTIES), with `:filter'
540             ((and (eq 'menu-item (car-safe defn))
541                   (member :filter (cdr (cddr defn))))
542              (let ((filt  (cadr (member :filter (cdr (cddr defn))))))
543                (setq composite-name
544                      (concat root (and root " > ") (eval (cadr defn))
545                              (let ((keys  (car-safe (cdr-safe (cdr-safe (cdr-safe defn))))))
546                              (and (consp keys) (stringp (cdr keys)) (cdr keys)))))
547                (setq defn (if (functionp filt) ; Apply the filter to REAL-BINDING.
548                               (funcall filt (car (cddr defn)))
549                             (car (cddr defn))))))
550
551             ;; (menu-item ITEM-STRING REAL-BINDING . PROPERTIES)
552             ((eq 'menu-item (car-safe defn))
553              (setq composite-name
554                    (concat root (and root " > ") (eval (cadr defn))
555                            (let ((keys  (car-safe (cdr-safe (cdr-safe (cdr-safe defn))))))
556                              (and (consp keys) (stringp (cdr keys)) (cdr keys)))))
557              (setq defn (car (cddr defn))))
558
559             ;; (ITEM-STRING . REAL-BINDING) or
560             ;; (ITEM-STRING [HELP-STRING] (KEYBD-SHORTCUTS) . REAL-BINDING)
561             ((stringp (car-safe defn))
562              (setq composite-name (concat root (and root " > ") (eval (car defn))))
563              (setq defn (cdr defn))
564              ;; Skip HELP-STRING
565              (when (stringp (car-safe defn)) (setq defn (cdr defn)))
566              ;; Skip (KEYBD-SHORTCUTS): cached key-equivalence data for menu items.
567              ;; But first add shortcuts to composite name.
568              (when (and (consp defn) (consp (car defn)))
569                (when (stringp (cdar defn)) ; Add shortcuts to name.
570                  (setq composite-name (concat composite-name (cdar defn))))
571                (setq defn (cdr defn)))))
572
573           ;; If REAL-BINDING is a keymap, then recurse on it.
574           (when (keymapp defn)
575             ;; Follow indirections to ultimate symbol naming a command.
576             (while (and (symbolp defn) (fboundp defn) (keymapp (symbol-function defn)))
577               (setq defn (symbol-function defn)))
578             (if (eq 'keymap (car-safe defn))
579                 (lacarte-get-a-menu-item-alist-1 (cdr defn) composite-name)
580               (lacarte-get-a-menu-item-alist-1 (symbol-function defn) composite-name)))
581
582           ;; Add menu item + command pair to `lacarte-menu-items-alist' alist.
583           ;; Don't add it if `composite-name' is nil - that's a non-selectable item.
584           (when (and root composite-name (not (keymapp defn)))
585             (setq lacarte-menu-items-alist
586                   (cons
587                    (cons (if (and (functionp lacarte-convert-menu-item-function)
588                                   (stringp composite-name)) ; Could be nil
589                              (funcall lacarte-convert-menu-item-function composite-name)
590                            composite-name)
591                          defn)
592                    lacarte-menu-items-alist))))
593         (when (consp scan) (setq scan (cdr scan)))))
594     lacarte-menu-items-alist))
595
596 (defun lacarte-remove-w32-keybd-accelerators (menu-item)
597   "Remove `&' characters that define keyboard accelerators in MS Windows.
598 \"&&\" is an escaped `&' - it is replaced by a single `&'.
599 This is a candidate value for `lacarte-convert-menu-item-function'."
600   (replace-regexp-in-string "&&?" 'lacarte-escape-w32-accel menu-item))
601
602 (defun lacarte-escape-w32-accel (match-string)
603   "If STRING is \"&&\", then return \"&\".  Else return \"\"."
604   (if (> (length match-string) 1) "&" ""))
605
606 ;;;;;;;;;;;;;;;;;;;;;;;
607
608 (provide 'lacarte)
609
610 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
611 ;;; lacarte.el ends here