X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/0f668a4db4a33f98f84613513af3efea521b4847..e18ee60b02d08b2f075903005798d3d6064dc013:/lisp/imenu.el diff --git a/lisp/imenu.el b/lisp/imenu.el index 0bfee77009..48257b892d 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -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 ;; Lars Lindberg -;; 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) @@ -448,11 +463,16 @@ 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. +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. @@ -465,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'.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; @@ -488,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 '()) @@ -553,16 +570,14 @@ NOT share structure with ALIST." (defun imenu--truncate-items (menulist) "Truncate all strings in MENULIST to `imenu-max-item-length'." - (mapcar (lambda (item) - (cond - ((consp (cdr item)) - (imenu--truncate-items (cdr item))) - ;; truncate if necessary - ((and (numberp imenu-max-item-length) - (> (length (car item)) imenu-max-item-length)) - (setcar item (substring (car item) 0 imenu-max-item-length))))) - menulist)) - + (mapc (lambda (item) + ;; 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))) + (when (imenu--subalist-p item) + (imenu--truncate-items (cdr item)))) + menulist)) (defun imenu--make-index-alist (&optional noerror) "Create an index alist for the definitions in the current buffer. @@ -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 @@ -676,26 +694,27 @@ The alternate method, which is the one most often used, is to call ;; in these major modes. But save that change for later. (cond ((and imenu-prev-index-position-function imenu-extract-index-name-function) - (let ((index-alist '()) (pos (point)) + (let ((index-alist '()) (pos (point-max)) name) - (goto-char (point-max)) + (goto-char pos) ;; Search for the function (while (funcall imenu-prev-index-position-function) - (when (= pos (point)) + (unless (< (point) pos) (error "Infinite loop at %s:%d: imenu-prev-index-position-function does not move point" (buffer-name) pos)) (setq pos (point)) (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)