]> code.delx.au - gnu-emacs/blobdiff - lisp/imenu.el
Bump version to 25.0.95
[gnu-emacs] / lisp / imenu.el
index c1077a49d1a08d23643b77918639438ecd35e668..48257b892db19f4008b1dd830e62206792ff150c 100644 (file)
@@ -1,10 +1,10 @@
 ;;; imenu.el --- framework for mode-specific buffer indexes  -*- lexical-binding: t -*-
 
-;; Copyright (C) 1994-1998, 2001-2013 Free Software Foundation, Inc.
+;; Copyright (C) 1994-1998, 2001-2016 Free Software Foundation, Inc.
 
 ;; Author: Ake Stenhoff <etxaksf@aom.ericsson.se>
 ;;         Lars Lindberg <lli@sypro.cap.se>
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Created: 8 Feb 1994
 ;; Keywords: tools convenience
 
@@ -185,6 +185,13 @@ with name concatenation."
   :type 'string
   :group 'imenu)
 
+(defcustom imenu-generic-skip-comments-and-strings t
+  "When non-nil, ignore text inside comments and strings.
+Only affects `imenu--generic-function'."
+  :type 'boolean
+  :group 'imenu
+  :version "24.4")
+
 ;;;###autoload
 (defvar imenu-generic-expression nil
   "List of definition matchers for creating an Imenu index.
@@ -286,8 +293,10 @@ The function in this variable is called when selecting a normal index-item.")
 
 
 (defun imenu--subalist-p (item)
-  (and (consp (cdr item)) (listp (cadr item))
-       (not (eq (car (cadr item)) 'lambda))))
+  (and (consp item)
+       (consp (cdr item))
+       (listp (cadr item))
+       (not (functionp (cadr item)))))
 
 (defmacro imenu-progress-message (_prevpos &optional _relpos _reverse)
   "Macro to display a progress message.
@@ -339,6 +348,12 @@ Don't move point."
 ;;; Lisp
 ;;;
 
+(define-error 'imenu-unavailable "imenu unavailable")
+
+(defun imenu-unavailable-error (format &rest args)
+  (signal 'imenu-unavailable
+          (list (apply #'format-message format args))))
+
 (defun imenu-example--lisp-extract-index-name ()
   ;; Example of a candidate for `imenu-extract-index-name-function'.
   ;; This will generate a flat index of definitions in a lisp file.
@@ -405,11 +420,11 @@ Don't move point."
 ;; Regular expression to find C functions
 (defvar imenu-example--function-name-regexp-c
   (concat
-   "^[a-zA-Z0-9]+[ \t]?"               ; type specs; there can be no
+   "^[a-zA-Z0-9]+[ \t]?"               ; Type specs; there can be no
    "\\([a-zA-Z0-9_*]+[ \t]+\\)?"       ; more than 3 tokens, right?
    "\\([a-zA-Z0-9_*]+[ \t]+\\)?"
-   "\\([*&]+[ \t]*\\)?"                        ; pointer
-   "\\([a-zA-Z0-9_*]+\\)[ \t]*("       ; name
+   "\\([*&]+[ \t]*\\)?"                        ; Pointer.
+   "\\([a-zA-Z0-9_*]+\\)[ \t]*("       ; Name.
    ))
 
 (defun imenu-example--create-c-index (&optional regexp)
@@ -447,14 +462,17 @@ Don't move point."
 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.
-POSITION is passed to `imenu-default-goto-function', so it can be a non-number
-if that variable has been changed (e.g. Semantic uses overlays for POSITIONs).
 
-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.
+POSITION is passed to `imenu-default-goto-function', so it can be
+a non-number if that variable has been changed (e.g. Semantic
+uses overlays for POSITIONs).
 
-A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
+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.
 
@@ -467,7 +485,7 @@ element recalculates the buffer's index alist.")
 
 (defvar imenu--history-list nil
   ;; Making this buffer local caused it not to work!
-  "History list for 'jump-to-function-in-buffer'.")
+  "History list for `jump-to-function-in-buffer'.")
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;
@@ -490,14 +508,11 @@ If REVERSE is non-nil then the beginning is 100 and the end is 0."
   (let ((pos (point))
        (total (buffer-size)))
     (and reverse (setq pos (- total pos)))
-    (if (> total 50000)
-       ;; Avoid overflow from multiplying by 100!
-       (/ (1- pos) (max (/ total 100) 1))
-      (/ (* 100 (1- pos)) (max total 1)))))
+    (floor (* 100.0 (1- pos)) (max total 1))))
 
 (defun imenu--split (list n)
   "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))
+Example (imenu--split \\='(1 2 3 4 5 6 7 8) 3) => ((1 2 3) (4 5 6) (7 8))
 The returned list DOES NOT share structure with LIST."
   (let ((remain list)
        (result '())
@@ -556,7 +571,7 @@ NOT share structure with ALIST."
 (defun imenu--truncate-items (menulist)
   "Truncate all strings in MENULIST to `imenu-max-item-length'."
   (mapc (lambda (item)
-         ;; truncate if necessary
+         ;; Truncate if necessary.
          (when (and (numberp imenu-max-item-length)
                     (> (length (car item)) imenu-max-item-length))
            (setcar item (substring (car item) 0 imenu-max-item-length)))
@@ -575,7 +590,7 @@ See `imenu--index-alist' for the format of the index alist."
           (or (not imenu-auto-rescan)
               (and imenu-auto-rescan
                    (> (buffer-size)  imenu-auto-rescan-maxout))))
-      ;; Get the index; truncate if necessary
+      ;; Get the index; truncate if necessary.
       (progn
        (setq imenu--index-alist
              (save-excursion
@@ -584,7 +599,8 @@ See `imenu--index-alist' for the format of the index alist."
                  (funcall imenu-create-index-function))))
        (imenu--truncate-items imenu--index-alist)))
   (or imenu--index-alist noerror
-      (user-error "No items suitable for an index found in this buffer"))
+      (imenu-unavailable-error
+       "No items suitable for an index found in this buffer"))
   (or imenu--index-alist
       (setq imenu--index-alist (list nil)))
   ;; Add a rescan option to the index.
@@ -638,9 +654,11 @@ Non-nil arguments are in recursive calls."
       ;;   (INDEX-NAME (INDEX-NAME . INDEX-POSITION) ...)
       ;; while a bottom-level element looks like
       ;;   (INDEX-NAME . INDEX-POSITION)
+      ;; or
+      ;;   (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...)
       ;; We are only interested in the bottom-level elements, so we need to
-      ;; recurse if TAIL is a list.
-      (cond ((listp tail)
+      ;; recurse if TAIL is a nested ALIST.
+      (cond ((imenu--subalist-p elt)
             (if (setq res (imenu--in-alist str tail))
                 (setq alist nil)))
            ((if imenu-name-lookup-function
@@ -687,15 +705,16 @@ The alternate method, which is the one most often used, is to call
             (save-excursion
               (setq name (funcall imenu-extract-index-name-function)))
             (and (stringp name)
-                 ;; [ydi] updated for imenu-use-markers
-                 (push (cons name (if imenu-use-markers (point-marker) (point)))
+                 ;; [ydi] Updated for imenu-use-markers.
+                 (push (cons name
+                              (if imenu-use-markers (point-marker) (point)))
                        index-alist)))
           index-alist))
        ;; Use generic expression if possible.
        ((and imenu-generic-expression)
         (imenu--generic-function imenu-generic-expression))
        (t
-        (user-error "This buffer cannot use `imenu-default-create-index-function'"))))
+         (imenu-unavailable-error "This buffer cannot use `imenu-default-create-index-function'"))))
 
 ;;;
 ;;; Generic index gathering function.
@@ -714,8 +733,12 @@ for modes which use `imenu--generic-function'.  If it is not set, but
 ;; so it needs to be careful never to loop!
 (defun imenu--generic-function (patterns)
   "Return an index alist of the current buffer based on PATTERNS.
-PATTERNS should be an alist which has the same form as
-`imenu-generic-expression'.
+PATTERNS should be an alist with the same form as `imenu-generic-expression'.
+
+If `imenu-generic-skip-comments-and-strings' is non-nil, this ignores
+text inside comments and strings.
+
+If `imenu-case-fold-search' is non-nil, this ignores case.
 
 The return value is an alist of the form
  (INDEX-NAME . INDEX-POSITION)
@@ -741,12 +764,12 @@ depending on PATTERNS."
                 (modify-syntax-entry c (cdr syn) table))
               (car syn))))
     (goto-char (point-max))
-    (unwind-protect                    ; for syntax table
+    (unwind-protect                    ; For syntax table.
        (save-match-data
          (set-syntax-table table)
 
-         ;; map over the elements of imenu-generic-expression
-         ;; (typically functions, variables ...)
+         ;; Map over the elements of imenu-generic-expression
+         ;; (typically functions, variables ...).
          (dolist (pat patterns)
            (let ((menu-title (car pat))
                  (regexp (nth 1 pat))
@@ -795,7 +818,9 @@ depending on PATTERNS."
                      ;; 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))
+                 (unless (or (member item (cdr menu))
+                              (and imenu-generic-skip-comments-and-strings
+                                   (nth 8 (syntax-ppss))))
                    (setcdr menu
                            (cons item (cdr menu)))))
                ;; Go to the start of the match, to make sure we
@@ -918,6 +943,8 @@ The returned value is of the form (INDEX-NAME . INDEX-POSITION)."
           (setq result t imenu--index-alist nil)))
     result))
 
+(defvar-local imenu--menubar-keymap nil)
+
 ;;;###autoload
 (defun imenu-add-to-menubar (name)
   "Add an `imenu' entry to the menu bar for the current buffer.
@@ -934,12 +961,13 @@ See the command `imenu' for more information."
        (let ((newmap (make-sparse-keymap)))
          (set-keymap-parent newmap (current-local-map))
          (setq imenu--last-menubar-index-alist nil)
+          (setq imenu--menubar-keymap (make-sparse-keymap "Imenu"))
          (define-key newmap [menu-bar index]
-           `(menu-item ,name ,(make-sparse-keymap "Imenu")))
+           `(menu-item ,name ,imenu--menubar-keymap))
          (use-local-map newmap)
          (add-hook 'menu-bar-update-hook 'imenu-update-menubar)))
-    (user-error "The mode `%s' does not support Imenu"
-                (format-mode-line mode-name))))
+    (imenu-unavailable-error "The mode `%s' does not support Imenu"
+                             (format-mode-line mode-name))))
 
 ;;;###autoload
 (defun imenu-add-menubar-index ()
@@ -957,28 +985,23 @@ to `imenu-update-menubar'.")
 
 (defun imenu-update-menubar ()
   (when (and (current-local-map)
-            (keymapp (lookup-key (current-local-map) [menu-bar index]))
+             imenu--menubar-keymap
             (/= (buffer-chars-modified-tick) imenu-menubar-modified-tick))
     (setq imenu-menubar-modified-tick (buffer-chars-modified-tick))
     (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.
       (unless (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 index-alist
-                                       (buffer-name)))
-         (setq menu1 (imenu--create-keymap (car menu)
+        (setq imenu--last-menubar-index-alist index-alist)
+        (setq index-alist (imenu--split-submenus index-alist))
+       (let* ((menu (imenu--split-menu index-alist
+                                        (buffer-name)))
+               (menu1 (imenu--create-keymap (car menu)
                                            (cdr (if (< 1 (length (cdr menu)))
                                                     menu
                                                   (car (cdr menu))))
-                                           'imenu--menubar-select))
-         (setq old (lookup-key (current-local-map) [menu-bar index]))
-         ;; This should never happen, but in some odd cases, potentially,
-         ;; lookup-key may return a dynamically composed keymap.
-         (if (keymapp (cadr old)) (setq old (cadr old)))
-         (setcdr old (cdr menu1)))))))
+                                           'imenu--menubar-select)))
+         (setcdr imenu--menubar-keymap (cdr menu1)))))))
 
 (defun imenu--menubar-select (item)
   "Use Imenu to select the function or variable named in this menu ITEM."
@@ -994,7 +1017,7 @@ to `imenu-update-menubar'.")
     (imenu item)
     nil))
 
-(defun imenu-default-goto-function (_name position &optional _rest)
+(defun imenu-default-goto-function (_name position &rest _rest)
   "Move to the given position.
 
 NAME is ignored.  POSITION is where to move.  REST is also ignored.
@@ -1002,7 +1025,7 @@ The ignored args just make this function have the same interface as a
 function placed in a special index-item."
   (if (or (< position (point-min))
          (> position (point-max)))
-      ;; widen if outside narrowing
+      ;; Widen if outside narrowing.
       (widen))
   (goto-char position))
 
@@ -1016,16 +1039,13 @@ for more information."
   (if (stringp index-item)
       (setq index-item (assoc index-item (imenu--make-index-alist))))
   (when index-item
-    (push-mark nil t)
-    (let* ((is-special-item (listp (cdr index-item)))
-          (function
-           (if is-special-item
-               (nth 2 index-item) imenu-default-goto-function))
-          (position (if is-special-item
-                        (cadr index-item) (cdr index-item)))
-          (rest (if is-special-item (cddr index-item))))
-      (apply function (car index-item) position rest))
-    (run-hooks 'imenu-after-jump-hook)))
+    (pcase index-item
+      (`(,name ,pos ,fn . ,args)
+       (push-mark nil t)
+       (apply fn name pos args)
+       (run-hooks 'imenu-after-jump-hook))
+      (`(,name . ,pos) (imenu (list name pos imenu-default-goto-function)))
+      (_ (error "Unknown imenu item: %S" index-item)))))
 
 (provide 'imenu)