]> code.delx.au - gnu-emacs/blobdiff - lisp/imenu.el
(Abbrevs): A @node line without explicit Prev, Next, and Up links.
[gnu-emacs] / lisp / imenu.el
index 16116025fb827774d047467d569b62319507ffb2..a609bcbadf98c11c0637407d610eefa18f2d5921 100644 (file)
@@ -1,7 +1,7 @@
 ;;; imenu.el --- framework for mode-specific buffer indexes
 
-;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 2003, 2004
-;;           Free Software Foundation, Inc.
+;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 2002, 2003, 2004,
+;;   2005, 2006 Free Software Foundation, Inc.
 
 ;; Author: Ake Stenhoff <etxaksf@aom.ericsson.se>
 ;;         Lars Lindberg <lli@sypro.cap.se>
@@ -23,8 +23,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; 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.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -62,8 +62,6 @@
 
 ;;; Code:
 
-(require 'newcomment)
-
 (eval-when-compile (require 'cl))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -109,7 +107,7 @@ This variable is buffer-local."
 
 (defvar imenu-always-use-completion-buffer-p nil)
 (make-obsolete-variable 'imenu-always-use-completion-buffer-p
-                       'imenu-use-popup-menu "21.4")
+                       'imenu-use-popup-menu "22.1")
 
 (defcustom imenu-use-popup-menu
   (if imenu-always-use-completion-buffer-p
@@ -121,14 +119,15 @@ If t, always use a popup menu,
 If `on-mouse' use a popup menu when `imenu' was invoked with the mouse."
   :type '(choice (const :tag "On Mouse" on-mouse)
                 (const :tag "Never" nil)
-                (other :tag "Always" t)))
+                (other :tag "Always" t))
+  :group 'imenu)
 
 (defcustom imenu-eager-completion-buffer
   (not (eq imenu-always-use-completion-buffer-p 'never))
   "If non-nil, eagerly popup the completion buffer."
   :type 'boolean
   :group 'imenu
-  :version "21.4")
+  :version "22.1")
 
 (defcustom imenu-after-jump-hook nil
   "*Hooks called after jumping to a place in the buffer.
@@ -193,32 +192,9 @@ with name concatenation."
 (defvar imenu-generic-expression nil
   "The regex pattern to use for creating a buffer index.
 
-If non-nil this pattern is passed to `imenu--generic-function'
-to create a buffer index.
-
-The value should be an alist with elements that look like this:
- (MENU-TITLE REGEXP INDEX)
-or like this:
- (MENU-TITLE REGEXP INDEX FUNCTION ARGUMENTS...)
-with zero or more ARGUMENTS.  The former format creates a simple element in
-the index alist when it matches; the latter creates a special element
-of the form  (NAME POSITION-MARKER FUNCTION ARGUMENTS...)
-with FUNCTION and ARGUMENTS copied from `imenu-generic-expression'.
-
-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.
-
-INDEX points to the substring in REGEXP that contains the name (of the
-function, variable or type) that is to appear in the menu.
-
-The variable `imenu-case-fold-search' determines whether or not the
-regexp matches are case sensitive, and `imenu-syntax-alist' can be
-used to alter the syntax table for the search.
+If non-nil this pattern is passed to `imenu--generic-function' to
+create a buffer index.  Look there for the documentation of this
+pattern's structure.
 
 For example, see the value of `fortran-imenu-generic-expression' used by
 `fortran-mode' with `imenu-syntax-alist' set locally to give the
@@ -232,18 +208,13 @@ during matching.")
 
 ;;;###autoload
 (defvar imenu-create-index-function 'imenu-default-create-index-function
-  "The function to use for creating a buffer index.
+  "The function to use for creating an index alist of the current buffer.
 
-It should be a function that takes no arguments and returns an index
-of the current buffer as an alist.
+It should be a function that takes no arguments and returns
+an index alist of the current buffer.  The function is
+called within a `save-excursion'.
 
-Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION).
-Special elements look like (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...).
-A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
-The function `imenu--subalist-p' tests an element and returns t
-if it is a sub-alist.
-
-This function is called within a `save-excursion'.")
+See `imenu--index-alist' for the format of the buffer index alist.")
 ;;;###autoload
 (make-variable-buffer-local 'imenu-create-index-function)
 
@@ -455,15 +426,27 @@ Don't move point."
 ;; The latest buffer index.
 ;; Buffer local.
 (defvar imenu--index-alist nil
-  "The buffer index computed for this buffer in Imenu.
-Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION).
-Special elements look like (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...).
-A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).")
+  "The buffer index alist computed for this buffer in Imenu.
+
+Simple elements in the alist look like (INDEX-NAME . POSITION).
+POSITION is the buffer position of the item; to go to the item
+is simply to move point to that position.
+
+Special elements look like (INDEX-NAME POSITION FUNCTION ARGUMENTS...).
+To \"go to\" a special element means applying FUNCTION
+to INDEX-NAME, POSITION, and the ARGUMENTS.
+
+A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
+The function `imenu--subalist-p' tests an element and returns t
+if it is a sub-alist.
+
+There is one simple element with negative POSITION; selecting that
+element recalculates the buffer's index alist.")
 
 (make-variable-buffer-local 'imenu--index-alist)
 
 (defvar imenu--last-menubar-index-alist nil
-  "The latest buffer index used to update the menu bar menu.")
+  "The latest buffer index alist used to update the menu bar menu.")
 
 (make-variable-buffer-local 'imenu--last-menubar-index-alist)
 
@@ -534,7 +517,7 @@ A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).")
        (push item keep-at-top)
        (setq menulist (delq item menulist))))
     (if imenu-sort-function
-       (setq menulist (sort menulist imenu-sort-function)))
+       (setq menulist (sort (copy-sequence menulist) imenu-sort-function)))
     (if (> (length menulist) imenu-max-items)
        (setq menulist
              (mapcar
@@ -571,19 +554,12 @@ A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).")
 
 
 (defun imenu--make-index-alist (&optional noerror)
-  "Create an index-alist for the definitions in the current buffer.
-
+  "Create an index alist for the definitions in the current buffer.
+This works by using the hook function `imenu-create-index-function'.
 Report an error if the list is empty unless NOERROR is supplied and
 non-nil.
 
-Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION).
-Special elements look like (INDEX-NAME FUNCTION ARGUMENTS...).
-A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
-The function `imenu--subalist-p' tests an element and returns t
-if it is a sub-alist.
-
-There is one simple element with negative POSITION; that's intended
-as a way for the user to ask to recalculate the buffer's index alist."
+See `imenu--index-alist' for the format of the index alist."
   (or (and imenu--index-alist
           (or (not imenu-auto-rescan)
               (and imenu-auto-rescan
@@ -681,11 +657,15 @@ and speed-up matching.")
 (make-variable-buffer-local 'imenu-syntax-alist)
 
 (defun imenu-default-create-index-function ()
-  "*Wrapper for index searching functions.
+  "*Default function to create an index alist of the current buffer.
 
-Moves point to end of buffer and then repeatedly calls
+The most general method is to move point to end of buffer, then repeatedly call
 `imenu-prev-index-position-function' and `imenu-extract-index-name-function'.
-Their results are gathered into an index alist."
+All the results returned by the latter are gathered into an index alist.
+This method is used if those two variables are non-nil.
+
+The alternate method, which is the one most often used, is to call
+`imenu--generic-function' with `imenu-generic-expression' as argument."
   ;; These should really be done by setting imenu-create-index-function
   ;; in these major modes.  But save that change for later.
   (cond ((and imenu-prev-index-position-function
@@ -711,27 +691,6 @@ Their results are gathered into an index alist."
        (t
         (error "This buffer cannot use `imenu-default-create-index-function'"))))
 
-;; Not used and would require cl at run time
-;; (defun imenu--flatten-index-alist (index-alist &optional concat-names prefix)
-;;   ;; Takes a nested INDEX-ALIST and returns a flat index alist.
-;;   ;; If optional CONCAT-NAMES is non-nil, then a nested index has its
-;;   ;; name and a space concatenated to the names of the children.
-;;   ;; Third argument PREFIX is for internal use only.
-;;   (mapcan
-;;    (lambda (item)
-;;      (let* ((name (car item))
-;;         (pos (cdr item))
-;;         (new-prefix (and concat-names
-;;                          (if prefix
-;;                              (concat prefix imenu-level-separator name)
-;;                            name))))
-;;        (cond
-;;     ((or (markerp pos) (numberp pos))
-;;      (list (cons new-prefix pos)))
-;;     (t
-;;      (imenu--flatten-index-alist pos new-prefix)))))
-;;    index-alist))
-
 ;;;
 ;;; Generic index gathering function.
 ;;;
@@ -745,27 +704,38 @@ for modes which use `imenu--generic-function'.  If it is not set, but
 ;;;###autoload
 (make-variable-buffer-local 'imenu-case-fold-search)
 
-;; Originally "Built on some ideas that Erik Naggum <erik@naggum.no>
-;; once posted to comp.emacs" but since substantially re-written.
+;; This function can be called with quitting disabled,
+;; so it needs to be careful never to loop!
 (defun imenu--generic-function (patterns)
-  "Return an index of the current buffer as an alist.
+  "Return an index alist of the current buffer based on PATTERNS.
 
 PATTERNS is an alist with elements that look like this:
- (MENU-TITLE REGEXP INDEX).
+ (MENU-TITLE REGEXP INDEX)
 or like this:
  (MENU-TITLE REGEXP INDEX FUNCTION ARGUMENTS...)
-with zero or more ARGUMENTS.
-
-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.
+with zero or more ARGUMENTS.  The former format creates a simple
+element in the index alist when it matches; the latter creates a
+special element of the form (INDEX-NAME POSITION-MARKER FUNCTION
+ARGUMENTS...) with FUNCTION and ARGUMENTS copied from PATTERNS.
+
+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.  REGEXP may also be a function, called without
+arguments.  It is expected to search backwards.  It shall return
+true and set `match-data' iff it finds another element.
+
+INDEX points to the substring in REGEXP that contains the
+name (of the function, variable or type) that is to appear in the
+menu.
 
-INDEX points to the substring in REGEXP that contains the name (of the
-function, variable or type) that is to appear in the menu.
+The variable `imenu-case-fold-search' determines whether or not the
+regexp matches are case sensitive, and `imenu-syntax-alist' can be
+used to alter the syntax table for the search.
 
 See `lisp-imenu-generic-expression' for an example of PATTERNS.
 
@@ -779,7 +749,7 @@ They may also be nested index alists like:
 depending on PATTERNS."
 
   (let ((index-alist (list 'dummy))
-       prev-pos beg
+       prev-pos
         (case-fold-search (if (or (local-variable-p 'imenu-case-fold-search)
                                  (not (local-variable-p 'font-lock-defaults)))
                              imenu-case-fold-search
@@ -800,6 +770,7 @@ depending on PATTERNS."
     (unwind-protect                    ; for syntax table
        (save-match-data
          (set-syntax-table table)
+
          ;; map over the elements of imenu-generic-expression
          ;; (typically functions, variables ...)
          (dolist (pat patterns)
@@ -808,36 +779,45 @@ depending on PATTERNS."
                  (index (nth 2 pat))
                  (function (nth 3 pat))
                  (rest (nthcdr 4 pat))
-                 cs)
+                 start beg)
              ;; Go backwards for convenience of adding items in order.
              (goto-char (point-max))
-             (while (re-search-backward regexp nil t)
-               (goto-char (match-end index))
-               (setq beg (match-beginning index))
-               (if (setq cs (save-match-data (comment-beginning)))
-                   (goto-char cs)      ; skip this one, it's in a comment
-                 (goto-char beg)
-                 (imenu-progress-message prev-pos nil t)
-                 ;; Add this sort of submenu only when we've found an
-                 ;; item for it, avoiding empty, duff menus.
-                 (unless (assoc menu-title index-alist)
-                   (push (list menu-title) index-alist))
-                 (if imenu-use-markers
-                     (setq beg (copy-marker beg)))
-                 (let ((item
-                        (if function
-                            (nconc (list (match-string-no-properties index)
-                                         beg function)
-                                   rest)
-                          (cons (match-string-no-properties index)
-                                beg)))
-                       ;; This is the desired submenu,
-                       ;; starting with its title (or nil).
-                       (menu (assoc menu-title index-alist)))
-                   ;; Insert the item unless it is already present.
-                   (unless (member item (cdr menu))
-                     (setcdr menu
-                             (cons item (cdr menu)))))))))
+             (while (and (if (functionp regexp)
+                             (funcall regexp)
+                           (re-search-backward regexp nil t))
+                         ;; Exit the loop if we get an empty match,
+                         ;; because it means a bad regexp was specified.
+                         (not (= (match-beginning 0) (match-end 0))))
+               (setq start (point))
+               ;; Record the start of the line in which the match starts.
+               ;; That's the official position of this definition.
+               (goto-char (match-beginning index))
+               (beginning-of-line)
+               (setq beg (point))
+               (imenu-progress-message prev-pos nil t)
+               ;; Add this sort of submenu only when we've found an
+               ;; item for it, avoiding empty, duff menus.
+               (unless (assoc menu-title index-alist)
+                 (push (list menu-title) index-alist))
+               (if imenu-use-markers
+                   (setq beg (copy-marker beg)))
+               (let ((item
+                      (if function
+                          (nconc (list (match-string-no-properties index)
+                                       beg function)
+                                 rest)
+                        (cons (match-string-no-properties index)
+                              beg)))
+                     ;; This is the desired submenu,
+                     ;; starting with its title (or nil).
+                     (menu (assoc menu-title index-alist)))
+                 ;; Insert the item unless it is already present.
+                 (unless (member item (cdr menu))
+                   (setcdr menu
+                           (cons item (cdr menu)))))
+               ;; Go to the start of the match, to make sure we
+               ;; keep making progress backwards.
+               (goto-char start))))
          (set-syntax-table old-table)))
     (imenu-progress-message prev-pos 100 t)
     ;; Sort each submenu by position.
@@ -879,7 +859,7 @@ Return one of the entries in index-alist or nil."
         (if (not imenu-space-replacement) index-alist
           (mapcar
            (lambda (item)
-             (cons (subst-char-in-string ?\ (aref imenu-space-replacement 0)
+             (cons (subst-char-in-string ?\s (aref imenu-space-replacement 0)
                                          (car item))
                    (cdr item)))
            index-alist))))