imenu-generic-expression

Inasmuch as `imenu-generic-expression` makes using Emacs’ “Imenu” simpler, it’s this triennial’s “Obscure Emacs variable of the week“.

Emacs’ “Imenu” feature puts in the menu-bar a menu whose each menu item (or sub-menu item) jumps you to a location in the current buffer. Emacs being Emacs, Imenu is highly configurable, and quite often an Emacs mode will set up the Imenu menu to point to locations in the buffer that are significant for that mode/file-type. For example, my xslide and tdtd modes each set up very different Imenu menus.

`imenu-generic-expression` is a variable that, at its simplest, contains a list of three-item lists that each specify a menu title, a regular expression, and the number corresponding to the subexpression of the regular expression to use as the resulting menu item’s name. When `imenu-generic-expression` is set and the Imenu menu bar item is enabled (using `imenu-add-to-menubar`, naturally), Emacs constructs a buffer index by searching the buffer using each of the regular expressions in turn and then builds up the menu based on the matches found.

For example, here’s the `rnc-mode-hook' that I use to add a “RNC” menu when using `rnc-mode' to edit RELAX NG compact syntax (RNC) files. The hook sets `imenu-generic-expression` with patterns that match significant declarations in a RNC file (with separate sub-menus for include, namespace, and datatypes declaration types) then enables Imenu with `imenu-add-to-menubar`. A screenshot of the resulting menu is action is shown after the code.

(require 'rnc-mode)
(add-hook 'rnc-mode-hook
 (lambda ()
   (set-variable
    'imenu-generic-expression
    (list
     (list
      nil
      "^\\([a-zA-Z][-a-zA-Z0-9._]*\\)\\s-*[&|]?=" 1)
     (list
      "include"
      "^include\\s-+['\"]\\([a-zA-Z][-a-zA-Z0-9._]*\\)['\"]" 1)
     (list
      "namespace"
      "^\\(default\\s-+\\)?namespace\\s-+\\([a-zA-Z][-a-zA-Z0-9._]*\\)\\s-*=" 2)
     (list
      "dataypes"
      "^datatypes\\s-+\\([a-zA-Z][-a-zA-Z0-9._]*\\)\\s-*=" 1)))
   (imenu-add-to-menubar "RNC")))

The only downside to using `imenu-add-to-menubar` compared to doing more of it yourself is that `imenu-add-to-menubar` doesn’t provide a way to sort the menu items, so the order of the matches in the file is the order of the items in the menu or sub-menu. I wrote both xslide and tdtd before I knew of `imenu-add-to-menubar`, but the recently revived xslide for XSLT 2.0 still uses a custom function to make the Imenu index because I also like to sort the index entries alphabetically within each menu or sub-menu.