aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard M. Stallman1998-04-30 00:05:06 +0000
committerRichard M. Stallman1998-04-30 00:05:06 +0000
commitfe2908be7b09f4c765ebdaf16fe07b0a77f78ba8 (patch)
tree8c59549201f51f818f427413534486618a5574d4
parent4063eb1c9cdda753fd4d2a2b10456f5df3cfed6e (diff)
downloademacs-fe2908be7b09f4c765ebdaf16fe07b0a77f78ba8.tar.gz
emacs-fe2908be7b09f4c765ebdaf16fe07b0a77f78ba8.zip
(imenu--generic-function): Doc fix. Rewritten to be faster.
(defgroup imenu): Add :link. (imenu-use-markers, imenu-auto-rescan-maxout, imenu-generic-expression) (imenu--make-index-alist, imenu-default-goto-function): Doc fixes. (imenu-max-item-length, imenu-sort-function) (imenu-scanning-message): Custom tweak. (imenu-progress-message): Use real backquote syntax. (imenu--in-alist): Unused function deleted. (imenu--flatten-index-alist): Likewise. (imenu-case-fold-search): Add autoload cookie. (imenu--completion-buffer): Offer function at point as default. (imenu--subalist-p): Don't use caadr. (imenu): Don't use caddr. (imenu-add-menubar-index): New function.
-rw-r--r--lisp/imenu.el405
1 files changed, 210 insertions, 195 deletions
diff --git a/lisp/imenu.el b/lisp/imenu.el
index 1e276705169..cae7310eed0 100644
--- a/lisp/imenu.el
+++ b/lisp/imenu.el
@@ -1,6 +1,6 @@
1;;; imenu.el --- Framework for mode-specific buffer indexes. 1;;; imenu.el --- Framework for mode-specific buffer indexes.
2 2
3;; Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. 3;; Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
4 4
5;; Author: Ake Stenhoff <etxaksf@aom.ericsson.se> 5;; Author: Ake Stenhoff <etxaksf@aom.ericsson.se>
6;; Lars Lindberg <lli@sypro.cap.se> 6;; Lars Lindberg <lli@sypro.cap.se>
@@ -32,6 +32,8 @@
32;; A buffer index is an alist of names and buffer positions. 32;; A buffer index is an alist of names and buffer positions.
33;; For instance all functions in a C-file and their positions. 33;; For instance all functions in a C-file and their positions.
34;; 34;;
35;; It is documented in the Emacs Lisp manual.
36;;
35;; How it works: 37;; How it works:
36 38
37;; A mode-specific function is called to generate the index. It is 39;; A mode-specific function is called to generate the index. It is
@@ -45,10 +47,11 @@
45;; customize for other modes. A function for jumping to the chosen 47;; customize for other modes. A function for jumping to the chosen
46;; index position is also supplied. 48;; index position is also supplied.
47 49
48;;; Thanks goes to 50;;; History:
51;; Thanks go to
49;; [simon] - Simon Leinen simon@lia.di.epfl.ch 52;; [simon] - Simon Leinen simon@lia.di.epfl.ch
50;; [dean] - Dean Andrews ada@unison.com 53;; [dean] - Dean Andrews ada@unison.com
51;; [alon] - Alon Albert al@mercury.co.il 54;; [alon] - Alon Albert al@mercury.co.il
52;; [greg] - Greg Thompson gregt@porsche.visix.COM 55;; [greg] - Greg Thompson gregt@porsche.visix.COM
53;; [wolfgang] - Wolfgang Bangerth zcg51122@rpool1.rus.uni-stuttgart.de 56;; [wolfgang] - Wolfgang Bangerth zcg51122@rpool1.rus.uni-stuttgart.de
54;; [kai] - Kai Grossjohann grossjoh@linus.informatik.uni-dortmund.de 57;; [kai] - Kai Grossjohann grossjoh@linus.informatik.uni-dortmund.de
@@ -69,11 +72,14 @@
69(defgroup imenu nil 72(defgroup imenu nil
70 "Mode-specific buffer indexes." 73 "Mode-specific buffer indexes."
71 :group 'matching 74 :group 'matching
72 :group 'frames) 75 :group 'frames
76 :link '(custom-manual "(elisp)Imenu"))
73 77
74(defcustom imenu-use-markers t 78(defcustom imenu-use-markers t
75 "*Non-nil means use markers instead of integers for Imenu buffer positions. 79 "*Non-nil means use markers instead of integers for Imenu buffer positions.
76Setting this to nil makes Imenu work faster. 80
81Setting this to nil makes Imenu work a little faster but editing the
82buffer will make the generated index positions wrong.
77 83
78This might not yet be honored by all index-building functions." 84This might not yet be honored by all index-building functions."
79 :type 'boolean 85 :type 'boolean
@@ -82,7 +88,8 @@ This might not yet be honored by all index-building functions."
82 88
83(defcustom imenu-max-item-length 60 89(defcustom imenu-max-item-length 60
84 "*If a number, truncate Imenu entries to that length." 90 "*If a number, truncate Imenu entries to that length."
85 :type 'integer 91 :type '(choice integer
92 (const :tag "Unlimited"))
86 :group 'imenu) 93 :group 'imenu)
87 94
88(defcustom imenu-auto-rescan nil 95(defcustom imenu-auto-rescan nil
@@ -90,8 +97,8 @@ This might not yet be honored by all index-building functions."
90 :type 'boolean 97 :type 'boolean
91 :group 'imenu) 98 :group 'imenu)
92 99
93(defcustom imenu-auto-rescan-maxout 60000 100(defcustom imenu-auto-rescan-maxout 60000
94 "*Imenu auto-rescan is disabled in buffers larger than this size. 101 "*Imenu auto-rescan is disabled in buffers larger than this size (in bytes).
95This variable is buffer-local." 102This variable is buffer-local."
96 :type 'integer 103 :type 'integer
97 :group 'imenu) 104 :group 'imenu)
@@ -122,7 +129,9 @@ Set it to `imenu--sort-by-name' if you want alphabetic sorting.
122The function should take two arguments and return T if the first 129The function should take two arguments and return T if the first
123element should come before the second. The arguments are cons cells; 130element should come before the second. The arguments are cons cells;
124\(NAME . POSITION). Look at `imenu--sort-by-name' for an example." 131\(NAME . POSITION). Look at `imenu--sort-by-name' for an example."
125 :type 'function 132 :type '(choice (const :tag "No sorting" nil)
133 (const :tag "Sort by name" 'imenu--sort-by-name)
134 (function :tag "Another function"))
126 :group 'imenu) 135 :group 'imenu)
127 136
128(defcustom imenu-max-items 25 137(defcustom imenu-max-items 25
@@ -135,8 +144,10 @@ element should come before the second. The arguments are cons cells;
135If non-nil, user gets a message during the scanning of the buffer. 144If non-nil, user gets a message during the scanning of the buffer.
136 145
137Relevant only if the mode-specific function that creates the buffer 146Relevant only if the mode-specific function that creates the buffer
138index use `imenu-progress-message'." 147index use `imenu-progress-message', and not useful if that is fast, in
139 :type 'string 148which case you might as well set this to nil."
149 :type '(choice string
150 (const :tag "None" nil))
140 :group 'imenu) 151 :group 'imenu)
141 152
142(defcustom imenu-space-replacement "^" 153(defcustom imenu-space-replacement "^"
@@ -180,16 +191,16 @@ menu. See the info section on Regexps for more information.
180INDEX points to the substring in REGEXP that contains the name (of the 191INDEX points to the substring in REGEXP that contains the name (of the
181function, variable or type) that is to appear in the menu. 192function, variable or type) that is to appear in the menu.
182 193
183For emacs-lisp-mode for example PATTERN would look like:
184
185'((nil \"^\\\\s-*(def\\\\(un\\\\|subst\\\\|macro\\\\|advice\\\\)\\\\s-+\\\\([-A-Za-z0-9+]+\\\\)\" 2)
186 (\"*Vars*\" \"^\\\\s-*(def\\\\(var\\\\|const\\\\)\\\\s-+\\\\([-A-Za-z0-9+]+\\\\)\" 2)
187 (\"*Types*\" \"^\\\\s-*(def\\\\(type\\\\|struct\\\\|class\\\\|ine-condition\\\\)\\\\s-+\\\\([-A-Za-z0-9+]+\\\\)\" 2))
188
189The variable is buffer-local. 194The variable is buffer-local.
190 195
191The variable `imenu-case-fold-search' determines whether or not the 196The variable `imenu-case-fold-search' determines whether or not the
192regexp matches are case sensitive.") 197regexp matches are case sensitive. and `imenu-syntax-alist' can be
198used to alter the syntax table for the search.
199
200For example, see the value of `lisp-imenu-generic-expression' used by
201`lisp-mode' and `emacs-lisp-mode' with `imenu-syntax-alist' set
202locally to give the characters which normally have \"punctuation\"
203syntax \"word\" syntax during matching.")
193 204
194;;;###autoload 205;;;###autoload
195(make-variable-buffer-local 'imenu-generic-expression) 206(make-variable-buffer-local 'imenu-generic-expression)
@@ -206,11 +217,12 @@ Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION).
206Special elements look like (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...). 217Special elements look like (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...).
207A nested sub-alist element looks like (INDEX-NAME SUB-ALIST). 218A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
208The function `imenu--subalist-p' tests an element and returns t 219The function `imenu--subalist-p' tests an element and returns t
209 if it is a sub-alist. 220if it is a sub-alist.
210 221
211This function is called within a `save-excursion'. 222This function is called within a `save-excursion'.
212 223
213The variable is buffer-local.") 224The variable is buffer-local.")
225;;;###autoload
214(make-variable-buffer-local 'imenu-create-index-function) 226(make-variable-buffer-local 'imenu-create-index-function)
215 227
216(defvar imenu-prev-index-position-function 'beginning-of-defun 228(defvar imenu-prev-index-position-function 'beginning-of-defun
@@ -229,7 +241,7 @@ This variable is local in all buffers.")
229(make-variable-buffer-local 'imenu-prev-index-position-function) 241(make-variable-buffer-local 'imenu-prev-index-position-function)
230 242
231(defvar imenu-extract-index-name-function nil 243(defvar imenu-extract-index-name-function nil
232 "Function for extracting the index item nam, given a position. 244 "Function for extracting the index item name, given a position.
233 245
234This function is called after `imenu-prev-index-position-function' 246This function is called after `imenu-prev-index-position-function'
235finds a position for an index item, with point at that position. 247finds a position for an index item, with point at that position.
@@ -247,25 +259,24 @@ The function in this variable is called when selecting a normal index-item.")
247 259
248(defun imenu--subalist-p (item) 260(defun imenu--subalist-p (item)
249 (and (consp (cdr item)) (listp (cadr item)) 261 (and (consp (cdr item)) (listp (cadr item))
250 (not (eq (caadr item) 'lambda)))) 262 (not (eq (car (cadr item)) 'lambda))))
251 263
252;;; 264;; Macro to display a progress message.
253;;; Macro to display a progress message. 265;; RELPOS is the relative position to display.
254;;; RELPOS is the relative position to display. 266;; If RELPOS is nil, then the relative position in the buffer
255;;; If RELPOS is nil, then the relative position in the buffer 267;; is calculated.
256;;; is calculated. 268;; PREVPOS is the variable in which we store the last position displayed.
257;;; PREVPOS is the variable in which we store the last position displayed.
258(defmacro imenu-progress-message (prevpos &optional relpos reverse) 269(defmacro imenu-progress-message (prevpos &optional relpos reverse)
259 (` (and 270 `(and
260 imenu-scanning-message 271 imenu-scanning-message
261 (let ((pos (, (if relpos 272 (let ((pos ,(if relpos
262 relpos 273 relpos
263 (` (imenu--relative-position (, reverse))))))) 274 `(imenu--relative-position ,reverse))))
264 (if (, (if relpos t 275 (if ,(if relpos t
265 (` (> pos (+ 5 (, prevpos)))))) 276 `(> pos (+ 5 ,prevpos)))
266 (progn 277 (progn
267 (message imenu-scanning-message pos) 278 (message imenu-scanning-message pos)
268 (setq (, prevpos) pos))))))) 279 (setq ,prevpos pos))))))
269 280
270 281
271;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 282;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -288,7 +299,7 @@ The function in this variable is called when selecting a normal index-item.")
288 299
289;;; 300;;;
290;;; Lisp 301;;; Lisp
291;;; 302;;;
292 303
293(defun imenu-example--lisp-extract-index-name () 304(defun imenu-example--lisp-extract-index-name ()
294 ;; Example of a candidate for `imenu-extract-index-name-function'. 305 ;; Example of a candidate for `imenu-extract-index-name-function'.
@@ -317,31 +328,31 @@ The function in this variable is called when selecting a normal index-item.")
317 ;; Search for the function 328 ;; Search for the function
318 (while (beginning-of-defun) 329 (while (beginning-of-defun)
319 (imenu-progress-message prev-pos nil t) 330 (imenu-progress-message prev-pos nil t)
320 (save-match-data 331 (save-match-data
321 (and (looking-at "(def") 332 (and (looking-at "(def")
322 (save-excursion 333 (save-excursion
323 (down-list 1) 334 (down-list 1)
324 (cond 335 (cond
325 ((looking-at "def\\(var\\|const\\)") 336 ((looking-at "def\\(var\\|const\\)")
326 (forward-sexp 2) 337 (forward-sexp 2)
327 (push (imenu-example--name-and-position) 338 (push (imenu-example--name-and-position)
328 index-var-alist)) 339 index-var-alist))
329 ((looking-at "def\\(un\\|subst\\|macro\\|advice\\)") 340 ((looking-at "def\\(un\\|subst\\|macro\\|advice\\)")
330 (forward-sexp 2) 341 (forward-sexp 2)
331 (push (imenu-example--name-and-position) 342 (push (imenu-example--name-and-position)
332 index-alist)) 343 index-alist))
333 ((looking-at "def\\(type\\|struct\\|class\\|ine-condition\\)") 344 ((looking-at "def\\(type\\|struct\\|class\\|ine-condition\\)")
334 (forward-sexp 2) 345 (forward-sexp 2)
335 (if (= (char-after (1- (point))) ?\)) 346 (if (= (char-after (1- (point))) ?\))
336 (progn 347 (progn
337 (forward-sexp -1) 348 (forward-sexp -1)
338 (down-list 1) 349 (down-list 1)
339 (forward-sexp 1))) 350 (forward-sexp 1)))
340 (push (imenu-example--name-and-position) 351 (push (imenu-example--name-and-position)
341 index-type-alist)) 352 index-type-alist))
342 (t 353 (t
343 (forward-sexp 2) 354 (forward-sexp 2)
344 (push (imenu-example--name-and-position) 355 (push (imenu-example--name-and-position)
345 index-unknown-alist))))))) 356 index-unknown-alist)))))))
346 (imenu-progress-message prev-pos 100) 357 (imenu-progress-message prev-pos 100)
347 (and index-var-alist 358 (and index-var-alist
@@ -357,7 +368,7 @@ The function in this variable is called when selecting a normal index-item.")
357 368
358;; Regular expression to find C functions 369;; Regular expression to find C functions
359(defvar imenu-example--function-name-regexp-c 370(defvar imenu-example--function-name-regexp-c
360 (concat 371 (concat
361 "^[a-zA-Z0-9]+[ \t]?" ; type specs; there can be no 372 "^[a-zA-Z0-9]+[ \t]?" ; type specs; there can be no
362 "\\([a-zA-Z0-9_*]+[ \t]+\\)?" ; more than 3 tokens, right? 373 "\\([a-zA-Z0-9_*]+[ \t]+\\)?" ; more than 3 tokens, right?
363 "\\([a-zA-Z0-9_*]+[ \t]+\\)?" 374 "\\([a-zA-Z0-9_*]+[ \t]+\\)?"
@@ -500,12 +511,13 @@ This variable is local in all buffers, once set.")
500;;; Split up each long alist that are nested within ALIST 511;;; Split up each long alist that are nested within ALIST
501;;; into nested alists. 512;;; into nested alists.
502(defun imenu--split-submenus (alist) 513(defun imenu--split-submenus (alist)
503 (mapcar (function (lambda (elt) 514 (mapcar (function
504 (if (and (consp elt) 515 (lambda (elt)
505 (stringp (car elt)) 516 (if (and (consp elt)
506 (listp (cdr elt))) 517 (stringp (car elt))
507 (imenu--split-menu (cdr elt) (car elt)) 518 (listp (cdr elt)))
508 elt))) 519 (imenu--split-menu (cdr elt) (car elt))
520 elt)))
509 alist)) 521 alist))
510 522
511;;; Truncate all strings in MENULIST to imenu-max-item-length 523;;; Truncate all strings in MENULIST to imenu-max-item-length
@@ -526,11 +538,14 @@ This variable is local in all buffers, once set.")
526(defun imenu--make-index-alist (&optional noerror) 538(defun imenu--make-index-alist (&optional noerror)
527 "Create an index-alist for the definitions in the current buffer. 539 "Create an index-alist for the definitions in the current buffer.
528 540
541Report an error if the list is empty unless NOERROR is supplied and
542non-nil.
543
529Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION). 544Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION).
530Special elements look like (INDEX-NAME FUNCTION ARGUMENTS...). 545Special elements look like (INDEX-NAME FUNCTION ARGUMENTS...).
531A nested sub-alist element looks like (INDEX-NAME SUB-ALIST). 546A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
532The function `imenu--subalist-p' tests an element and returns t 547The function `imenu--subalist-p' tests an element and returns t
533 if it is a sub-alist. 548if it is a sub-alist.
534 549
535There is one simple element with negative POSITION; that's intended 550There is one simple element with negative POSITION; that's intended
536as a way for the user to ask to recalculate the buffer's index alist." 551as a way for the user to ask to recalculate the buffer's index alist."
@@ -560,7 +575,7 @@ as a way for the user to ask to recalculate the buffer's index alist."
560(defvar imenu--cleanup-seen) 575(defvar imenu--cleanup-seen)
561 576
562(defun imenu--cleanup (&optional alist) 577(defun imenu--cleanup (&optional alist)
563 ;; If alist is provided use that list. 578 ;; If alist is provided use that list.
564 ;; If not, empty the table of lists already seen 579 ;; If not, empty the table of lists already seen
565 ;; and use imenu--index-alist. 580 ;; and use imenu--index-alist.
566 (if alist 581 (if alist
@@ -596,8 +611,7 @@ as a way for the user to ask to recalculate the buffer's index alist."
596 (imenu--menubar-select ',item)) 611 (imenu--menubar-select ',item))
597 (cons '(nil) item)))) 612 (cons '(nil) item))))
598 (cons (car item) 613 (cons (car item)
599 (cons (car item) end)))) 614 (cons (car item) end)))))))
600 )))
601 alist))) 615 alist)))
602 616
603;; If COMMANDS is non-nil, make a real keymap 617;; If COMMANDS is non-nil, make a real keymap
@@ -606,16 +620,15 @@ as a way for the user to ask to recalculate the buffer's index alist."
606(defun imenu--create-keymap-1 (title alist &optional commands) 620(defun imenu--create-keymap-1 (title alist &optional commands)
607 (append (list 'keymap title) (imenu--create-keymap-2 alist 0 commands))) 621 (append (list 'keymap title) (imenu--create-keymap-2 alist 0 commands)))
608 622
609
610(defun imenu--in-alist (str alist) 623(defun imenu--in-alist (str alist)
611 "Check whether the string STR is contained in multi-level ALIST." 624 "Check whether the string STR is contained in multi-level ALIST."
612 (let (elt head tail res) 625 (let (elt head tail res)
613 (setq res nil) 626 (setq res nil)
614 (while alist 627 (while alist
615 (setq elt (car alist) 628 (setq elt (car alist)
616 tail (cdr elt) 629 tail (cdr elt)
617 alist (cdr alist) 630 alist (cdr alist)
618 head (car elt)) 631 head (car elt))
619 ;; A nested ALIST element looks like 632 ;; A nested ALIST element looks like
620 ;; (INDEX-NAME (INDEX-NAME . INDEX-POSITION) ...) 633 ;; (INDEX-NAME (INDEX-NAME . INDEX-POSITION) ...)
621 ;; while a bottom-level element looks like 634 ;; while a bottom-level element looks like
@@ -656,7 +669,7 @@ Their results are gathered into an index alist."
656 (goto-char (point-max)) 669 (goto-char (point-max))
657 (imenu-progress-message prev-pos 0 t) 670 (imenu-progress-message prev-pos 0 t)
658 ;; Search for the function 671 ;; Search for the function
659 (while (funcall imenu-prev-index-position-function) 672 (while (funcall imenu-prev-index-position-function)
660 (imenu-progress-message prev-pos nil t) 673 (imenu-progress-message prev-pos nil t)
661 (save-excursion 674 (save-excursion
662 (setq name (funcall imenu-extract-index-name-function))) 675 (setq name (funcall imenu-extract-index-name-function)))
@@ -668,7 +681,7 @@ Their results are gathered into an index alist."
668 index-alist)) 681 index-alist))
669 ;; Use generic expression if possible. 682 ;; Use generic expression if possible.
670 ((and imenu-generic-expression) 683 ((and imenu-generic-expression)
671 (imenu--generic-function imenu-generic-expression)) 684 (imenu--generic-function imenu-generic-expression))
672 (t 685 (t
673 (error "This buffer cannot use `imenu-default-create-index-function'")))) 686 (error "This buffer cannot use `imenu-default-create-index-function'"))))
674 687
@@ -684,26 +697,26 @@ Their results are gathered into an index alist."
684 name 697 name
685 "")) 698 ""))
686 699
687(defun imenu--flatten-index-alist (index-alist &optional concat-names prefix) 700;; Not used and would require cl at run time
688 ;; Takes a nested INDEX-ALIST and returns a flat index alist. 701;;; (defun imenu--flatten-index-alist (index-alist &optional concat-names prefix)
689 ;; If optional CONCAT-NAMES is non-nil, then a nested index has its 702;;; ;; Takes a nested INDEX-ALIST and returns a flat index alist.
690 ;; name and a space concatenated to the names of the children. 703;;; ;; If optional CONCAT-NAMES is non-nil, then a nested index has its
691 ;; Third argument PREFIX is for internal use only. 704;;; ;; name and a space concatenated to the names of the children.
692 (mapcan 705;;; ;; Third argument PREFIX is for internal use only.
693 (function 706;;; (mapcan
694 (lambda (item) 707;;; (lambda (item)
695 (let* ((name (car item)) 708;;; (let* ((name (car item))
696 (pos (cdr item)) 709;;; (pos (cdr item))
697 (new-prefix (and concat-names 710;;; (new-prefix (and concat-names
698 (if prefix 711;;; (if prefix
699 (concat prefix imenu-level-separator name) 712;;; (concat prefix imenu-level-separator name)
700 name)))) 713;;; name))))
701 (cond 714;;; (cond
702 ((or (markerp pos) (numberp pos)) 715;;; ((or (markerp pos) (numberp pos))
703 (list (cons new-prefix pos))) 716;;; (list (cons new-prefix pos)))
704 (t 717;;; (t
705 (imenu--flatten-index-alist pos new-prefix)))))) 718;;; (imenu--flatten-index-alist pos new-prefix)))))
706 index-alist)) 719;;; index-alist))
707 720
708;;; 721;;;
709;;; Generic index gathering function. 722;;; Generic index gathering function.
@@ -716,15 +729,16 @@ This buffer-local variable should be set (only) by initialization code
716for modes which use `imenu--generic-function'. If it is not set, that 729for modes which use `imenu--generic-function'. If it is not set, that
717function will use the current value of `case-fold-search' to match 730function will use the current value of `case-fold-search' to match
718patterns.") 731patterns.")
732;;;###autoload
719(make-variable-buffer-local 'imenu-case-fold-search) 733(make-variable-buffer-local 'imenu-case-fold-search)
720 734
735;; Originally "Built on some ideas that Erik Naggum <erik@naggum.no>
736;; once posted to comp.emacs" but since substantially re-written.
721(defun imenu--generic-function (patterns) 737(defun imenu--generic-function (patterns)
722;; Built on some ideas that Erik Naggum <erik@naggum.no> once posted
723;; to comp.emacs
724 "Return an index of the current buffer as an alist. 738 "Return an index of the current buffer as an alist.
725 739
726PATTERN is an alist with elements that look like this: (MENU-TITLE 740PATTERNS is an alist with elements that look like this:
727REGEXP INDEX). 741 (MENU-TITLE REGEXP INDEX).
728 742
729MENU-TITLE is a string used as the title for the submenu or nil if the 743MENU-TITLE is a string used as the title for the submenu or nil if the
730entries are not nested. 744entries are not nested.
@@ -737,85 +751,70 @@ menu. See the info section on Regexps for more information.
737INDEX points to the substring in REGEXP that contains the name (of the 751INDEX points to the substring in REGEXP that contains the name (of the
738function, variable or type) that is to appear in the menu. 752function, variable or type) that is to appear in the menu.
739 753
740For emacs-lisp-mode for example PATTERN would look like: 754See `lisp-imenu-generic-expression' for an example of PATTERNS.
741
742'((nil \"^\\\\s-*(def\\\\(un\\\\|subst\\\\|macro\\\\|advice\\\\)\\\\s-+\\\\([-A-Za-z0-9]+\\\\)\" 2)
743 (\"*Vars*\" \"^\\\\s-*(def\\\\(var\\\\|const\\\\)\\\\s-+\\\\([-A-Za-z0-9]+\\\\)\" 2)
744 (\"*Types*\" \"^\\\\s-*(def\\\\(type\\\\|struct\\\\|class\\\\|ine-condition\\\\)\\\\s-+\\\\([-A-Za-z0-9]+\\\\)\" 2))'
745 755
746Returns an index of the current buffer as an alist. The elements in 756Returns an index of the current buffer as an alist. The elements in
747the alist look like: (INDEX-NAME . INDEX-POSITION). They may also be 757the alist look like: (INDEX-NAME . INDEX-POSITION). They may also be
748nested index lists like (INDEX-NAME . INDEX-ALIST) depending on 758nested index lists like (INDEX-NAME . INDEX-ALIST) depending on
749pattern. 759PATTERNS."
750
751\(imenu--generic-function PATTERN\)."
752 760
753 (let ((index-alist (list 'dummy)) 761 (let ((index-alist (list 'dummy))
754 (found nil) 762 prev-pos beg
755 (global-regexp
756 (concat "\\("
757 (mapconcat
758 (function (lambda (pattern) (identity (cadr pattern))))
759 patterns "\\)\\|\\(")
760 "\\)"))
761 prev-pos
762
763 (case-fold-search imenu-case-fold-search) 763 (case-fold-search imenu-case-fold-search)
764 (old-table (syntax-table)) 764 (old-table (syntax-table))
765 (table (copy-syntax-table (syntax-table))) 765 (table (copy-syntax-table (syntax-table)))
766 (slist imenu-syntax-alist)) 766 (slist imenu-syntax-alist))
767 ;; Modify the syntax table used while matching regexps. 767 ;; Modify the syntax table used while matching regexps.
768 (while slist 768 (while slist
769 ;; The character to modify may be a single CHAR or a STRING. 769 ;; The character(s) to modify may be a single char or a string.
770 (let ((chars (if (numberp (car (car slist))) 770 (if (numberp (caar slist))
771 (list (car (car slist))) 771 (modify-syntax-entry (caar slist) (cdar slist) table)
772 (mapcar 'identity (car (car slist))))) 772 (mapcar (function
773 (syntax (cdr (car slist)))) 773 (lambda (c)
774 (while chars 774 (modify-syntax-entry c (cdar slist) table)))
775 (modify-syntax-entry (car chars) syntax table) 775 (caar slist)))
776 (setq chars (cdr chars))) 776 (setq slist (cdr slist)))
777 (setq slist (cdr slist))))
778 (goto-char (point-max)) 777 (goto-char (point-max))
779 (imenu-progress-message prev-pos 0 t) 778 (imenu-progress-message prev-pos 0 t)
780 (unwind-protect 779 (unwind-protect ; for syntax table
781 (progn 780 (save-match-data
782 (set-syntax-table table) 781 (set-syntax-table table)
783 (save-match-data 782 ;; map over the elements of imenu-generic-expression
784 (while (re-search-backward global-regexp nil t) 783 ;; (typically functions, variables ...)
785 (imenu-progress-message prev-pos nil t) 784 (mapcar
786 (setq found nil) 785 (function
787 (save-excursion 786 (lambda (pat)
788 (goto-char (match-beginning 0)) 787 (let ((menu-title (car pat))
789 (mapcar 788 (regexp (nth 1 pat))
790 (function 789 (index (nth 2 pat))
791 (lambda (pat) 790 (function (nth 3 pat))
792 (let ((menu-title (car pat)) 791 (rest (nthcdr 4 pat)))
793 (regexp (cadr pat)) 792 ;; Go backwards for convenience of adding items in order.
794 (index (caddr pat)) 793 (goto-char (point-max))
795 (function (cadddr pat)) 794 (while (re-search-backward regexp nil t)
796 (rest (cddddr pat))) 795 (imenu-progress-message prev-pos nil t)
797 (if (and (not found) ; Only allow one entry; 796 (setq beg (match-beginning index))
798 (looking-at regexp)) 797 ;; Add this sort of submenu only when we've found an
799 (let ((beg (match-beginning index)) 798 ;; item for it, avoiding empty, duff menus.
800 (end (match-end index))) 799 (unless (assoc menu-title index-alist)
801 (setq found t) 800 (push (list menu-title) index-alist))
802 (push 801 (if imenu-use-markers
803 (let ((name 802 (setq beg (set-marker (make-marker) beg)))
804 (buffer-substring-no-properties beg end))) 803 (let ((item
805 ;; [ydi] updated for imenu-use-markers 804 (if function
806 (if imenu-use-markers 805 (nconc (list (match-string-no-properties index)
807 (setq beg (set-marker (make-marker) beg))) 806 beg function)
808 (if function 807 rest)
809 (nconc (list name beg function) 808 (cons (match-string-no-properties index)
810 rest) 809 beg)))
811 (cons name beg))) 810 (menu (cdr (assoc menu-title index-alist))))
812 (cdr 811 ;; avoid duplicates from, e.g. cc-mode patterns
813 (or (assoc menu-title index-alist) 812 (unless (member item menu)
814 (car (push 813 ;; insert the item after the (sub-)menu title
815 (cons menu-title '()) 814 (setcdr (assoc menu-title index-alist)
816 index-alist)))))))))) 815 (cons item menu))))))))
817 patterns))) 816 patterns)
818 (set-syntax-table old-table)))) 817 (set-syntax-table old-table)))
819 (imenu-progress-message prev-pos 100 t) 818 (imenu-progress-message prev-pos 100 t)
820 (let ((main-element (assq nil index-alist))) 819 (let ((main-element (assq nil index-alist)))
821 (nconc (delq main-element (delq 'dummy index-alist)) 820 (nconc (delq main-element (delq 'dummy index-alist))
@@ -832,33 +831,39 @@ pattern.
832 831
833Returns t for rescan and otherwise a position number." 832Returns t for rescan and otherwise a position number."
834 ;; Create a list for this buffer only when needed. 833 ;; Create a list for this buffer only when needed.
835 (let (name choice 834 (let ((name (thing-at-point 'symbol))
836 (prepared-index-alist 835 choice
837 (mapcar 836 (prepared-index-alist
838 (function 837 (mapcar
839 (lambda (item) 838 (function
840 (cons (imenu--replace-spaces (car item) imenu-space-replacement) 839 (lambda (item)
841 (cdr item)))) 840 (cons (imenu--replace-spaces (car item) imenu-space-replacement)
842 index-alist))) 841 (cdr item))))
842 index-alist)))
843 (cond (prompt)
844 ((and name (imenu--in-alist name prepared-index-alist))
845 (setq prompt (format "Index item (default %s): " name)))
846 (t (setq prompt "Index item: ")))
843 (if (eq imenu-always-use-completion-buffer-p 'never) 847 (if (eq imenu-always-use-completion-buffer-p 'never)
844 (setq name (completing-read (or prompt "Index item: ") 848 (setq name (completing-read prompt
845 prepared-index-alist 849 prepared-index-alist
846 nil t nil 'imenu--history-list)) 850 nil t nil 'imenu--history-list name))
847 (save-window-excursion 851 (save-window-excursion
848 ;; Display the completion buffer 852 ;; Display the completion buffer
849 (with-output-to-temp-buffer "*Completions*" 853 (with-output-to-temp-buffer "*Completions*"
850 (display-completion-list 854 (display-completion-list
851 (all-completions "" prepared-index-alist ))) 855 (all-completions "" prepared-index-alist )))
852 (let ((minibuffer-setup-hook 856 (let ((minibuffer-setup-hook
853 (function (lambda () 857 (function
854 (let ((buffer (current-buffer))) 858 (lambda ()
855 (save-excursion 859 (let ((buffer (current-buffer)))
856 (set-buffer "*Completions*") 860 (save-excursion
857 (setq completion-reference-buffer buffer))))))) 861 (set-buffer "*Completions*")
862 (setq completion-reference-buffer buffer)))))))
858 ;; Make a completion question 863 ;; Make a completion question
859 (setq name (completing-read (or prompt "Index item: ") 864 (setq name (completing-read prompt
860 prepared-index-alist 865 prepared-index-alist
861 nil t nil 'imenu--history-list))))) 866 nil t nil 'imenu--history-list name)))))
862 (cond ((not (stringp name)) 867 (cond ((not (stringp name))
863 nil) 868 nil)
864 ((string= name (car imenu--rescan-item)) 869 ((string= name (car imenu--rescan-item))
@@ -877,9 +882,9 @@ INDEX-ALIST is the buffer index and EVENT is a mouse event.
877Returns t for rescan and otherwise an element or subelement of INDEX-ALIST." 882Returns t for rescan and otherwise an element or subelement of INDEX-ALIST."
878 (setq index-alist (imenu--split-submenus index-alist)) 883 (setq index-alist (imenu--split-submenus index-alist))
879 (let* ((menu (imenu--split-menu index-alist 884 (let* ((menu (imenu--split-menu index-alist
880 (or title (buffer-name)))) 885 (or title (buffer-name))))
881 position) 886 position)
882 (setq menu (imenu--create-keymap-1 (car menu) 887 (setq menu (imenu--create-keymap-1 (car menu)
883 (if (< 1 (length (cdr menu))) 888 (if (< 1 (length (cdr menu)))
884 (cdr menu) 889 (cdr menu)
885 (cdr (car (cdr menu)))))) 890 (cdr (car (cdr menu))))))
@@ -896,7 +901,7 @@ Returns t for rescan and otherwise an element or subelement of INDEX-ALIST."
896 (setq final (assoc (car position) final)) 901 (setq final (assoc (car position) final))
897 (setq position (cdr position))) 902 (setq position (cdr position)))
898 (or (string= (car final) (car imenu--rescan-item)) 903 (or (string= (car final) (car imenu--rescan-item))
899 (cdr (cdr (cdr final)))))) 904 (nthcdr 3 final))))
900 ;; If x-popup-menu went just one level and found a leaf item, 905 ;; If x-popup-menu went just one level and found a leaf item,
901 ;; return the INDEX-ALIST element for that. 906 ;; return the INDEX-ALIST element for that.
902 ((and (consp position) 907 ((and (consp position)
@@ -956,7 +961,7 @@ The returned value is of the form (INDEX-NAME . INDEX-POSITION)."
956 961
957;;;###autoload 962;;;###autoload
958(defun imenu-add-to-menubar (name) 963(defun imenu-add-to-menubar (name)
959 "Adds an `imenu' entry to the menu bar for the current buffer. 964 "Add an `imenu' entry to the menu bar for the current buffer.
960NAME is a string used to name the menu bar item. 965NAME is a string used to name the menu bar item.
961See the command `imenu' for more information." 966See the command `imenu' for more information."
962 (interactive "sImenu menu item name: ") 967 (interactive "sImenu menu item name: ")
@@ -976,6 +981,14 @@ See the command `imenu' for more information."
976 (add-hook 'menu-bar-update-hook 'imenu-update-menubar)) 981 (add-hook 'menu-bar-update-hook 'imenu-update-menubar))
977 (error "The mode `%s' does not support Imenu" mode-name))) 982 (error "The mode `%s' does not support Imenu" mode-name)))
978 983
984;;;###autoload
985(defun imenu-add-menubar-index ()
986 "Add an Imenu \"Index\" entry on the menu bar for the current buffer.
987
988A trivial interface to `imenu-add-to-menubar' suitable for use in a hook."
989 (interactive)
990 (imenu-add-to-menubar "Index"))
991
979(defvar imenu-buffer-menubar nil) 992(defvar imenu-buffer-menubar nil)
980 993
981(defun imenu-update-menubar () 994(defun imenu-update-menubar ()
@@ -989,12 +1002,12 @@ See the command `imenu' for more information."
989 (setq imenu--last-menubar-index-alist index-alist) 1002 (setq imenu--last-menubar-index-alist index-alist)
990 (setq index-alist (imenu--split-submenus index-alist)) 1003 (setq index-alist (imenu--split-submenus index-alist))
991 (setq menu (imenu--split-menu index-alist 1004 (setq menu (imenu--split-menu index-alist
992 (buffer-name))) 1005 (buffer-name)))
993 (setq menu1 (imenu--create-keymap-1 (car menu) 1006 (setq menu1 (imenu--create-keymap-1 (car menu)
994 (if (< 1 (length (cdr menu))) 1007 (if (< 1 (length (cdr menu)))
995 (cdr menu) 1008 (cdr menu)
996 (cdr (car (cdr menu)))) 1009 (cdr (car (cdr menu))))
997 t)) 1010 t))
998 (setq old (lookup-key (current-local-map) [menu-bar index])) 1011 (setq old (lookup-key (current-local-map) [menu-bar index]))
999 (setcdr old (cdr menu1))))))) 1012 (setcdr old (cdr menu1)))))))
1000 1013
@@ -1008,10 +1021,11 @@ See the command `imenu' for more information."
1008 (imenu item))) 1021 (imenu item)))
1009 1022
1010(defun imenu-default-goto-function (name position &optional rest) 1023(defun imenu-default-goto-function (name position &optional rest)
1011 "This function is used for moving the point to POSITION. 1024 "Move the point to the given position.
1012The NAME and REST parameters are not used, they are here just to make 1025
1013this function have the same interface as a function placed in a special 1026NAME is ignored. POSITION is where to move. REST is also ignored.
1014index-item." 1027The ignored args just make this function have the same interface as a
1028function placed in a special index-item."
1015 (if (or (< position (point-min)) 1029 (if (or (< position (point-min))
1016 (> position (point-max))) 1030 (> position (point-max)))
1017 ;; widen if outside narrowing 1031 ;; widen if outside narrowing
@@ -1021,7 +1035,8 @@ index-item."
1021;;;###autoload 1035;;;###autoload
1022(defun imenu (index-item) 1036(defun imenu (index-item)
1023 "Jump to a place in the buffer chosen using a buffer menu or mouse menu. 1037 "Jump to a place in the buffer chosen using a buffer menu or mouse menu.
1024See `imenu-choose-buffer-index' for more information." 1038INDEX-ITEM specifies the position. See `imenu-choose-buffer-index'
1039for more information."
1025 (interactive (list (imenu-choose-buffer-index))) 1040 (interactive (list (imenu-choose-buffer-index)))
1026 ;; Convert a string to an alist element. 1041 ;; Convert a string to an alist element.
1027 (if (stringp index-item) 1042 (if (stringp index-item)
@@ -1030,9 +1045,9 @@ See `imenu-choose-buffer-index' for more information."
1030 (progn 1045 (progn
1031 (push-mark) 1046 (push-mark)
1032 (let* ((is-special-item (listp (cdr index-item))) 1047 (let* ((is-special-item (listp (cdr index-item)))
1033 (function 1048 (function
1034 (if is-special-item 1049 (if is-special-item
1035 (caddr index-item) imenu-default-goto-function)) 1050 (nth 2 index-item) imenu-default-goto-function))
1036 (position (if is-special-item 1051 (position (if is-special-item
1037 (cadr index-item) (cdr index-item))) 1052 (cadr index-item) (cdr index-item)))
1038 (rest (if is-special-item (cddr index-item)))) 1053 (rest (if is-special-item (cddr index-item))))