]> code.delx.au - gnu-emacs/blobdiff - lisp/imenu.el
(ps-print-preprint): Special handling if
[gnu-emacs] / lisp / imenu.el
index 315e2caf599c697a3898e31222ab02f9562bf03c..166d2e10798cddb291758d5d9d3b3a3e43b89a06 100644 (file)
@@ -1,29 +1,31 @@
 ;;; imenu.el --- Framework for mode-specific buffer indexes.
 
-;; Copyright (C) 1994 Free Software Foundation, Inc.
+;; Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
 
 ;; Author: Ake Stenhoff <etxaksf@aom.ericsson.se>
 ;;         Lars Lindberg <lli@sypro.cap.se>
 ;; Created: 8 Feb 1994
-;; Version: 1.17
 ;; Keywords: tools
-;;
-;; This program is free software; you can redistribute it and/or modify
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
 ;; the Free Software Foundation; either version 2, or (at your option)
 ;; any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program; if not, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
 
 ;;; Commentary:
-;;
+
 ;; Purpose of this package:
 ;;   To present a framework for mode-specific buffer indexes.
 ;;   A buffer index is an alist of names and buffer positions.
@@ -54,6 +56,7 @@
 ;;  [karl] - Karl Fogel kfogel@floss.life.uiuc.edu
 
 ;;; Code
+
 (eval-when-compile (require 'cl))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (defvar imenu-use-keymap-menu nil
-  "* Set this to non-nil for using a keymap when making 
-  the mouse menu.")
+  "*Non-nil means use a keymap when making the mouse menu.")
 
 (defvar imenu-auto-rescan nil
-  "* T if we always should rescan the buffers, nil to disable
-  automatic rescan.")
+  "*Non-nil means Imenu should always rescan the buffers.")
 
 (defvar imenu-auto-rescan-maxout 60000 
   "* auto-rescan is disabled in buffers larger than this.
-  This variable is buffer-local.")
+This variable is buffer-local.")
 
 (defvar imenu-always-use-completion-buffer-p nil
   "*Set this to non-nil for displaying the index in a completion buffer.
@@ -97,9 +98,9 @@ element should come before the second.  The arguments are cons cells;
 \(NAME . POSITION).  Look at `imenu--sort-by-name' for an example.")
 
 (defvar imenu-max-items 25
-  "*Maximum number of elements in an index mouse-menu.")
+  "*Maximum number of elements in an mouse menu for Imenu.")
 
-(defvar imenu-scanning-message "Scanning buffer for index. (%3d%%)"
+(defvar imenu-scanning-message "Scanning buffer for index (%3d%%)"
   "*Progress message during the index scanning of the buffer.
 If non-nil, user gets a message during the scanning of the buffer
 
@@ -116,9 +117,6 @@ names work as tokens.")
 Used for making mouse-menu titles and for flattening nested indexes
 with name concatenation.")
 
-(defvar imenu-submenu-name-format "%s..."
-  "*The format for making a submenu name.")
-
 ;;;###autoload
 (defvar imenu-generic-expression nil
   "The regex pattern to use for creating a buffer index.
@@ -133,26 +131,23 @@ MENU-TITLE is a string used as the title for the submenu or nil if the
 entries are not nested.
 
 REGEXP is a regexp that should match a construct in the buffer that is
-to be displayed in the menu i.e. function or variable definitions,
-etc. It contains a substring which is the name to appear in the
-menu. See the info section on Regexps for more information.
+to be displayed in the menu; i.e., function or variable definitions,
+etc.  It contains a substring which is the name to appear in the
+menu.  See the info section on Regexps for more information.
 
 INDEX points to the substring in REGEXP that contains the name (of the
 function, variable or type) that is to appear in the menu.
 
 For emacs-lisp-mode for example PATTERN would look like:
 
-'((nil \"^\\s-*(def\\(un\\|subst\\|macro\\|advice\\)\\s-+\\([-A-Za-z0-9+]+\\)\" 2)
-  (\"*Vars*\" \"^\\s-*(def\\(var\\|const\\)\\s-+\\([-A-Za-z0-9+]+\\)\" 2)
-  (\"*Types*\" \"^\\s-*(def\\(type\\|struct\\|class\\|ine-condition\\)\\s-+\\([-A-Za-z0-9+]+\\)\" 2))
+'((nil \"^\\\\s-*(def\\\\(un\\\\|subst\\\\|macro\\\\|advice\\\\)\\\\s-+\\\\([-A-Za-z0-9+]+\\\\)\" 2)
+  (\"*Vars*\" \"^\\\\s-*(def\\\\(var\\\\|const\\\\)\\\\s-+\\\\([-A-Za-z0-9+]+\\\\)\" 2)
+  (\"*Types*\" \"^\\\\s-*(def\\\\(type\\\\|struct\\\\|class\\\\|ine-condition\\\\)\\\\s-+\\\\([-A-Za-z0-9+]+\\\\)\" 2))
 
 The variable is buffer-local.")
 
 ;;;###autoload
-(make-variable-buffer-local 'imenu-create-index-pattern)
-
-;; make sure the default is nil
-(setq-default imenu-create-index-pattern nil)
+(make-variable-buffer-local 'imenu-generic-expression)
 
 ;;;; Hooks
 
@@ -160,8 +155,8 @@ The variable is buffer-local.")
   "The function to use for creating a buffer index.
 
 It should be a function that takes no arguments and returns an index
-of the current buffer as an alist. The elements in the alist look
-like: (INDEX-NAME . INDEX-POSITION). You may also nest index list like
+of the current buffer as an alist.  The elements in the alist look
+like: (INDEX-NAME . INDEX-POSITION).  You may also nest index list like
 \(INDEX-NAME . INDEX-ALIST).
 
 This function is called within a `save-excursion'.
@@ -178,7 +173,7 @@ to a function that will find the next index, looking backwards in the
 file.
 
 The function should leave point at the place to be connected to the
-index and it should return nil when it doesn't find another index. ")
+index and it should return nil when it doesn't find another index.")
 (make-variable-buffer-local 'imenu-prev-index-position-function)
 
 (defvar imenu-extract-index-name-function nil
@@ -214,7 +209,7 @@ This function is called after the function pointed out by
 ;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-;; Return the current/previous sexp and the location of the sexp (it's
+;; Return the current/previous sexp and the location of the sexp (its
 ;; beginning) without moving the point.
 (defun imenu-example--name-and-position ()
   (save-excursion
@@ -285,144 +280,16 @@ This function is called after the function pointed out by
                       index-unknown-alist)))))))
     (imenu-progress-message prev-pos 100)
     (and index-var-alist
-        (push (cons (imenu-create-submenu-name "Variables") index-var-alist)
+        (push (cons "Variables" index-var-alist)
               index-alist))
     (and index-type-alist
-        (push (cons (imenu-create-submenu-name "Types") index-type-alist)
+        (push (cons "Types" index-type-alist)
               index-alist))
     (and index-unknown-alist
-        (push (cons (imenu-create-submenu-name "Syntax-unknown") index-unknown-alist)
+        (push (cons "Syntax-unknown" index-unknown-alist)
               index-alist))
     index-alist))
 
-(defvar imenu-generic-lisp-expression
-      '(
-       (nil 
-        "^\\s-*(def\\(un\\|subst\\|macro\\|advice\\)\\s-+\\([-A-Za-z0-9+]+\\)" 2)
-       ("Variables" 
-        "^\\s-*(def\\(var\\|const\\)\\s-+\\([-A-Za-z0-9+]+\\)" 2)
-       ("Types" 
-        "^\\s-*(def\\(type\\|struct\\|class\\|ine-condition\\)\\s-+\\([-A-Za-z0-9+]+\\)" 
-        2))
-
-  "imenu generic expression for Lisp mode in the form
-(PATTERN), where PATTERN is a list containing entries of the form 
-(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.")
-
-;;;
-;;; C++
-;;;
-;; Example of an imenu-generic-expression
-;;
-(defvar imenu-generic-c++-expression
-  (` 
-   ((nil
-     (, 
-      (concat
-       "^"                               ; beginning of line is required
-       "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
-       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"     ; type specs; there can be no
-       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"     ; more than 3 tokens, right?
-       
-       "\\("                             ; last type spec including */&
-       "[a-zA-Z0-9_:]+"
-       "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)"        ; either pointer/ref sign or whitespace
-       "\\)?"                            ; if there is a last type spec
-       "\\("                         ; name; take that into the imenu entry
-       "[a-zA-Z0-9_:~]+"                     ; member function, ctor or dtor...
-                                       ; (may not contain * because then 
-                                       ; "a::operator char*" would become "char*"!)
-       "\\|"
-       "\\([a-zA-Z0-9_:~]*::\\)?operator"
-       "[^a-zA-Z1-9_][^(]*"          ; ...or operator
-       " \\)"
-       "[ \t]*([^)]*)[ \t\n]*[^              ;]" ; require something other than a ; after
-                                       ; the (...) to avoid prototypes. Can't
-                                       ; catch cases with () inside the parentheses
-                                       ; surrounding the parameters
-                                       ; (like "int foo(int a=bar()) {...}"
-       
-       )) 6)    
-    ("Class" 
-     (, (concat 
-        "^"                               ; beginning of line is required
-        "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
-        "class[ \t]+"
-        "\\([a-zA-Z0-9_]+\\)"                ; this is the string we want to get
-        "[ \t]*[:{]"
-        )) 2)
-;; Example of generic expression for finding prototypes, structs, unions, enums.
-;; Uncomment if You want to find these too. It will be at bit slower gathering
-;; the indexes.
-;    ("Prototypes"
-;     (, 
-;      (concat
-;       "^"                              ; beginning of line is required
-;       "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
-;       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"    ; type specs; there can be no
-;       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"    ; more than 3 tokens, right?
-       
-;       "\\("                            ; last type spec including */&
-;       "[a-zA-Z0-9_:]+"
-;       "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)"       ; either pointer/ref sign or whitespace
-;       "\\)?"                           ; if there is a last type spec
-;       "\\("                        ; name; take that into the imenu entry
-;       "[a-zA-Z0-9_:~]+"                    ; member function, ctor or dtor...
-;                                      ; (may not contain * because then 
-;                                      ; "a::operator char*" would become "char*"!)
-;       "\\|"
-;       "\\([a-zA-Z0-9_:~]*::\\)?operator"
-;       "[^a-zA-Z1-9_][^(]*"         ; ...or operator
-;       " \\)"
-;       "[ \t]*([^)]*)[ \t\n]*;"       ; require ';' after
-;                                      ; the (...) Can't
-;                                      ; catch cases with () inside the parentheses
-;                                      ; surrounding the parameters
-;                                      ; (like "int foo(int a=bar());"       
-;       )) 6)    
-;    ("Struct"
-;     (, (concat
-;       "^"                            ; beginning of line is required
-;       "\\(static[ \t]+\\)?"          ; there may be static or const.
-;       "\\(const[ \t]+\\)?"
-;       "struct[ \t]+"
-;       "\\([a-zA-Z0-9_]+\\)"          ; this is the string we want to get
-;       "[ \t]*[{]"
-;       )) 3)
-;    ("Enum"
-;     (, (concat
-;       "^"                            ; beginning of line is required
-;       "\\(static[ \t]+\\)?"          ; there may be static or const.
-;       "\\(const[ \t]+\\)?"
-;       "enum[ \t]+"
-;       "\\([a-zA-Z0-9_]+\\)"          ; this is the string we want to get
-;       "[ \t]*[{]"
-;       )) 3)
-;    ("Union"
-;     (, (concat
-;       "^"                            ; beginning of line is required
-;       "\\(static[ \t]+\\)?"          ; there may be static or const.
-;       "\\(const[ \t]+\\)?"
-;       "union[ \t]+"
-;       "\\([a-zA-Z0-9_]+\\)"          ; this is the string we want to get
-;       "[ \t]*[{]"
-;       )) 3)
-    ))
-  "imenu generic expression for C++ mode in the form
-(PATTERN), where PATTERN is a list containing entries of the form 
-(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.")
-
-;;;
-;;; C
-;;;
-;;;
-(defvar imenu-generic-c-expression 
-  ;; Use the C++ expression above.
-  imenu-generic-c++-expression
-  "imenu generic expression for C mode in the form
-(PATTERN), where PATTERN is a list containing entries of the form 
-(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.")
-
 ;; Regular expression to find C functions
 (defvar imenu-example--function-name-regexp-c
   (concat 
@@ -455,57 +322,6 @@ This function is called after the function pointed out by
     (nreverse index-alist)))
 
 
-;; 
-;; Ada
-;; 
-;; Written by Christian Egli <Christian.Egli@hcsd.hac.com>
-;;
-(defvar imenu-generic-ada-expression
-      '((nil "^\\s-*\\(procedure\\|function\\)\\s-+\\([A-Za-z0-9_]+\\)" 2)
-       ("Type Defs" "^\\s-*\\(sub\\)?type\\s-+\\([A-Za-z0-9_]+\\)" 2))
-
-  "imenu generic expression for Ada mode in the form
-(PATTERN), where PATTERN is a list containing entries of the form 
-(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.")
-
-;;; 
-;;; TexInfo
-;;; 
-;; Written by Wolfgang Bangerth <zcg51122@rpool1.rus.uni-stuttgart.de>
-;;
-;;
-(defvar imenu-generic-texinfo-expression
-  '((nil "^@node[ \t]+\\([^,\n]*\\)" 1)
-    ("Chapters" "^@chapter[ \t]+\\(.*\\)$" 1))
-
-  "imenu generic expression for TexInfo mode in the form
-(PATTERN), where PATTERN is a list containing entries of the form 
-(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.
-
-To overide this example, Either set 'imenu-generic-expression
-or 'imenu-create-index-function")
-
-;;; 
-;;; LaTex
-;;; 
-;; Written by Wolfgang Bangerth <zcg51122@rpool1.rus.uni-stuttgart.de>
-;;
-;;
-(defvar imenu-generic-latex-expression
-  '(
-    ("Part" "\\\\part{\\([^}]*\\)}" 1)
-    ("Chapter" "\\\\chapter{\\([^}]*\\)}" 1)
-    ("Section" "\\\\[a-zA-Z]*section{\\([^}]*\\)}" 1)
-    ;; i put numbers like 3.15 before my
-    ;; \begin{equation}'s which tell me
-    ;; the number the equation will get when
-    ;; being printed.
-    ("Equations" "%[ \t]*\\([0-9]+\\.[0-9]+\\)[,;]?[ \t]?" 1))  
-
-  "imenu generic expression for LaTex mode in the form
-(PATTERN), where PATTERN is a list containing entries of the form 
-(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.")
-
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;
 ;;; Internal variables
@@ -520,27 +336,13 @@ or 'imenu-create-index-function")
 (defvar imenu--index-alist nil)
 (make-variable-buffer-local 'imenu--index-alist)
 
+;; The latest buffer index used to update the menu bar menu.
+(defvar imenu--last-menubar-index-alist nil)
+(make-variable-buffer-local 'imenu--last-menubar-index-alist)
+
 ;; History list for 'jump-to-function-in-buffer'.
-;; Buffer local.
+;; Making this buffer local caused it not to work!
 (defvar imenu--history-list nil)
-(make-variable-buffer-local 'imenu--history-list)
-
-(defvar imenu--scanning-method-alist
-  '((emacs-lisp-mode  imenu-generic-lisp-expression)
-    (lisp-mode        imenu-example--create-lisp-index)
-    (c++-mode         imenu-generic-c++-expression)
-    (c-mode           imenu-generic-c-expression)
-    (latex-mode       imenu-generic-latex-expression)
-    (texinfo-mode     imenu-generic-texinfo-expression)
-    (ada-mode         imenu-generic-ada-expression))
-
-  "Alist of major mode and imenu scanning methods.  
-
-Each item should be a list of the form: (MAJOR-MODE
-IMENU-SCANNING-METHOD) where both MAJOR-MODE and IMENU-SCANNING-METHOD
-are symbols. If IMENU-SCANNING-METHOD is a function then it is called
-to create an index. If it is a `pattern' (See `imenu-generic-expression') 
-it is passed to imenu--generic-function to create an index.")
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;
@@ -568,14 +370,6 @@ it is passed to imenu--generic-function to create an index.")
        (/ (1- pos) (max (/ total 100) 1))
       (/ (* 100 (1- pos)) (max total 1)))))
 
-;;;
-;;; Function for suporting general looking submenu names.
-;;; Uses `imenu-submenu-name-format' for creating the name.
-;;; NAME is the base of the new submenu name.
-;;;
-(defun imenu-create-submenu-name (name)
-   (format imenu-submenu-name-format name))
-
 ;; Split LIST into sublists of max length N.
 ;; Example (imenu--split '(1 2 3 4 5 6 7 8) 3)-> '((1 2 3) (4 5 6) (7 8))
 (defun imenu--split (list n)
@@ -597,16 +391,30 @@ it is passed to imenu--generic-function to create an index.")
         (push (nreverse sublist) result))
     (nreverse result)))
 
-;;;
-;;; Split a menu in to several menus.
-;;;
+;;; Split the alist MENULIST into a nested alist, if it is long enough.
+;;; In any case, add TITLE to the front of the alist.
 (defun imenu--split-menu (menulist title)
-  (cons "Index menu"
-       (mapcar
-        (function
-         (lambda (menu)
-           (cons (format "(%s)" title) menu)))
-        (imenu--split menulist imenu-max-items))))
+  (if (> (length menulist) imenu-max-items)
+      (let ((count 0))
+       (cons title
+             (mapcar
+              (function
+               (lambda (menu)
+                 (cons (format "(%s-%d)" title (setq count (1+ count)))
+                       menu)))
+              (imenu--split menulist imenu-max-items))))
+    (cons title menulist)))
+
+;;; Split up each long alist that are nested within ALIST
+;;; into nested alists.
+(defun imenu--split-submenus (alist)
+  (mapcar (function (lambda (elt)
+                     (if (and (consp elt)
+                              (stringp (car elt))
+                              (listp (cdr elt)))
+                         (imenu--split-menu (cdr elt) (car elt))
+                       elt)))
+         alist))
 
 ;;;
 ;;; Find all items in this buffer that should be in the index.
@@ -614,7 +422,7 @@ it is passed to imenu--generic-function to create an index.")
 ;;; ((NAME . POSITION) (NAME . POSITION) ...)
 ;;;
 
-(defun imenu--make-index-alist ()
+(defun imenu--make-index-alist (&optional noerror)
   ;; Create a list for this buffer only when needed.
   (or (and imenu--index-alist
           (or (not imenu-auto-rescan)
@@ -624,8 +432,10 @@ it is passed to imenu--generic-function to create an index.")
       (setq imenu--index-alist
            (save-excursion
              (funcall imenu-create-index-function))))
+  (or imenu--index-alist noerror
+      (error "No items suitable for an index found in this buffer"))
   (or imenu--index-alist
-      (error "No items suitable for an index found in this buffer."))
+      (setq imenu--index-alist (list nil)))
   ;; Add a rescan option to the index.
   (cons imenu--rescan-item imenu--index-alist))
 ;;;
@@ -650,24 +460,30 @@ it is passed to imenu--generic-function to create an index.")
        alist)
        t))
 
-(defun imenu--create-keymap-2 (alist counter)
+(defun imenu--create-keymap-2 (alist counter &optional commands)
   (let ((map nil))
     (mapcar
      (function
       (lambda (item)
        (cond
         ((listp (cdr item))
-         (append (list (incf counter) (car item) 'keymap (car item))
-                 (imenu--create-keymap-2 (cdr item) (+ counter 10))))
+         (append (list (setq counter (1+ counter))
+                       (car item) 'keymap (car item))
+                 (imenu--create-keymap-2 (cdr item) (+ counter 10) commands)))
         (t
-         (let ((end (cons '(nil) t)))
+         (let ((end (if commands `(lambda () (interactive)
+                                    (imenu--menubar-select ',item))
+                      (cons '(nil) t))))
            (cons (car item)
                  (cons (car item) end))))
         )))
      alist)))
 
-(defun imenu--create-keymap-1 (title alist)
-  (append (list 'keymap title) (imenu--create-keymap-2 alist 0)))
+;; If COMMANDS is non-nil, make a real keymap
+;; with a real command used as the definition.
+;; If it is nil, make something suitable for x-popup-menu.
+(defun imenu--create-keymap-1 (title alist &optional commands)
+  (append (list 'keymap title) (imenu--create-keymap-2 alist 0 commands)))
 
 
 (defun imenu--in-alist (str alist)
@@ -711,16 +527,7 @@ Their results are gathered into an index alist."
           index-alist))
        ;; Use generic expression if possible.
        ((and imenu-generic-expression)
-        (imenu--generic-function imenu-generic-expression))
-       ;; Use supplied example functions or expressions
-       ((assq major-mode imenu--scanning-method-alist)
-        (let ((method (cadr (assq major-mode imenu--scanning-method-alist))))
-          ;; is it a function?
-          (if (fboundp method)
-              ;; ... then call it
-              (funcall method) 
-            ;; ...otherwise pass the pattern to imenu--generic-function
-            (imenu--generic-function (eval method))))) 
+        (imenu--generic-function imenu-generic-expression)) 
        (t
         (error "The mode \"%s\" does not take full advantage of imenu.el yet."
                mode-name))))      
@@ -768,27 +575,27 @@ Their results are gathered into an index alist."
   "Return an index of the current buffer as an alist.
 
 PATTERN is an alist with elements that look like this: (MENU-TITLE
-REGEXP INDEX). 
+REGEXP INDEX).
 
 MENU-TITLE is a string used as the title for the submenu or nil if the
 entries are not nested.
 
 REGEXP is a regexp that should match a construct in the buffer that is
-to be displayed in the menu i.e. function or variable definitions,
-etc. It contains a substring which is the name to appear in the
-menu. See the info section on Regexps for more information.
+to be displayed in the menu; i.e., function or variable definitions,
+etc.  It contains a substring which is the name to appear in the
+menu.  See the info section on Regexps for more information.
 
 INDEX points to the substring in REGEXP that contains the name (of the
 function, variable or type) that is to appear in the menu.
 
 For emacs-lisp-mode for example PATTERN would look like:
 
-'((nil \"^\\s-*(def\\(un\\|subst\\|macro\\|advice\\)\\s-+\\([-A-Za-z0-9]+\\)\" 2)
-  (\"*Vars*\" \"^\\s-*(def\\(var\\|const\\)\\s-+\\([-A-Za-z0-9]+\\)\" 2)
-  (\"*Types*\" \"^\\s-*(def\\(type\\|struct\\|class\\|ine-condition\\)\\s-+\\([-A-Za-z0-9]+\\)\" 2))'
+'((nil \"^\\\\s-*(def\\\\(un\\\\|subst\\\\|macro\\\\|advice\\\\)\\\\s-+\\\\([-A-Za-z0-9]+\\\\)\" 2)
+  (\"*Vars*\" \"^\\\\s-*(def\\\\(var\\\\|const\\\\)\\\\s-+\\\\([-A-Za-z0-9]+\\\\)\" 2)
+  (\"*Types*\" \"^\\\\s-*(def\\\\(type\\\\|struct\\\\|class\\\\|ine-condition\\\\)\\\\s-+\\\\([-A-Za-z0-9]+\\\\)\" 2))'
 
-Returns an index of the current buffer as an alist. The elements in
-the alist look like: (INDEX-NAME . INDEX-POSITION). They may also be
+Returns an index of the current buffer as an alist.  The elements in
+the alist look like: (INDEX-NAME . INDEX-POSITION).  They may also be
 nested index lists like (INDEX-NAME . INDEX-ALIST) depending on
 pattern.
 
@@ -824,20 +631,16 @@ pattern.
                              (end (match-end index)))
                          (setq found t)
                          (push 
-                          (cons (buffer-substring beg end) beg)
+                          (cons (buffer-substring-no-properties beg end) beg)
                           (cdr 
-                           (or (if (not (stringp menu-title)) index-alist) 
-                               (assoc 
-                                (imenu-create-submenu-name menu-title) 
-                                index-alist)
+                           (or (assoc menu-title index-alist)
                                (car (push 
-                                     (cons 
-                                      (imenu-create-submenu-name menu-title) 
-                                      '()) 
+                                     (cons menu-title '()) 
                                      index-alist))))))))))
-           patterns))))
-      (imenu-progress-message prev-pos 100 t)
-      (delete 'dummy index-alist)))
+          patterns))))
+    (imenu-progress-message prev-pos 100 t)
+    (let ((main-element (assq nil index-alist)))
+      (nconc (delq main-element (delq 'dummy index-alist)) main-element))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;
@@ -893,6 +696,7 @@ Returns t for rescan and otherwise a position number."
 INDEX-ALIST is the buffer index and EVENT is a mouse event.
 
 Returns t for rescan and otherwise a position number."
+  (setq index-alist (imenu--split-submenus index-alist))
   (let* ((menu         (imenu--split-menu
                 (if imenu-sort-function
                     (sort
@@ -910,6 +714,9 @@ Returns t for rescan and otherwise a position number."
                                            (if (< 1 (length (cdr menu)))
                                                (cdr menu)
                                              (cdr (cadr menu))))))
+
+    (or imenu-use-keymap-menu
+       (setq menu (list "Imenu" (delq nil menu))))
     (setq position (x-popup-menu event menu))
     (if imenu-use-keymap-menu
        (progn
@@ -964,8 +771,9 @@ The returned value is on the form (INDEX-NAME . INDEX-POSITION)."
     ;; If selected by mouse, see to that the window where the mouse is
     ;; really is selected.
     (and mouse-triggered
+        (not (equal last-nonmenu-event '(menu-bar)))
         (let ((window (posn-window (event-start last-nonmenu-event))))
-          (or (framep window) (select-window window))))
+          (or (framep window) (null window) (select-window window))))
     ;; Create a list for this buffer only when needed.
     (while (eq result t)
       (setq index-alist (if alist alist (imenu--make-index-alist)))
@@ -981,39 +789,88 @@ The returned value is on the form (INDEX-NAME . INDEX-POSITION)."
 
 ;;;###autoload
 (defun imenu-add-to-menubar (name)
-  "Adds an \"imenu\" entry to the menubar for the 
-current local keymap.
-NAME is the string naming the menu to be added.
-See 'imenu' for more information."
-  (interactive "sMenu name: ")
-  (and window-system
-       (define-key (current-local-map) [menu-bar index]
-        (cons name 'imenu))))
+  "Adds an `imenu' entry to the menu bar for the current buffer.
+NAME is a string used to name the menu bar item.
+See the command `imenu' for more information."
+  (interactive "sImenu menu item name: ")
+  (let ((newmap (make-sparse-keymap))
+       (menu-bar (lookup-key (current-local-map) [menu-bar])))
+    (define-key newmap [menu-bar]
+      (append (make-sparse-keymap) menu-bar))
+    (define-key newmap [menu-bar index]
+      (cons name (nconc (make-sparse-keymap "Imenu")
+                       (make-sparse-keymap))))
+    (use-local-map (append newmap (current-local-map))))
+  (add-hook 'menu-bar-update-hook 'imenu-update-menubar))
+
+(defvar imenu-buffer-menubar nil)
+
+(defun imenu-update-menubar ()
+  (and (current-local-map)
+       (keymapp (lookup-key (current-local-map) [menu-bar index]))
+       (let ((index-alist (imenu--make-index-alist t)))
+        ;; Don't bother updating if the index-alist has not changed
+        ;; since the last time we did it.
+        (or (equal index-alist imenu--last-menubar-index-alist)
+            (let (menu menu1 old)
+              (setq imenu--last-menubar-index-alist index-alist)
+              (setq index-alist (imenu--split-submenus index-alist))
+              (setq menu (imenu--split-menu
+                          (if imenu-sort-function
+                              (sort
+                               (let ((res nil)
+                                     (oldlist index-alist))
+                                 ;; Copy list method from the cl package `copy-list'
+                                 (while (consp oldlist) (push (pop oldlist) res))
+                                 (prog1 (nreverse res) (setcdr res oldlist)))
+                               imenu-sort-function)
+                            index-alist)
+                          (buffer-name)))
+              (setq menu1 (imenu--create-keymap-1 (car menu) 
+                                                  (if (< 1 (length (cdr menu)))
+                                                      (cdr menu)
+                                                    (cdr (car (cdr menu))))
+                                                  t))
+              (setq old (lookup-key (current-local-map) [menu-bar index]))
+              (if (keymapp old)
+                  (setcdr (nthcdr 2 old) menu1)))))))
+
+(defun imenu--menubar-select (item)
+  "Use Imenu to select the function or variable named in this menu item."
+  (if (equal item '("*Rescan*" . -99))
+      (progn
+       (imenu--cleanup)
+       (setq imenu--index-alist nil)
+       (imenu-update-menubar))
+    (imenu item)))
 
 ;;;###autoload
-(defun imenu ()
+(defun imenu (index-item)
   "Jump to a place in the buffer chosen using a buffer menu or mouse menu.
 See `imenu-choose-buffer-index' for more information."
-  (interactive)
-  (let ((index-item (save-restriction 
-                     (widen)
-                     (imenu-choose-buffer-index))))
-    (and index-item
-        (progn
-          (push-mark)
-          (cond
-           ((markerp (cdr index-item))
-            (if (or ( > (marker-position (cdr index-item)) (point-min))
-                    ( < (marker-position (cdr index-item)) (point-max)))
-                ;; widen if outside narrowing
-                (widen))
-            (goto-char (marker-position (cdr index-item))))
-           (t
-            (if (or ( > (cdr index-item) (point-min))
-                    ( < (cdr index-item) (point-max)))
-                ;; widen if outside narrowing
-                (widen))
-            (goto-char (cdr index-item))))))))
+  (interactive
+   (list (save-restriction 
+          (widen)
+          (car (imenu-choose-buffer-index)))))
+  ;; Convert a string to an alist element.
+  (if (stringp index-item)
+      (setq index-item (assoc index-item (imenu--make-index-alist))))
+  (and index-item
+       (progn
+        (push-mark)
+        (cond
+         ((markerp (cdr index-item))
+          (if (or ( > (marker-position (cdr index-item)) (point-min))
+                  ( < (marker-position (cdr index-item)) (point-max)))
+              ;; widen if outside narrowing
+              (widen))
+          (goto-char (marker-position (cdr index-item))))
+         (t
+          (if (or ( > (cdr index-item) (point-min))
+                  ( < (cdr index-item) (point-max)))
+              ;; widen if outside narrowing
+              (widen))
+          (goto-char (cdr index-item)))))))
 
 (provide 'imenu)