Subject: 24.3.50; new, undocumented menu structure using VECTORS?

From: Drew Adams <[email-masked]>
Date: Thu, 4 Jul 2013 16:54:21 -0700 (PDT)

I have a library, lacarte.el, that lets you use the keyboard to navigate
the menu-bar menus.  The aim is thus similar to that of tmm, but you can
use completion against the full "path" to a menu item (submenus etc.).
Completion candidates look like this: `Buffers > Frames > foo.el' (item
`foo.el' in submenu `Frames' of menu-bar menu `Buffers'.

When you have multiple frames, the dynamically created `Buffers'
menu-bar menu has a (dynamically created) submenu `Frames'.

Starting with Emacs 23, instead of seeing candidates like `Buffers >
Frames > foo.el' in LaCarte, you see only a pseudo candidate for the
submenu itself: `Buffers > Frames', and if you choose that candidate you
get an error saying that there is no such command.  That's because the
LaCarte code assumes that the menu data structure corresponds to the
documented menu structures.

It seems that the Emacs code now uses an undocumented menu structure
here. The code in menu-bar.el that creates the `Buffers' menu (and its
`Frames' submenu) changed in Emacs 23 to use a vector of buffer (and a
vector of frame) entries instead of a list of them.

I don't see anything in the manual that mentions that a menu can take
this form.  Dunno whether I am not reading it well enough or the doc is
incomplete.

And I see nothing in the Emacs 23 NEWS about such a new menu structure.
(I do not understand how someone can make such a fundamental change and
not mention it in NEWS.  New menu structures are not something that
Emacs adds everyday.)

1. So at a minimum this is a DOC bug report: I would like the doc to
describe all of the possible forms of menus.  Apparently it no longer
does that.

2. Beyond that, using vectors here is a PITA for Lisp code.  It makes
code that traverses such code difficult, if not impossible.  Without
this change to vectors, a simple recursion on a list cdr is all that is
needed.  No doubt I'll find a fix, once I know the actual possible menu
structures available.  But using vectors here does not seem very lispy.

Could you perhaps consider changing the code back to using lists?

Here are some details - see function `menu-bar-update-buffers' in
`menu-bar.el.  This is a snippet from that function - the part that
creates the `Frames' submenu:

Emacs 22 (and prior is similar, but a little different (but still uses a
list, not a vector)):

;; Make a Frames menu if we have more than one frame.
(when (cdr frames)
  (let ((frames-menu
         (cons 'keymap
               (cons "Select Frame"
                     (mapcar
                      (lambda (frame)
                        (nconc
                         (list (frame-parameter frame 'name)
                               (frame-parameter frame 'name)
                               (cons nil nil))
                         'menu-bar-select-frame))
                      frames)))))
    ;; Put it after the normal buffers
    (setq buffers-menu
          (nconc buffers-menu
                 `((frames-separator "--")
                   (frames menu-item "Frames" ,frames-menu))))))

Emacs 23 - uses a vector (why?):

;; Make a Frames menu if we have more than one frame.
(when (cdr frames)
  (let* ((frames-vec (make-vector (length frames) nil)) ; <============
         (frames-menu (cons 'keymap (list "Select Frame" frames-vec)))
         (i 0))
    (dolist (frame frames)
      (aset frames-vec i
            (nconc
             (list
              (frame-parameter frame 'name)
              (cons nil nil))
             `(lambda ()
                (interactive) (menu-bar-select-frame ,frame))))
      (setq i (1+ i)))
    ;; Put it after the normal buffers
    (setq buffers-menu
          (nconc buffers-menu
                 `((frames-separator "--")
                   (frames menu-item "Frames" ,frames-menu))))))

I assume (hope) this change to using vectors was not gratuitous.  But is
it necessary?  The cost is added difficulty analyzing and traversing the
data structure, a priori.  What is the benefit?

As a heads-up, can you tell me where else, besides these two dynamically
created menus (`Buffers' and `Frames'), Emacs use vectors in menu data
structures?

In GNU Emacs 24.3.50.1 (i686-pc-mingw32)
 of 2013-07-01 on LEG570
Bzr revision: 113246 [email-masked]
Windowing system distributor `Microsoft Corp.', version 6.1.7601
Configured using:
 `configure --prefix=/c/usr --enable-checking CFLAGS='-O0 -g3'
 CPPFLAGS='-DGLYPH_DEBUG=1 -I/c/usr/include''