Search code examples
emacselispmenuitemmenubarkeymapping

patching menu, getting "Wow, indirect keymap entry" error


Gnu Emacs 24.4 pretest on Windows. I want to modify the menu-bar menu of nxml-mode on the fly, appending a forest structure of known XML files (formed by the xi:include's of any XML files that get edited). Works fine except for the menu patching. That also actually works for a single file, but once it becomes a hierarchy (nested keymap), accessing the menu gives me the nefarious "Wow, indirect keymap entry" error, at which point it's time to quit Emacs because things are getting severely hosed (it's disturbing when Alt-Tab stops working). Humorously, I see someone once submitted a bug report requesting more intelligible error text, which was denied.

I dump the menu structure before and after I patch it, and I can't see what's wrong with the patched version. The dump is pretty tedious reading, but less so than the code that patches it, I reckon, which would likely only cause gasps of horror without eliciting a solution. Here's the before state of the relevant portion of the menu bar:

((Show\ Outline\ Only menu-item "Show Outline Only" nxml-hide-all-text-content) 
 (Show\ Everything menu-item "Show Everything" nxml-show-all)
 (nil menu-item "---")
 (Validation menu-item "Validation" rng-validate-mode :button (:toggle . rng-validate-mode))
 (nil-4 menu-item "---")
 (Set\ Schema menu-item "Set Schema" (keymap "Set Schema" (Automatically menu-item "Automatically" rng-auto-set-schema) (For\ Document\ Type menu-item "For Document Type" nil :filter #[257 "ÂÁ!À\"" ["For Document Type" (lambda (menu) (mapcar (lambda (type-id) (vector type-id (list (quote rng-set-document-type) type-id))) (rng-possible-type-ids))) easy-menu-filter-return] 4 " (fn MENU)"]) (Any\ Well-Formed\ XML menu-item "Any Well-Formed XML" rng-set-vacuous-schema) (File\.\.\. menu-item "File..." rng-set-schema-file)))
 (Show\ Schema\ Location menu-item "Show Schema Location" rng-what-schema)
 (Save\ Schema\ Location menu-item "Save Schema Location" rng-save-schema-location :help "Save the location of the schema currently being used for this buffer")
 (nil-8 menu-item "---")
 (First\ Error menu-item "First Error" rng-first-error :enable rng-validate-mode) 
 (Next\ Error menu-item "Next Error" rng-next-error :enable rng-validate-mode)
 (nil-11 menu-item "---")
 (Customize\ nXML menu-item "Customize nXML" menu-function-7 :key-sequence nil))

And here's the state after appending my menu stuff to the end:

((Show\ Outline\ Only menu-item "Show Outline Only" nxml-hide-all-text-content)
 (Show\ Everything menu-item "Show Everything" nxml-show-all)
 (nil menu-item "---")
 (Validation menu-item "Validation" rng-validate-mode :button (:toggle . rng-validate-mode))
 (nil-4 menu-item "---")
 (Set\ Schema menu-item "Set Schema" (keymap "Set Schema" (Automatically menu-item "Automatically" rng-auto-set-schema) (For\ Document\ Type menu-item "For Document Type" nil :filter #[257 "ÂÁ!À\"" ["For Document Type" (lambda (menu) (mapcar (lambda (type-id) (vector type-id (list (quote rng-set-document-type) type-id))) (rng-possible-type-ids))) easy-menu-filter-return] 4 " (fn MENU)"]) (Any\ Well-Formed\ XML menu-item "Any Well-Formed XML" rng-set-vacuous-schema) (File\.\.\. menu-item "File..." rng-set-schema-file)))
 (Show\ Schema\ Location menu-item "Show Schema Location" rng-what-schema)
 (Save\ Schema\ Location menu-item "Save Schema Location" rng-save-schema-location :help "Save the location of the schema currently being used for this buffer")
 (nil-8 menu-item "---")
 (First\ Error menu-item "First Error" rng-first-error :enable rng-validate-mode) 
 (Next\ Error menu-item "Next Error" rng-next-error :enable rng-validate-mode)
 (nil-11 menu-item "---")
 (Customize\ nXML menu-item "Customize nXML" menu-function-7 :key-sequence nil)
 (ppop-event-0 "intro.xml" (keymap "intro.xml" (ppop-event-4 menu-item "introswan.xml" nil) (ppop-event-3 menu-item "introgame.xml" nil) (ppop-event-2 menu-item "introclark.xml" nil) (ppop-event-1 menu-item "introroots.xml" nil))))

For clarity, this sexp was added to the list, just after the last list element (Customize\ nXML ...:

 (ppop-event-0
  "intro.xml"
  (keymap "intro.xml"
          (ppop-event-4 menu-item "introswan.xml" nil)
          (ppop-event-3 menu-item "introgame.xml" nil)
          (ppop-event-2 menu-item "introclark.xml" nil)
          (ppop-event-1 menu-item "introroots.xml" nil)))

The intent was that the existing drop-down would have a new entry at the end with text "intro.xml" which should be produce another menu with the entries "introswan.xml", "introclark.xml", "introroots.xml" and "introgame.xml". I have set the callback functions for all added items to nil for brevity; putting the real function in does not avoid the error.

The structure for my sub-hierarchy seems identical to that of another sub-hierarchy on the same dropdown (see keymap "Set Schema"), which of course works. I can't see what's wrong or how the structure could be interpreted as an indirect keymap. And it seems to work fine for the case of a single file that requires no nested keymap. I am running out of things to try...

Relevant source emitting the message is in C, seen at: http://bzr.savannah.gnu.org/lh/emacs/emacs-24/annotate/head:/src/keymap.c#L789


Solution

  • I think the problem is that your ppop-event-0 binding is missing a menu-item symbol before its "intro.xml" "name". The end result is that your binding ends up looking like some old format which AFAIK is not used anywhere anymore (but it's extremely difficult to figure it out, hence my adding a nasty error there if/when we actually bump into such a thing, so as to try and make sure we hear from users).

    I think this error message has been with us for long enough that we can say for sure that such indirect bindings aren't used any more and we can drop support for it (and hence the corresponding error, tho the end result may not be much more helpful for you).