notes from /dev/null

by Charles Choi 최민수

Customizing the Emacs Tools Menu

24 Oct 2023  Charles Choi

Truth be told, I’ve always found the default Emacs Tools menu to be weird. But that’s really a matter of taste and rather than litigate the default configuration of the Tools menu, let’s talk about how you can customize the Tools menu to your liking.

Some Background on Emacs Menus

Emacs menus are defined as keymaps, a data structure that holds information like the label, command, and bindings (key or mouse) per menu entry stored in a keymap. Menu keymaps can be edited, which enables one to arbitrarily customize them to their desired taste.

Identifying Existing Menu Items

Use the command describe-key (C-h k) to identify an existing menu item selected by the mouse. An Emacs window describing the command will be displayed showing the hierarchical keymap path to the menu item, with each keymap identified between angled brackets (<>). We’ll use this keymap path to identify menu items to remove or add.

For a more comprehensive view of a keymap, use the describe-keymap function. This enables you to see all the keymap paths in one step. To see keymap paths (or bindings) of the Tools menu, issue the following command:

(describe-keymap menu-bar-tools-menu)

Removing Menu Items

To demonstrate removing a menu item, let’s remove the default item Tools ‣ Project Support (EDE). Using the describe-key function, we see that its keymap path is <menu-bar> <tools> <ede>. Use the function define-key to remove (or hide) the menu entry. The function signature for define-key is shown below:

(define-key KEYMAP KEY DEF &optional REMOVE)

To remove the EDE menu item use the following argument values:

Argument Value Notes
KEYMAP global-map Default global keymap.
KEY [menu-bar tools ede] Vector of hierarchical keymap path to menu item.
DEF nil In versions older than 29.1, a nil value will hide the item.
REMOVE t Only available in 29.1+. If this value is non-nil, then the item will be removed.

Note that the REMOVE argument is new in Emacs 29.1. Beforehand you could only hide a menu entry when DEF is set to nil. Equipped with the above info, we can remove Tools ‣ Project Support (EDE) using the following Elisp:

(define-key global-map [menu-bar tools ede] nil t)

Adding Menu Items

While Emacs provides multiple approaches to adding a menu item, easy-menu-add-item is relatively straightforward as it allows one to pass either a vector type or another menu (defined by easy-menu-define) as the ITEM argument.

(easy-menu-add-item MAP PATH ITEM &optional BEFORE)

To see the above command in action, let’s implement a menu item for magit-status and place it above the existing menu item whose label is “Version Control”. We will also make it conditionally visible if the default-directory of the current Emacs window is under version control.

(easy-menu-add-item global-map '(menu-bar tools)
                    ["Magit Status"
                     :visible (vc-responsible-backend default-directory t)
                     :help "Show the status of the current Git repository in a buffer"]
                     "Version Control")

If ITEM is a vector type, then different keywords are supported as described here. Use describe-function to get documentation on easy-menu-add-item.

Defining Separators

The new 29.1 keymap-set-after function lets you add a menu separator with the benefit of defining keywords such as :enable or :visible to provide control over when the separator is displayed. An example of this is described below.

(keymap-set-after (lookup-key global-map [menu-bar tools])
  '(menu-item "--")

My Tools Menu

With the above you are now equipped to configure your Tools (or really, any menu) to your taste. As of this writing, my customized Tools menu looks like this on Emacs 29.1:

The Elisp to configure the above menu is found at this source.

Closing Thoughts

Among the many benefits that menus provide is to lower the cognitive load of memorizing commands. But those benefits are only seen if the menu commands are useful to the user. Customizing menus provides a path for the user to maximize their utility. Done judiciously, customizing Emacs menus can significantly enhance the overall experience of using Emacs.

Addendum 2023-11-02

Dan Drake made two excellent notes on this post which I've amended accordingly. First is that the predicate using the function vc-responsible-backend for the key :visible will return an error object if applied to a directory or file that is not under version control. The :visible key in an Emacs menu item would rather see a nil value than the aforementioned error object. To support this, you must set the NO_ERROR argument to t as follows:

(vc-responsible-backend default-directory t)

The second note is to use the function describe-keymap to show all of a keymap's bindings in one step.




Feeds & TagsGet Captee for macOS

Powered by Pelican