Creating a dynamic menu for Emacs

| categories: emacs | tags:

I have an application where I want a dynamic menu in Emacs, e.g. the menu auto-updates as things change on your computer. Here is a prototype example. We will make a menu that shows entries for each file in the current directory, and opens that entry.

We start by creating a menu that is initially empty like this. This menu will be called "My Files" in the menu.

(easy-menu-define jrk-menu global-map "MyMenu"
  '("My Files"))

Next, we create this function which will create a submenu with a vector entry for each file in this directory.

(defun get-menu ()
  (easy-menu-create-menu
   "Files"
   (mapcar (lambda (x)
             (vector (file-name-nondirectory x)
                     `(lambda () (interactive) (find-file ,x) t)))
           (f-glob "*"))))
get-menu

Next, we add the submenu. This is a one-time addition, which reflects the files in the directory at the time I ran this block.

(easy-menu-add-item jrk-menu '() (get-menu))

After you do that, the menu looks like this:

This menu is not yet dynamic. We need to create a function that can update the menu, and then add the function to a hook that runs each time the menu opens. Here is the code. The easy-menu-add-item function will replace the contents of an item by the same name, which we use here to update the menu.

(defun update-my-file-menu ()
  (easy-menu-add-item jrk-menu '() (get-menu)))

(add-hook 'menu-bar-update-hook 'update-my-file-menu)
update-my-file-menu undo-tree-update-menu-bar menu-bar-update-buffers

Now, if we run this block to create a file:

touch newfile

Then, after saving this buffer the menu looks like this:

Now, every time a new file appears in this directory, a new menu item will appear every time you check the menu. That is really dynamic.

Copyright (C) 2014 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.7c

Discuss on Twitter