(ange-ftp-reread-dir): Renamed from `re-read'.
[bpt/emacs.git] / lisp / imenu.el
CommitLineData
0a688fd0
RS
1;;; imenu.el --- Framework for mode-specific buffer indexes.
2
fe2908be 3;; Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
0a688fd0
RS
4
5;; Author: Ake Stenhoff <etxaksf@aom.ericsson.se>
6;; Lars Lindberg <lli@sypro.cap.se>
e4874521 7;; Maintainer: FSF
0a688fd0 8;; Created: 8 Feb 1994
f5f727f8 9;; Keywords: tools convenience
b578f267
EN
10
11;; This file is part of GNU Emacs.
12
13;; GNU Emacs is free software; you can redistribute it and/or modify
0a688fd0
RS
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation; either version 2, or (at your option)
16;; any later version.
b578f267
EN
17
18;; GNU Emacs is distributed in the hope that it will be useful,
0a688fd0
RS
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
b578f267 22
0a688fd0 23;; You should have received a copy of the GNU General Public License
b578f267
EN
24;; along with GNU Emacs; see the file COPYING. If not, write to the
25;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26;; Boston, MA 02111-1307, USA.
0a688fd0
RS
27
28;;; Commentary:
b578f267 29
0a688fd0
RS
30;; Purpose of this package:
31;; To present a framework for mode-specific buffer indexes.
32;; A buffer index is an alist of names and buffer positions.
33;; For instance all functions in a C-file and their positions.
34;;
fe2908be
RS
35;; It is documented in the Emacs Lisp manual.
36;;
0a688fd0
RS
37;; How it works:
38
39;; A mode-specific function is called to generate the index. It is
40;; then presented to the user, who can choose from this index.
41;;
42;; The package comes with a set of example functions for how to
43;; utilize this package.
44
2d24227e
RS
45;; There are *examples* for index gathering functions/regular
46;; expressions for C/C++ and Lisp/Emacs Lisp but it is easy to
47;; customize for other modes. A function for jumping to the chosen
48;; index position is also supplied.
0a688fd0 49
fe2908be
RS
50;;; History:
51;; Thanks go to
26d6bb60
RS
52;; [simon] - Simon Leinen simon@lia.di.epfl.ch
53;; [dean] - Dean Andrews ada@unison.com
fe2908be 54;; [alon] - Alon Albert al@mercury.co.il
7804cd27 55;; [greg] - Greg Thompson gregt@porsche.visix.COM
615b306c 56;; [wolfgang] - Wolfgang Bangerth zcg51122@rpool1.rus.uni-stuttgart.de
056ab244 57;; [kai] - Kai Grossjohann grossjoh@linus.informatik.uni-dortmund.de
af447694 58;; [david] - David M. Smith dsmith@stats.adelaide.edu.au
2d24227e
RS
59;; [christian] - Christian Egli Christian.Egli@hcsd.hac.com
60;; [karl] - Karl Fogel kfogel@floss.life.uiuc.edu
61
0a688fd0 62;;; Code
b578f267 63
0ee4f8ad 64(eval-when-compile (require 'cl))
0a688fd0
RS
65
66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
67;;;
68;;; Customizable variables
69;;;
70;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2d24227e 71
94114394
RS
72(defgroup imenu nil
73 "Mode-specific buffer indexes."
74 :group 'matching
fe2908be 75 :group 'frames
f5f727f8 76 :group 'convenience
fe2908be 77 :link '(custom-manual "(elisp)Imenu"))
94114394
RS
78
79(defcustom imenu-use-markers t
e7c8378c 80 "*Non-nil means use markers instead of integers for Imenu buffer positions.
fe2908be
RS
81
82Setting this to nil makes Imenu work a little faster but editing the
83buffer will make the generated index positions wrong.
e7c8378c 84
94114394
RS
85This might not yet be honored by all index-building functions."
86 :type 'boolean
87 :group 'imenu)
88
e7c8378c 89
94114394
RS
90(defcustom imenu-max-item-length 60
91 "*If a number, truncate Imenu entries to that length."
fe2908be
RS
92 :type '(choice integer
93 (const :tag "Unlimited"))
94114394 94 :group 'imenu)
e7c8378c 95
9df23821 96(defcustom imenu-auto-rescan nil
94114394
RS
97 "*Non-nil means Imenu should always rescan the buffers."
98 :type 'boolean
99 :group 'imenu)
2d24227e 100
fe2908be
RS
101(defcustom imenu-auto-rescan-maxout 60000
102 "*Imenu auto-rescan is disabled in buffers larger than this size (in bytes).
94114394
RS
103This variable is buffer-local."
104 :type 'integer
105 :group 'imenu)
0a688fd0 106
94114394 107(defcustom imenu-always-use-completion-buffer-p nil
0a688fd0
RS
108 "*Set this to non-nil for displaying the index in a completion buffer.
109
e7c8378c
RS
110`never' means never automatically display a listing of any kind.
111A value of nil (the default) means display the index as a mouse menu
112if the mouse was used to invoke `imenu'.
94114394
RS
113Another non-nil value means always display the index in a completion buffer."
114 :type '(choice (const :tag "On Mouse" nil)
115 (const :tag "Never" never)
8a3e08a6 116 (other :tag "Always" t))
94114394 117 :group 'imenu)
0a688fd0 118
94114394 119(defcustom imenu-sort-function nil
0a688fd0
RS
120 "*The function to use for sorting the index mouse-menu.
121
122Affects only the mouse index menu.
123
124Set this to nil if you don't want any sorting (faster).
125The items in the menu are then presented in the order they were found
126in the buffer.
127
0ee4f8ad 128Set it to `imenu--sort-by-name' if you want alphabetic sorting.
0a688fd0
RS
129
130The function should take two arguments and return T if the first
131element should come before the second. The arguments are cons cells;
94114394 132\(NAME . POSITION). Look at `imenu--sort-by-name' for an example."
fe2908be
RS
133 :type '(choice (const :tag "No sorting" nil)
134 (const :tag "Sort by name" 'imenu--sort-by-name)
135 (function :tag "Another function"))
94114394 136 :group 'imenu)
0a688fd0 137
94114394
RS
138(defcustom imenu-max-items 25
139 "*Maximum number of elements in a mouse menu for Imenu."
140 :type 'integer
141 :group 'imenu)
0a688fd0 142
94114394 143(defcustom imenu-scanning-message "Scanning buffer for index (%3d%%)"
0a688fd0 144 "*Progress message during the index scanning of the buffer.
2892dc82 145If non-nil, user gets a message during the scanning of the buffer.
0a688fd0
RS
146
147Relevant only if the mode-specific function that creates the buffer
fe2908be
RS
148index use `imenu-progress-message', and not useful if that is fast, in
149which case you might as well set this to nil."
150 :type '(choice string
151 (const :tag "None" nil))
94114394 152 :group 'imenu)
0a688fd0 153
a742f6cc 154(defcustom imenu-space-replacement "."
0a688fd0 155 "*The replacement string for spaces in index names.
a742f6cc 156Used when presenting the index in a completion buffer to make the
94114394
RS
157names work as tokens."
158 :type 'string
159 :group 'imenu)
0a688fd0 160
94114394 161(defcustom imenu-level-separator ":"
0a688fd0
RS
162 "*The separator between index names of different levels.
163Used for making mouse-menu titles and for flattening nested indexes
94114394
RS
164with name concatenation."
165 :type 'string
166 :group 'imenu)
0a688fd0 167
2d24227e 168;;;###autoload
615b306c 169(defvar imenu-generic-expression nil
2d24227e
RS
170 "The regex pattern to use for creating a buffer index.
171
01e980fb 172If non-nil this pattern is passed to `imenu--generic-function'
2d24227e
RS
173to create a buffer index.
174
215b077e
RS
175The value should be an alist with elements that look like this:
176 (MENU-TITLE REGEXP INDEX)
177or like this:
178 (MENU-TITLE REGEXP INDEX FUNCTION ARGUMENTS...)
179with zero or more ARGUMENTS. The former format creates a simple element in
180the index alist when it matches; the latter creates a special element
35c8b898 181of the form (NAME FUNCTION POSITION-MARKER ARGUMENTS...)
215b077e 182with FUNCTION and ARGUMENTS beiong copied from `imenu-generic-expression'.
2d24227e
RS
183
184MENU-TITLE is a string used as the title for the submenu or nil if the
185entries are not nested.
186
187REGEXP is a regexp that should match a construct in the buffer that is
6c1bf12b
RS
188to be displayed in the menu; i.e., function or variable definitions,
189etc. It contains a substring which is the name to appear in the
190menu. See the info section on Regexps for more information.
2d24227e
RS
191
192INDEX points to the substring in REGEXP that contains the name (of the
193function, variable or type) that is to appear in the menu.
615b306c 194
73f48953
DL
195The variable is buffer-local.
196
197The variable `imenu-case-fold-search' determines whether or not the
fe2908be
RS
198regexp matches are case sensitive. and `imenu-syntax-alist' can be
199used to alter the syntax table for the search.
200
201For example, see the value of `lisp-imenu-generic-expression' used by
202`lisp-mode' and `emacs-lisp-mode' with `imenu-syntax-alist' set
203locally to give the characters which normally have \"punctuation\"
204syntax \"word\" syntax during matching.")
2d24227e 205
af5eb153 206;;;###autoload
6c1bf12b 207(make-variable-buffer-local 'imenu-generic-expression)
615b306c 208
0a688fd0
RS
209;;;; Hooks
210
211(defvar imenu-create-index-function 'imenu-default-create-index-function
212 "The function to use for creating a buffer index.
213
214It should be a function that takes no arguments and returns an index
215b077e
RS
215of the current buffer as an alist.
216
217Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION).
35c8b898 218Special elements look like (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...).
215b077e
RS
219A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
220The function `imenu--subalist-p' tests an element and returns t
fe2908be 221if it is a sub-alist.
0a688fd0 222
0ee4f8ad 223This function is called within a `save-excursion'.
0a688fd0
RS
224
225The variable is buffer-local.")
226(make-variable-buffer-local 'imenu-create-index-function)
227
68e01f5a 228(defvar imenu-prev-index-position-function 'beginning-of-defun
0a688fd0
RS
229 "Function for finding the next index position.
230
0ee4f8ad
RS
231If `imenu-create-index-function' is set to
232`imenu-default-create-index-function', then you must set this variable
0a688fd0
RS
233to a function that will find the next index, looking backwards in the
234file.
235
236The function should leave point at the place to be connected to the
35c8b898
RS
237index and it should return nil when it doesn't find another index.
238
239This variable is local in all buffers.")
240
68e01f5a 241(make-variable-buffer-local 'imenu-prev-index-position-function)
0a688fd0 242
68e01f5a 243(defvar imenu-extract-index-name-function nil
fe2908be 244 "Function for extracting the index item name, given a position.
35c8b898
RS
245
246This function is called after `imenu-prev-index-position-function'
247finds a position for an index item, with point at that position.
248It should return the name for that index item.
249
250This variable is local in all buffers.")
0a688fd0 251
68e01f5a 252(make-variable-buffer-local 'imenu-extract-index-name-function)
0a688fd0 253
37954a9a
RS
254(defvar imenu-default-goto-function 'imenu-default-goto-function
255 "The default function called when selecting an Imenu item.
256The function in this variable is called when selecting a normal index-item.")
257(make-variable-buffer-local 'imenu-default-goto-function)
258
259
215b077e
RS
260(defun imenu--subalist-p (item)
261 (and (consp (cdr item)) (listp (cadr item))
fe2908be 262 (not (eq (car (cadr item)) 'lambda))))
215b077e 263
fe2908be
RS
264;; Macro to display a progress message.
265;; RELPOS is the relative position to display.
266;; If RELPOS is nil, then the relative position in the buffer
267;; is calculated.
268;; PREVPOS is the variable in which we store the last position displayed.
615b306c 269(defmacro imenu-progress-message (prevpos &optional relpos reverse)
fe2908be
RS
270 `(and
271 imenu-scanning-message
272 (let ((pos ,(if relpos
273 relpos
274 `(imenu--relative-position ,reverse))))
275 (if ,(if relpos t
276 `(> pos (+ 5 ,prevpos)))
277 (progn
278 (message imenu-scanning-message pos)
279 (setq ,prevpos pos))))))
615b306c
KH
280
281
282;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
283;;;;
284;;;; Some examples of functions utilizing the framework of this
285;;;; package.
286;;;;
287;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
288
e064a4f9 289;; Return the current/previous sexp and the location of the sexp (its
615b306c
KH
290;; beginning) without moving the point.
291(defun imenu-example--name-and-position ()
292 (save-excursion
293 (forward-sexp -1)
e7c8378c
RS
294 ;; [ydi] modified for imenu-use-markers
295 (let ((beg (if imenu-use-markers (point-marker) (point)))
296 (end (progn (forward-sexp) (point))))
615b306c 297 (cons (buffer-substring beg end)
e7c8378c 298 beg))))
615b306c
KH
299
300;;;
301;;; Lisp
fe2908be 302;;;
615b306c
KH
303
304(defun imenu-example--lisp-extract-index-name ()
305 ;; Example of a candidate for `imenu-extract-index-name-function'.
306 ;; This will generate a flat index of definitions in a lisp file.
307 (save-match-data
308 (and (looking-at "(def")
309 (condition-case nil
310 (progn
311 (down-list 1)
312 (forward-sexp 2)
313 (let ((beg (point))
314 (end (progn (forward-sexp -1) (point))))
315 (buffer-substring beg end)))
316 (error nil)))))
317
318(defun imenu-example--create-lisp-index ()
319 ;; Example of a candidate for `imenu-create-index-function'.
320 ;; It will generate a nested index of definitions.
321 (let ((index-alist '())
322 (index-var-alist '())
323 (index-type-alist '())
324 (index-unknown-alist '())
325 prev-pos)
326 (goto-char (point-max))
327 (imenu-progress-message prev-pos 0)
328 ;; Search for the function
329 (while (beginning-of-defun)
330 (imenu-progress-message prev-pos nil t)
fe2908be
RS
331 (save-match-data
332 (and (looking-at "(def")
333 (save-excursion
615b306c 334 (down-list 1)
fe2908be 335 (cond
615b306c 336 ((looking-at "def\\(var\\|const\\)")
fe2908be
RS
337 (forward-sexp 2)
338 (push (imenu-example--name-and-position)
339 index-var-alist))
615b306c 340 ((looking-at "def\\(un\\|subst\\|macro\\|advice\\)")
fe2908be
RS
341 (forward-sexp 2)
342 (push (imenu-example--name-and-position)
343 index-alist))
615b306c 344 ((looking-at "def\\(type\\|struct\\|class\\|ine-condition\\)")
fe2908be 345 (forward-sexp 2)
615b306c 346 (if (= (char-after (1- (point))) ?\))
fe2908be 347 (progn
615b306c 348 (forward-sexp -1)
fe2908be 349 (down-list 1)
615b306c 350 (forward-sexp 1)))
fe2908be
RS
351 (push (imenu-example--name-and-position)
352 index-type-alist))
353 (t
354 (forward-sexp 2)
355 (push (imenu-example--name-and-position)
615b306c
KH
356 index-unknown-alist)))))))
357 (imenu-progress-message prev-pos 100)
358 (and index-var-alist
0c20ee61 359 (push (cons "Variables" index-var-alist)
615b306c
KH
360 index-alist))
361 (and index-type-alist
0c20ee61 362 (push (cons "Types" index-type-alist)
615b306c
KH
363 index-alist))
364 (and index-unknown-alist
0c20ee61 365 (push (cons "Syntax-unknown" index-unknown-alist)
615b306c
KH
366 index-alist))
367 index-alist))
368
615b306c
KH
369;; Regular expression to find C functions
370(defvar imenu-example--function-name-regexp-c
fe2908be 371 (concat
615b306c
KH
372 "^[a-zA-Z0-9]+[ \t]?" ; type specs; there can be no
373 "\\([a-zA-Z0-9_*]+[ \t]+\\)?" ; more than 3 tokens, right?
374 "\\([a-zA-Z0-9_*]+[ \t]+\\)?"
375 "\\([*&]+[ \t]*\\)?" ; pointer
376 "\\([a-zA-Z0-9_*]+\\)[ \t]*(" ; name
377 ))
378
379(defun imenu-example--create-c-index (&optional regexp)
380 (let ((index-alist '())
381 prev-pos char)
382 (goto-char (point-min))
383 (imenu-progress-message prev-pos 0)
384 ;; Search for the function
385 (save-match-data
386 (while (re-search-forward
387 (or regexp imenu-example--function-name-regexp-c)
388 nil t)
389 (imenu-progress-message prev-pos)
390 (backward-up-list 1)
391 (save-excursion
392 (goto-char (scan-sexps (point) 1))
393 (setq char (following-char)))
394 ;; Skip this function name if it is a prototype declaration.
395 (if (not (eq char ?\;))
396 (push (imenu-example--name-and-position) index-alist))))
397 (imenu-progress-message prev-pos 100)
398 (nreverse index-alist)))
399
2d24227e 400
0a688fd0
RS
401;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
402;;;
403;;; Internal variables
404;;;
405;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
406
407;; The item to use in the index for rescanning the buffer.
408(defconst imenu--rescan-item '("*Rescan*" . -99))
409
410;; The latest buffer index.
411;; Buffer local.
35c8b898
RS
412(defvar imenu--index-alist nil
413 "The buffer index computed for this buffer in Imenu.
414Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION).
415Special elements look like (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...).
416A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
417
418This variable is local in all buffers, once set.")
419
0a688fd0
RS
420(make-variable-buffer-local 'imenu--index-alist)
421
0a8e8bc6
KH
422;; The latest buffer index used to update the menu bar menu.
423(defvar imenu--last-menubar-index-alist nil)
424(make-variable-buffer-local 'imenu--last-menubar-index-alist)
425
0a688fd0 426;; History list for 'jump-to-function-in-buffer'.
6c1bf12b 427;; Making this buffer local caused it not to work!
0a688fd0 428(defvar imenu--history-list nil)
0a688fd0
RS
429
430;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
431;;;
432;;; Internal support functions
433;;;
434;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
435
436;;;
437;;; Sort function
438;;; Sorts the items depending on their index name.
439;;; An item look like (NAME . POSITION).
440;;;
441(defun imenu--sort-by-name (item1 item2)
442 (string-lessp (car item1) (car item2)))
443
444(defun imenu--relative-position (&optional reverse)
445 ;; Support function to calculate relative position in buffer
446 ;; Beginning of buffer is 0 and end of buffer is 100
447 ;; If REVERSE is non-nil then the beginning is 100 and the end is 0.
448 (let ((pos (point))
449 (total (buffer-size)))
450 (and reverse (setq pos (- total pos)))
451 (if (> total 50000)
452 ;; Avoid overflow from multiplying by 100!
453 (/ (1- pos) (max (/ total 100) 1))
454 (/ (* 100 (1- pos)) (max total 1)))))
455
0a688fd0
RS
456;; Split LIST into sublists of max length N.
457;; Example (imenu--split '(1 2 3 4 5 6 7 8) 3)-> '((1 2 3) (4 5 6) (7 8))
458(defun imenu--split (list n)
459 (let ((remain list)
460 (result '())
461 (sublist '())
462 (i 0))
463 (while remain
464 (push (pop remain) sublist)
465 (incf i)
466 (and (= i n)
467 ;; We have finished a sublist
468 (progn (push (nreverse sublist) result)
469 (setq i 0)
470 (setq sublist '()))))
471 ;; There might be a sublist (if the length of LIST mod n is != 0)
472 ;; that has to be added to the result list.
473 (and sublist
474 (push (nreverse sublist) result))
475 (nreverse result)))
476
0c20ee61
RS
477;;; Split the alist MENULIST into a nested alist, if it is long enough.
478;;; In any case, add TITLE to the front of the alist.
0a688fd0 479(defun imenu--split-menu (menulist title)
7ebea144
RS
480 (let (keep-at-top tail)
481 (if (memq imenu--rescan-item menulist)
482 (setq keep-at-top (cons imenu--rescan-item nil)
483 menulist (delq imenu--rescan-item menulist)))
484 (setq tail menulist)
485 (while tail
486 (if (imenu--subalist-p (car tail))
487 (setq keep-at-top (cons (car tail) keep-at-top)
488 menulist (delq (car tail) menulist)))
489 (setq tail (cdr tail)))
490 (if imenu-sort-function
491 (setq menulist
492 (sort
493 (let ((res nil)
494 (oldlist menulist))
495 ;; Copy list method from the cl package `copy-list'
496 (while (consp oldlist) (push (pop oldlist) res))
fea79780
DL
497 (if res ; in case, e.g. no functions defined
498 (prog1 (nreverse res) (setcdr res oldlist))))
7ebea144
RS
499 imenu-sort-function)))
500 (if (> (length menulist) imenu-max-items)
501 (let ((count 0))
502 (setq menulist
503 (mapcar
504 (function
505 (lambda (menu)
506 (cons (format "From: %s" (caar menu)) menu)))
507 (imenu--split menulist imenu-max-items)))))
508 (cons title
509 (nconc (nreverse keep-at-top) menulist))))
0c20ee61
RS
510
511;;; Split up each long alist that are nested within ALIST
512;;; into nested alists.
513(defun imenu--split-submenus (alist)
fe2908be
RS
514 (mapcar (function
515 (lambda (elt)
516 (if (and (consp elt)
517 (stringp (car elt))
518 (listp (cdr elt)))
519 (imenu--split-menu (cdr elt) (car elt))
520 elt)))
0c20ee61 521 alist))
0a688fd0 522
e7c8378c
RS
523;;; Truncate all strings in MENULIST to imenu-max-item-length
524(defun imenu--truncate-items (menulist)
525 (mapcar (function
526 (lambda (item)
527 (cond
528 ((consp (cdr item))
529 (imenu--truncate-items (cdr item)))
530 (t
531 ;; truncate if necessary
532 (if (and (numberp imenu-max-item-length)
533 (> (length (car item)) imenu-max-item-length))
534 (setcar item (substring (car item) 0 imenu-max-item-length)))))))
535 menulist))
536
537
0a8e8bc6 538(defun imenu--make-index-alist (&optional noerror)
7e563e04
RS
539 "Create an index-alist for the definitions in the current buffer.
540
fe2908be
RS
541Report an error if the list is empty unless NOERROR is supplied and
542non-nil.
543
7e563e04
RS
544Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION).
545Special elements look like (INDEX-NAME FUNCTION ARGUMENTS...).
546A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
547The function `imenu--subalist-p' tests an element and returns t
fe2908be 548if it is a sub-alist.
7e563e04
RS
549
550There is one simple element with negative POSITION; that's intended
551as a way for the user to ask to recalculate the buffer's index alist."
2d24227e
RS
552 (or (and imenu--index-alist
553 (or (not imenu-auto-rescan)
554 (and imenu-auto-rescan
555 (> (buffer-size) imenu-auto-rescan-maxout))))
e7c8378c
RS
556 ;; Get the index; truncate if necessary
557 (progn
558 (setq imenu--index-alist
559 (save-excursion
560 (save-restriction
561 (widen)
562 (funcall imenu-create-index-function))))
563 (imenu--truncate-items imenu--index-alist)))
0a8e8bc6 564 (or imenu--index-alist noerror
6c1bf12b 565 (error "No items suitable for an index found in this buffer"))
0a8e8bc6
KH
566 (or imenu--index-alist
567 (setq imenu--index-alist (list nil)))
0a688fd0
RS
568 ;; Add a rescan option to the index.
569 (cons imenu--rescan-item imenu--index-alist))
79e098ca 570
5d3b0f18
RS
571;;; Find all markers in alist and makes
572;;; them point nowhere.
79e098ca
RS
573;;; The top-level call uses nil as the argument;
574;;; non-nil arguments are in recursivecalls.
575(defvar imenu--cleanup-seen)
576
5d3b0f18 577(defun imenu--cleanup (&optional alist)
fe2908be 578 ;; If alist is provided use that list.
79e098ca
RS
579 ;; If not, empty the table of lists already seen
580 ;; and use imenu--index-alist.
581 (if alist
582 (setq imenu--cleanup-seen (cons alist imenu--cleanup-seen))
583 (setq alist imenu--index-alist imenu--cleanup-seen (list alist)))
584
4818d210 585 (and alist
7804cd27 586 (mapcar
5d3b0f18
RS
587 (function
588 (lambda (item)
589 (cond
590 ((markerp (cdr item))
591 (set-marker (cdr item) nil))
79e098ca
RS
592 ;; Don't process one alist twice.
593 ((memq (cdr item) imenu--cleanup-seen))
215b077e 594 ((imenu--subalist-p item)
5d3b0f18 595 (imenu--cleanup (cdr item))))))
4818d210 596 alist)
615b306c
KH
597 t))
598
0a8e8bc6 599(defun imenu--create-keymap-2 (alist counter &optional commands)
2d24227e
RS
600 (let ((map nil))
601 (mapcar
602 (function
603 (lambda (item)
604 (cond
215b077e 605 ((imenu--subalist-p item)
fc0ac20d
KH
606 (append (list (setq counter (1+ counter))
607 (car item) 'keymap (car item))
0a8e8bc6 608 (imenu--create-keymap-2 (cdr item) (+ counter 10) commands)))
2d24227e 609 (t
fc0ac20d
KH
610 (let ((end (if commands `(lambda () (interactive)
611 (imenu--menubar-select ',item))
32c1a22e 612 (cons '(nil) item))))
2d24227e 613 (cons (car item)
fe2908be 614 (cons (car item) end)))))))
2d24227e
RS
615 alist)))
616
0a8e8bc6
KH
617;; If COMMANDS is non-nil, make a real keymap
618;; with a real command used as the definition.
619;; If it is nil, make something suitable for x-popup-menu.
620(defun imenu--create-keymap-1 (title alist &optional commands)
621 (append (list 'keymap title) (imenu--create-keymap-2 alist 0 commands)))
2d24227e 622
2d24227e
RS
623(defun imenu--in-alist (str alist)
624 "Check whether the string STR is contained in multi-level ALIST."
625 (let (elt head tail res)
626 (setq res nil)
627 (while alist
fe2908be 628 (setq elt (car alist)
2d24227e 629 tail (cdr elt)
fe2908be
RS
630 alist (cdr alist)
631 head (car elt))
8396299d
RS
632 ;; A nested ALIST element looks like
633 ;; (INDEX-NAME (INDEX-NAME . INDEX-POSITION) ...)
634 ;; while a bottom-level element looks like
635 ;; (INDEX-NAME . INDEX-POSITION)
636 ;; We are only interested in the bottom-level elements, so we need to
637 ;; recurse if TAIL is a list.
638 (cond ((listp tail)
639 (if (setq res (imenu--in-alist str tail))
640 (setq alist nil)))
641 ((string= str head)
642 (setq alist nil res elt))))
2d24227e
RS
643 res))
644
fea79780
DL
645(defvar imenu-syntax-alist nil
646 "Alist of syntax table modifiers to use while executing `imenu--generic-function'.
647
648The car of the assocs may be either a character or a string and the
649cdr is a syntax description appropriate fo `modify-syntax-entry'. For
650a string, all the characters in the string get the specified syntax.
651
652This is typically used to give word syntax to characters which
90806abc 653normally have symbol syntax to simplify `imenu-expression'
fea79780
DL
654and speed-up matching.")
655(make-variable-buffer-local 'imenu-syntax-alist)
656
0a688fd0
RS
657(defun imenu-default-create-index-function ()
658 "*Wrapper for index searching functions.
659
660Moves point to end of buffer and then repeatedly calls
68e01f5a 661`imenu-prev-index-position-function' and `imenu-extract-index-name-function'.
0a688fd0 662Their results are gathered into an index alist."
3e062f78
RS
663 ;; These should really be done by setting imenu-create-index-function
664 ;; in these major modes. But save that change for later.
e536ef56
KH
665 (cond ((and imenu-prev-index-position-function
666 imenu-extract-index-name-function)
3e062f78 667 (let ((index-alist '())
615b306c 668 prev-pos name)
3e062f78 669 (goto-char (point-max))
7dea4e70 670 (imenu-progress-message prev-pos 0 t)
3e062f78 671 ;; Search for the function
fe2908be 672 (while (funcall imenu-prev-index-position-function)
7dea4e70 673 (imenu-progress-message prev-pos nil t)
3e062f78
RS
674 (save-excursion
675 (setq name (funcall imenu-extract-index-name-function)))
676 (and (stringp name)
e7c8378c
RS
677 ;; [ydi] updated for imenu-use-markers
678 (push (cons name (if imenu-use-markers (point-marker) (point)))
679 index-alist)))
7dea4e70 680 (imenu-progress-message prev-pos 100 t)
615b306c
KH
681 index-alist))
682 ;; Use generic expression if possible.
683 ((and imenu-generic-expression)
fe2908be 684 (imenu--generic-function imenu-generic-expression))
615b306c 685 (t
e7c8378c 686 (error "This buffer cannot use `imenu-default-create-index-function'"))))
0a688fd0
RS
687
688(defun imenu--replace-spaces (name replacement)
689 ;; Replace all spaces in NAME with REPLACEMENT.
690 ;; That second argument should be a string.
691 (mapconcat
692 (function
693 (lambda (ch)
694 (if (char-equal ch ?\ )
695 replacement
696 (char-to-string ch))))
697 name
698 ""))
699
fe2908be
RS
700;; Not used and would require cl at run time
701;;; (defun imenu--flatten-index-alist (index-alist &optional concat-names prefix)
702;;; ;; Takes a nested INDEX-ALIST and returns a flat index alist.
703;;; ;; If optional CONCAT-NAMES is non-nil, then a nested index has its
704;;; ;; name and a space concatenated to the names of the children.
705;;; ;; Third argument PREFIX is for internal use only.
706;;; (mapcan
707;;; (lambda (item)
708;;; (let* ((name (car item))
709;;; (pos (cdr item))
710;;; (new-prefix (and concat-names
711;;; (if prefix
712;;; (concat prefix imenu-level-separator name)
713;;; name))))
714;;; (cond
715;;; ((or (markerp pos) (numberp pos))
716;;; (list (cons new-prefix pos)))
717;;; (t
718;;; (imenu--flatten-index-alist pos new-prefix)))))
719;;; index-alist))
0a688fd0 720
615b306c
KH
721;;;
722;;; Generic index gathering function.
723;;;
2d24227e 724
73f48953
DL
725(defvar imenu-case-fold-search t
726 "Defines whether `imenu--generic-function' should fold case when matching.
727
728This buffer-local variable should be set (only) by initialization code
729for modes which use `imenu--generic-function'. If it is not set, that
730function will use the current value of `case-fold-search' to match
731patterns.")
fe2908be 732;;;###autoload
73f48953
DL
733(make-variable-buffer-local 'imenu-case-fold-search)
734
fe2908be
RS
735;; Originally "Built on some ideas that Erik Naggum <erik@naggum.no>
736;; once posted to comp.emacs" but since substantially re-written.
2d24227e 737(defun imenu--generic-function (patterns)
2d24227e
RS
738 "Return an index of the current buffer as an alist.
739
fe2908be
RS
740PATTERNS is an alist with elements that look like this:
741 (MENU-TITLE REGEXP INDEX).
2d24227e
RS
742
743MENU-TITLE is a string used as the title for the submenu or nil if the
744entries are not nested.
745
746REGEXP is a regexp that should match a construct in the buffer that is
6c1bf12b
RS
747to be displayed in the menu; i.e., function or variable definitions,
748etc. It contains a substring which is the name to appear in the
749menu. See the info section on Regexps for more information.
2d24227e
RS
750
751INDEX points to the substring in REGEXP that contains the name (of the
752function, variable or type) that is to appear in the menu.
753
fe2908be 754See `lisp-imenu-generic-expression' for an example of PATTERNS.
2d24227e 755
6c1bf12b
RS
756Returns an index of the current buffer as an alist. The elements in
757the alist look like: (INDEX-NAME . INDEX-POSITION). They may also be
2d24227e 758nested index lists like (INDEX-NAME . INDEX-ALIST) depending on
fe2908be 759PATTERNS."
2d24227e
RS
760
761 (let ((index-alist (list 'dummy))
fe2908be 762 prev-pos beg
fea79780
DL
763 (case-fold-search imenu-case-fold-search)
764 (old-table (syntax-table))
765 (table (copy-syntax-table (syntax-table)))
766 (slist imenu-syntax-alist))
767 ;; Modify the syntax table used while matching regexps.
768 (while slist
fe2908be
RS
769 ;; The character(s) to modify may be a single char or a string.
770 (if (numberp (caar slist))
771 (modify-syntax-entry (caar slist) (cdar slist) table)
772 (mapcar (function
773 (lambda (c)
774 (modify-syntax-entry c (cdar slist) table)))
775 (caar slist)))
776 (setq slist (cdr slist)))
615b306c
KH
777 (goto-char (point-max))
778 (imenu-progress-message prev-pos 0 t)
fe2908be
RS
779 (unwind-protect ; for syntax table
780 (save-match-data
781 (set-syntax-table table)
782 ;; map over the elements of imenu-generic-expression
783 ;; (typically functions, variables ...)
784 (mapcar
785 (function
786 (lambda (pat)
787 (let ((menu-title (car pat))
788 (regexp (nth 1 pat))
789 (index (nth 2 pat))
790 (function (nth 3 pat))
791 (rest (nthcdr 4 pat)))
792 ;; Go backwards for convenience of adding items in order.
793 (goto-char (point-max))
794 (while (re-search-backward regexp nil t)
795 (imenu-progress-message prev-pos nil t)
796 (setq beg (match-beginning index))
797 ;; Add this sort of submenu only when we've found an
798 ;; item for it, avoiding empty, duff menus.
799 (unless (assoc menu-title index-alist)
800 (push (list menu-title) index-alist))
801 (if imenu-use-markers
802 (setq beg (set-marker (make-marker) beg)))
803 (let ((item
804 (if function
805 (nconc (list (match-string-no-properties index)
806 beg function)
807 rest)
808 (cons (match-string-no-properties index)
809 beg)))
810 (menu (cdr (assoc menu-title index-alist))))
811 ;; avoid duplicates from, e.g. cc-mode patterns
812 (unless (member item menu)
813 ;; insert the item after the (sub-)menu title
814 (setcdr (assoc menu-title index-alist)
815 (cons item menu))))))))
816 patterns)
817 (set-syntax-table old-table)))
0c20ee61
RS
818 (imenu-progress-message prev-pos 100 t)
819 (let ((main-element (assq nil index-alist)))
7ebea144
RS
820 (nconc (delq main-element (delq 'dummy index-alist))
821 (cdr main-element)))))
615b306c 822
0a688fd0
RS
823;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
824;;;
825;;; The main functions for this package!
826;;;
827;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
828
829(defun imenu--completion-buffer (index-alist &optional prompt)
830 "Let the user select from INDEX-ALIST in a completion buffer with PROMPT.
831
832Returns t for rescan and otherwise a position number."
833 ;; Create a list for this buffer only when needed.
fe2908be
RS
834 (let ((name (thing-at-point 'symbol))
835 choice
836 (prepared-index-alist
837 (mapcar
838 (function
839 (lambda (item)
840 (cons (imenu--replace-spaces (car item) imenu-space-replacement)
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: ")))
af447694 847 (if (eq imenu-always-use-completion-buffer-p 'never)
fe2908be 848 (setq name (completing-read prompt
af447694 849 prepared-index-alist
fe2908be 850 nil t nil 'imenu--history-list name))
af447694
RS
851 (save-window-excursion
852 ;; Display the completion buffer
853 (with-output-to-temp-buffer "*Completions*"
854 (display-completion-list
855 (all-completions "" prepared-index-alist )))
856 (let ((minibuffer-setup-hook
fe2908be
RS
857 (function
858 (lambda ()
859 (let ((buffer (current-buffer)))
860 (save-excursion
861 (set-buffer "*Completions*")
862 (setq completion-reference-buffer buffer)))))))
af447694 863 ;; Make a completion question
fe2908be 864 (setq name (completing-read prompt
af447694 865 prepared-index-alist
fe2908be 866 nil t nil 'imenu--history-list name)))))
3e062f78
RS
867 (cond ((not (stringp name))
868 nil)
869 ((string= name (car imenu--rescan-item))
870 t)
871 (t
872 (setq choice (assoc name prepared-index-alist))
215b077e 873 (if (imenu--subalist-p choice)
3e062f78
RS
874 (imenu--completion-buffer (cdr choice) prompt)
875 choice)))))
68e01f5a 876
0a688fd0
RS
877(defun imenu--mouse-menu (index-alist event &optional title)
878 "Let the user select from a buffer index from a mouse menu.
879
880INDEX-ALIST is the buffer index and EVENT is a mouse event.
881
32c1a22e 882Returns t for rescan and otherwise an element or subelement of INDEX-ALIST."
0c20ee61 883 (setq index-alist (imenu--split-submenus index-alist))
32c1a22e 884 (let* ((menu (imenu--split-menu index-alist
fe2908be
RS
885 (or title (buffer-name))))
886 position)
887 (setq menu (imenu--create-keymap-1 (car menu)
fdbf0fc7
RS
888 (if (< 1 (length (cdr menu)))
889 (cdr menu)
32c1a22e 890 (cdr (car (cdr menu))))))
0a688fd0 891 (setq position (x-popup-menu event menu))
32c1a22e
RS
892 (cond ((eq position nil)
893 position)
894 ;; If one call to x-popup-menu handled the nested menus,
895 ;; find the result by looking down the menus here.
896 ((and (listp position)
27f94c9b
RS
897 (numberp (car position))
898 (stringp (nth (1- (length position)) position)))
32c1a22e
RS
899 (let ((final menu))
900 (while position
901 (setq final (assoc (car position) final))
902 (setq position (cdr position)))
b8c44b29 903 (or (string= (car final) (car imenu--rescan-item))
fe2908be 904 (nthcdr 3 final))))
32c1a22e
RS
905 ;; If x-popup-menu went just one level and found a leaf item,
906 ;; return the INDEX-ALIST element for that.
907 ((and (consp position)
908 (stringp (car position))
27f94c9b 909 (null (cdr position)))
32c1a22e
RS
910 (or (string= (car position) (car imenu--rescan-item))
911 (assq (car position) index-alist)))
912 ;; If x-popup-menu went just one level
913 ;; and found a non-leaf item (a submenu),
914 ;; recurse to handle the rest.
27f94c9b
RS
915 ((listp position)
916 (imenu--mouse-menu position event
917 (if title
918 (concat title imenu-level-separator
919 (car (rassq position index-alist)))
32c1a22e 920 (car (rassq position index-alist))))))))
0a688fd0 921
26d6bb60 922(defun imenu-choose-buffer-index (&optional prompt alist)
0a688fd0
RS
923 "Let the user select from a buffer index and return the chosen index.
924
925If the user originally activated this function with the mouse, a mouse
0a688fd0
RS
926menu is used. Otherwise a completion buffer is used and the user is
927prompted with PROMPT.
928
26d6bb60
RS
929If you call this function with index alist ALIST, then it lets the user
930select from ALIST.
931
0ee4f8ad 932With no index alist ALIST, it calls `imenu--make-index-alist' to
26d6bb60
RS
933create the index alist.
934
0ee4f8ad 935If `imenu-always-use-completion-buffer-p' is non-nil, then the
0a688fd0
RS
936completion buffer is always used, no matter if the mouse was used or
937not.
938
7e563e04 939The returned value is of the form (INDEX-NAME . INDEX-POSITION)."
0a688fd0 940 (let (index-alist
7dea4e70 941 (mouse-triggered (listp last-nonmenu-event))
0a688fd0
RS
942 (result t) )
943 ;; If selected by mouse, see to that the window where the mouse is
944 ;; really is selected.
945 (and mouse-triggered
4cde72b4 946 (not (equal last-nonmenu-event '(menu-bar)))
7dea4e70 947 (let ((window (posn-window (event-start last-nonmenu-event))))
4a840d8b 948 (or (framep window) (null window) (select-window window))))
0a688fd0
RS
949 ;; Create a list for this buffer only when needed.
950 (while (eq result t)
26d6bb60 951 (setq index-alist (if alist alist (imenu--make-index-alist)))
0a688fd0
RS
952 (setq result
953 (if (and mouse-triggered
954 (not imenu-always-use-completion-buffer-p))
7dea4e70 955 (imenu--mouse-menu index-alist last-nonmenu-event)
0a688fd0
RS
956 (imenu--completion-buffer index-alist prompt)))
957 (and (eq result t)
5d3b0f18 958 (imenu--cleanup)
0a688fd0
RS
959 (setq imenu--index-alist nil)))
960 result))
961
2d24227e 962;;;###autoload
5d3b0f18 963(defun imenu-add-to-menubar (name)
fe2908be 964 "Add an `imenu' entry to the menu bar for the current buffer.
0a8e8bc6 965NAME is a string used to name the menu bar item.
d1757026 966See the command `imenu' for more information."
0a8e8bc6 967 (interactive "sImenu menu item name: ")
e536ef56
KH
968 (if (or (and imenu-prev-index-position-function
969 imenu-extract-index-name-function)
970 imenu-generic-expression
971 (not (eq imenu-create-index-function
972 'imenu-default-create-index-function)))
973 (let ((newmap (make-sparse-keymap))
974 (menu-bar (lookup-key (current-local-map) [menu-bar])))
975 (define-key newmap [menu-bar]
976 (append (make-sparse-keymap) menu-bar))
977 (define-key newmap [menu-bar index]
978 (cons name (nconc (make-sparse-keymap "Imenu")
979 (make-sparse-keymap))))
980 (use-local-map (append newmap (current-local-map)))
981 (add-hook 'menu-bar-update-hook 'imenu-update-menubar))
37954a9a 982 (error "The mode `%s' does not support Imenu" mode-name)))
0a8e8bc6 983
fe2908be
RS
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
6d7a4832
KH
992(defvar imenu-buffer-menubar nil)
993
0a8e8bc6
KH
994(defun imenu-update-menubar ()
995 (and (current-local-map)
996 (keymapp (lookup-key (current-local-map) [menu-bar index]))
997 (let ((index-alist (imenu--make-index-alist t)))
998 ;; Don't bother updating if the index-alist has not changed
999 ;; since the last time we did it.
1000 (or (equal index-alist imenu--last-menubar-index-alist)
1001 (let (menu menu1 old)
1002 (setq imenu--last-menubar-index-alist index-alist)
0c20ee61 1003 (setq index-alist (imenu--split-submenus index-alist))
32c1a22e 1004 (setq menu (imenu--split-menu index-alist
fe2908be 1005 (buffer-name)))
0a8e8bc6 1006 (setq menu1 (imenu--create-keymap-1 (car menu)
fe2908be
RS
1007 (if (< 1 (length (cdr menu)))
1008 (cdr menu)
0a8e8bc6 1009 (cdr (car (cdr menu))))
fe2908be 1010 t))
0a8e8bc6 1011 (setq old (lookup-key (current-local-map) [menu-bar index]))
5d43dca8 1012 (setcdr old (cdr menu1)))))))
0a8e8bc6
KH
1013
1014(defun imenu--menubar-select (item)
1015 "Use Imenu to select the function or variable named in this menu item."
37954a9a 1016 (if (equal item imenu--rescan-item)
e63679b8
RS
1017 (progn
1018 (imenu--cleanup)
1019 (setq imenu--index-alist nil)
1020 (imenu-update-menubar))
1021 (imenu item)))
5d3b0f18 1022
37954a9a 1023(defun imenu-default-goto-function (name position &optional rest)
fe2908be
RS
1024 "Move the point to the given position.
1025
1026NAME is ignored. POSITION is where to move. REST is also ignored.
1027The ignored args just make this function have the same interface as a
1028function placed in a special index-item."
e7c8378c
RS
1029 (if (or (< position (point-min))
1030 (> position (point-max)))
37954a9a
RS
1031 ;; widen if outside narrowing
1032 (widen))
e7c8378c 1033 (goto-char position))
37954a9a 1034
68e01f5a 1035;;;###autoload
6c1bf12b 1036(defun imenu (index-item)
68e01f5a 1037 "Jump to a place in the buffer chosen using a buffer menu or mouse menu.
fe2908be
RS
1038INDEX-ITEM specifies the position. See `imenu-choose-buffer-index'
1039for more information."
01e980fb 1040 (interactive (list (imenu-choose-buffer-index)))
0a8e8bc6
KH
1041 ;; Convert a string to an alist element.
1042 (if (stringp index-item)
1043 (setq index-item (assoc index-item (imenu--make-index-alist))))
6c1bf12b
RS
1044 (and index-item
1045 (progn
1046 (push-mark)
37954a9a 1047 (let* ((is-special-item (listp (cdr index-item)))
fe2908be 1048 (function
37954a9a 1049 (if is-special-item
fe2908be 1050 (nth 2 index-item) imenu-default-goto-function))
37954a9a
RS
1051 (position (if is-special-item
1052 (cadr index-item) (cdr index-item)))
1053 (rest (if is-special-item (cddr index-item))))
1054 (apply function (car index-item) position rest)))))
5d3b0f18 1055
0a688fd0
RS
1056(provide 'imenu)
1057
1058;;; imenu.el ends here