Sync to HEAD
[bpt/emacs.git] / lisp / imenu.el
CommitLineData
55535639 1;;; imenu.el --- framework for mode-specific buffer indexes
0a688fd0 2
dd631e8a 3;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 2003 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
55535639 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
5988bd27
SM
107(defvar imenu-always-use-completion-buffer-p nil)
108(make-obsolete-variable 'imenu-always-use-completion-buffer-p
109 'imenu-use-popup-menu "21.4")
110
111(defcustom imenu-use-popup-menu
112 (if imenu-always-use-completion-buffer-p
113 (not (eq imenu-always-use-completion-buffer-p 'never))
114 'on-mouse)
115 "Use a popup menu rather than a minibuffer prompt.
116If nil, always use a minibuffer prompt.
117If t, always use a popup menu,
118If `on-mouse' use a popup menu when `imenu' was invoked with the mouse."
119 :type '(choice (const :tag "On Mouse" on-mouse)
120 (const :tag "Never" nil)
121 (other :tag "Always" t)))
122
123(defcustom imenu-eager-completion-buffer
124 (not (eq imenu-always-use-completion-buffer-p 'never))
125 "If non-nil, eagerly popup the completion buffer."
126 :type 'boolean)
0a688fd0 127
020e8fdf
PR
128(defcustom imenu-after-jump-hook nil
129 "*Hooks called after jumping to a place in the buffer.
130
131Useful things to use here include `reposition-window', `recenter', and
132\(lambda () (recenter 0)) to show at top of screen."
133 :type 'hook
134 :group 'imenu)
135
31f2a064 136;;;###autoload
94114394 137(defcustom imenu-sort-function nil
0a688fd0
RS
138 "*The function to use for sorting the index mouse-menu.
139
140Affects only the mouse index menu.
141
142Set this to nil if you don't want any sorting (faster).
143The items in the menu are then presented in the order they were found
144in the buffer.
145
0ee4f8ad 146Set it to `imenu--sort-by-name' if you want alphabetic sorting.
0a688fd0 147
c01ee596 148The function should take two arguments and return t if the first
0a688fd0 149element should come before the second. The arguments are cons cells;
94114394 150\(NAME . POSITION). Look at `imenu--sort-by-name' for an example."
fe2908be 151 :type '(choice (const :tag "No sorting" nil)
df90db13 152 (const :tag "Sort by name" imenu--sort-by-name)
fe2908be 153 (function :tag "Another function"))
94114394 154 :group 'imenu)
0a688fd0 155
94114394
RS
156(defcustom imenu-max-items 25
157 "*Maximum number of elements in a mouse menu for Imenu."
158 :type 'integer
159 :group 'imenu)
0a688fd0 160
94114394 161(defcustom imenu-scanning-message "Scanning buffer for index (%3d%%)"
0a688fd0 162 "*Progress message during the index scanning of the buffer.
2892dc82 163If non-nil, user gets a message during the scanning of the buffer.
0a688fd0
RS
164
165Relevant only if the mode-specific function that creates the buffer
fe2908be
RS
166index use `imenu-progress-message', and not useful if that is fast, in
167which case you might as well set this to nil."
168 :type '(choice string
169 (const :tag "None" nil))
94114394 170 :group 'imenu)
0a688fd0 171
a742f6cc 172(defcustom imenu-space-replacement "."
0a688fd0 173 "*The replacement string for spaces in index names.
a742f6cc 174Used when presenting the index in a completion buffer to make the
94114394 175names work as tokens."
5988bd27 176 :type '(choice string (const nil))
94114394 177 :group 'imenu)
0a688fd0 178
94114394 179(defcustom imenu-level-separator ":"
0a688fd0
RS
180 "*The separator between index names of different levels.
181Used for making mouse-menu titles and for flattening nested indexes
94114394
RS
182with name concatenation."
183 :type 'string
184 :group 'imenu)
0a688fd0 185
2d24227e 186;;;###autoload
615b306c 187(defvar imenu-generic-expression nil
2d24227e
RS
188 "The regex pattern to use for creating a buffer index.
189
01e980fb 190If non-nil this pattern is passed to `imenu--generic-function'
2d24227e
RS
191to create a buffer index.
192
215b077e
RS
193The value should be an alist with elements that look like this:
194 (MENU-TITLE REGEXP INDEX)
195or like this:
196 (MENU-TITLE REGEXP INDEX FUNCTION ARGUMENTS...)
197with zero or more ARGUMENTS. The former format creates a simple element in
198the index alist when it matches; the latter creates a special element
70223ca4
SM
199of the form (NAME POSITION-MARKER FUNCTION ARGUMENTS...)
200with FUNCTION and ARGUMENTS copied from `imenu-generic-expression'.
2d24227e
RS
201
202MENU-TITLE is a string used as the title for the submenu or nil if the
203entries are not nested.
204
205REGEXP is a regexp that should match a construct in the buffer that is
6c1bf12b
RS
206to be displayed in the menu; i.e., function or variable definitions,
207etc. It contains a substring which is the name to appear in the
208menu. See the info section on Regexps for more information.
2d24227e
RS
209
210INDEX points to the substring in REGEXP that contains the name (of the
211function, variable or type) that is to appear in the menu.
615b306c 212
73f48953
DL
213The variable is buffer-local.
214
215The variable `imenu-case-fold-search' determines whether or not the
1447c4b1 216regexp matches are case sensitive, and `imenu-syntax-alist' can be
fe2908be
RS
217used to alter the syntax table for the search.
218
0cdb3baa 219For example, see the value of `fortran-imenu-generic-expression' used by
1447c4b1
DL
220`fortran-mode' with `imenu-syntax-alist' set locally to give the
221characters which normally have \"symbol\" syntax \"word\" syntax
222during matching.")
2d24227e 223
af5eb153 224;;;###autoload
6c1bf12b 225(make-variable-buffer-local 'imenu-generic-expression)
615b306c 226
0a688fd0
RS
227;;;; Hooks
228
31f2a064 229;;;###autoload
0a688fd0
RS
230(defvar imenu-create-index-function 'imenu-default-create-index-function
231 "The function to use for creating a buffer index.
232
233It should be a function that takes no arguments and returns an index
215b077e
RS
234of the current buffer as an alist.
235
236Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION).
35c8b898 237Special elements look like (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...).
215b077e
RS
238A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
239The function `imenu--subalist-p' tests an element and returns t
fe2908be 240if it is a sub-alist.
0a688fd0 241
0ee4f8ad 242This function is called within a `save-excursion'.
0a688fd0
RS
243
244The variable is buffer-local.")
31f2a064 245;;;###autoload
0a688fd0
RS
246(make-variable-buffer-local 'imenu-create-index-function)
247
31f2a064 248;;;###autoload
68e01f5a 249(defvar imenu-prev-index-position-function 'beginning-of-defun
0a688fd0
RS
250 "Function for finding the next index position.
251
0ee4f8ad
RS
252If `imenu-create-index-function' is set to
253`imenu-default-create-index-function', then you must set this variable
0a688fd0
RS
254to a function that will find the next index, looking backwards in the
255file.
256
257The function should leave point at the place to be connected to the
35c8b898
RS
258index and it should return nil when it doesn't find another index.
259
260This variable is local in all buffers.")
31f2a064 261;;;###autoload
68e01f5a 262(make-variable-buffer-local 'imenu-prev-index-position-function)
0a688fd0 263
31f2a064 264;;;###autoload
68e01f5a 265(defvar imenu-extract-index-name-function nil
fe2908be 266 "Function for extracting the index item name, given a position.
35c8b898
RS
267
268This function is called after `imenu-prev-index-position-function'
269finds a position for an index item, with point at that position.
270It should return the name for that index item.
271
272This variable is local in all buffers.")
31f2a064 273;;;###autoload
68e01f5a 274(make-variable-buffer-local 'imenu-extract-index-name-function)
0a688fd0 275
020e8fdf
PR
276;;;###autoload
277(defvar imenu-name-lookup-function nil
278 "Function to compare string with index item.
279
280This function will be called with two strings, and should return
281non-nil if they match.
282
283If nil, comparison is done with `string='.
284Set this to some other function for more advanced comparisons,
285such as \"begins with\" or \"name matches and number of
286arguments match\".
287
288This variable is local in all buffers.")
289;;;###autoload
290(make-variable-buffer-local 'imenu-name-lookup-function)
291
31f2a064 292;;;###autoload
37954a9a
RS
293(defvar imenu-default-goto-function 'imenu-default-goto-function
294 "The default function called when selecting an Imenu item.
295The function in this variable is called when selecting a normal index-item.")
31f2a064 296;;;###autoload
37954a9a
RS
297(make-variable-buffer-local 'imenu-default-goto-function)
298
299
215b077e
RS
300(defun imenu--subalist-p (item)
301 (and (consp (cdr item)) (listp (cadr item))
fe2908be 302 (not (eq (car (cadr item)) 'lambda))))
215b077e 303
fe2908be
RS
304;; Macro to display a progress message.
305;; RELPOS is the relative position to display.
306;; If RELPOS is nil, then the relative position in the buffer
307;; is calculated.
308;; PREVPOS is the variable in which we store the last position displayed.
615b306c 309(defmacro imenu-progress-message (prevpos &optional relpos reverse)
fe2908be
RS
310 `(and
311 imenu-scanning-message
312 (let ((pos ,(if relpos
313 relpos
314 `(imenu--relative-position ,reverse))))
315 (if ,(if relpos t
316 `(> pos (+ 5 ,prevpos)))
317 (progn
318 (message imenu-scanning-message pos)
319 (setq ,prevpos pos))))))
615b306c
KH
320
321
322;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
323;;;;
324;;;; Some examples of functions utilizing the framework of this
325;;;; package.
326;;;;
327;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
328
e064a4f9 329;; Return the current/previous sexp and the location of the sexp (its
615b306c
KH
330;; beginning) without moving the point.
331(defun imenu-example--name-and-position ()
332 (save-excursion
333 (forward-sexp -1)
e7c8378c
RS
334 ;; [ydi] modified for imenu-use-markers
335 (let ((beg (if imenu-use-markers (point-marker) (point)))
336 (end (progn (forward-sexp) (point))))
615b306c 337 (cons (buffer-substring beg end)
e7c8378c 338 beg))))
615b306c
KH
339
340;;;
341;;; Lisp
fe2908be 342;;;
615b306c
KH
343
344(defun imenu-example--lisp-extract-index-name ()
345 ;; Example of a candidate for `imenu-extract-index-name-function'.
346 ;; This will generate a flat index of definitions in a lisp file.
347 (save-match-data
348 (and (looking-at "(def")
349 (condition-case nil
350 (progn
351 (down-list 1)
352 (forward-sexp 2)
353 (let ((beg (point))
354 (end (progn (forward-sexp -1) (point))))
355 (buffer-substring beg end)))
356 (error nil)))))
357
358(defun imenu-example--create-lisp-index ()
359 ;; Example of a candidate for `imenu-create-index-function'.
360 ;; It will generate a nested index of definitions.
361 (let ((index-alist '())
362 (index-var-alist '())
363 (index-type-alist '())
364 (index-unknown-alist '())
365 prev-pos)
366 (goto-char (point-max))
367 (imenu-progress-message prev-pos 0)
368 ;; Search for the function
369 (while (beginning-of-defun)
370 (imenu-progress-message prev-pos nil t)
fe2908be
RS
371 (save-match-data
372 (and (looking-at "(def")
373 (save-excursion
615b306c 374 (down-list 1)
fe2908be 375 (cond
615b306c 376 ((looking-at "def\\(var\\|const\\)")
fe2908be
RS
377 (forward-sexp 2)
378 (push (imenu-example--name-and-position)
379 index-var-alist))
615b306c 380 ((looking-at "def\\(un\\|subst\\|macro\\|advice\\)")
fe2908be
RS
381 (forward-sexp 2)
382 (push (imenu-example--name-and-position)
383 index-alist))
615b306c 384 ((looking-at "def\\(type\\|struct\\|class\\|ine-condition\\)")
fe2908be 385 (forward-sexp 2)
615b306c 386 (if (= (char-after (1- (point))) ?\))
fe2908be 387 (progn
615b306c 388 (forward-sexp -1)
fe2908be 389 (down-list 1)
615b306c 390 (forward-sexp 1)))
fe2908be
RS
391 (push (imenu-example--name-and-position)
392 index-type-alist))
393 (t
394 (forward-sexp 2)
395 (push (imenu-example--name-and-position)
615b306c
KH
396 index-unknown-alist)))))))
397 (imenu-progress-message prev-pos 100)
398 (and index-var-alist
0c20ee61 399 (push (cons "Variables" index-var-alist)
615b306c
KH
400 index-alist))
401 (and index-type-alist
0c20ee61 402 (push (cons "Types" index-type-alist)
615b306c
KH
403 index-alist))
404 (and index-unknown-alist
0c20ee61 405 (push (cons "Syntax-unknown" index-unknown-alist)
615b306c
KH
406 index-alist))
407 index-alist))
408
615b306c
KH
409;; Regular expression to find C functions
410(defvar imenu-example--function-name-regexp-c
fe2908be 411 (concat
615b306c
KH
412 "^[a-zA-Z0-9]+[ \t]?" ; type specs; there can be no
413 "\\([a-zA-Z0-9_*]+[ \t]+\\)?" ; more than 3 tokens, right?
414 "\\([a-zA-Z0-9_*]+[ \t]+\\)?"
415 "\\([*&]+[ \t]*\\)?" ; pointer
416 "\\([a-zA-Z0-9_*]+\\)[ \t]*(" ; name
417 ))
418
419(defun imenu-example--create-c-index (&optional regexp)
420 (let ((index-alist '())
421 prev-pos char)
422 (goto-char (point-min))
423 (imenu-progress-message prev-pos 0)
424 ;; Search for the function
425 (save-match-data
426 (while (re-search-forward
427 (or regexp imenu-example--function-name-regexp-c)
428 nil t)
429 (imenu-progress-message prev-pos)
430 (backward-up-list 1)
431 (save-excursion
432 (goto-char (scan-sexps (point) 1))
433 (setq char (following-char)))
434 ;; Skip this function name if it is a prototype declaration.
435 (if (not (eq char ?\;))
436 (push (imenu-example--name-and-position) index-alist))))
437 (imenu-progress-message prev-pos 100)
438 (nreverse index-alist)))
439
2d24227e 440
0a688fd0
RS
441;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
442;;;
443;;; Internal variables
444;;;
445;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
446
447;; The item to use in the index for rescanning the buffer.
448(defconst imenu--rescan-item '("*Rescan*" . -99))
449
450;; The latest buffer index.
451;; Buffer local.
35c8b898
RS
452(defvar imenu--index-alist nil
453 "The buffer index computed for this buffer in Imenu.
454Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION).
455Special elements look like (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...).
456A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
457
458This variable is local in all buffers, once set.")
459
0a688fd0
RS
460(make-variable-buffer-local 'imenu--index-alist)
461
0cff96e7
RS
462(defvar imenu--last-menubar-index-alist nil
463 "The latest buffer index used to update the menu bar menu.")
464
0a8e8bc6
KH
465(make-variable-buffer-local 'imenu--last-menubar-index-alist)
466
0a688fd0 467;; History list for 'jump-to-function-in-buffer'.
6c1bf12b 468;; Making this buffer local caused it not to work!
0a688fd0 469(defvar imenu--history-list nil)
0a688fd0
RS
470
471;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
472;;;
473;;; Internal support functions
474;;;
475;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
476
477;;;
478;;; Sort function
479;;; Sorts the items depending on their index name.
c01ee596 480;;; An item looks like (NAME . POSITION).
0a688fd0
RS
481;;;
482(defun imenu--sort-by-name (item1 item2)
483 (string-lessp (car item1) (car item2)))
484
c01ee596
KH
485(defun imenu--sort-by-position (item1 item2)
486 (< (cdr item1) (cdr item2)))
487
0a688fd0
RS
488(defun imenu--relative-position (&optional reverse)
489 ;; Support function to calculate relative position in buffer
490 ;; Beginning of buffer is 0 and end of buffer is 100
491 ;; If REVERSE is non-nil then the beginning is 100 and the end is 0.
492 (let ((pos (point))
493 (total (buffer-size)))
494 (and reverse (setq pos (- total pos)))
495 (if (> total 50000)
496 ;; Avoid overflow from multiplying by 100!
497 (/ (1- pos) (max (/ total 100) 1))
498 (/ (* 100 (1- pos)) (max total 1)))))
499
0a688fd0
RS
500;; Split LIST into sublists of max length N.
501;; Example (imenu--split '(1 2 3 4 5 6 7 8) 3)-> '((1 2 3) (4 5 6) (7 8))
502(defun imenu--split (list n)
503 (let ((remain list)
504 (result '())
505 (sublist '())
506 (i 0))
507 (while remain
508 (push (pop remain) sublist)
509 (incf i)
510 (and (= i n)
511 ;; We have finished a sublist
512 (progn (push (nreverse sublist) result)
513 (setq i 0)
514 (setq sublist '()))))
515 ;; There might be a sublist (if the length of LIST mod n is != 0)
516 ;; that has to be added to the result list.
517 (and sublist
518 (push (nreverse sublist) result))
519 (nreverse result)))
520
0c20ee61
RS
521;;; Split the alist MENULIST into a nested alist, if it is long enough.
522;;; In any case, add TITLE to the front of the alist.
0a688fd0 523(defun imenu--split-menu (menulist title)
7ebea144
RS
524 (let (keep-at-top tail)
525 (if (memq imenu--rescan-item menulist)
526 (setq keep-at-top (cons imenu--rescan-item nil)
527 menulist (delq imenu--rescan-item menulist)))
528 (setq tail menulist)
0cdb3baa 529 (dolist (item tail)
dd631e8a
SM
530 (when (imenu--subalist-p item)
531 (push item keep-at-top)
532 (setq menulist (delq item menulist))))
7ebea144 533 (if imenu-sort-function
dd631e8a 534 (setq menulist (sort menulist imenu-sort-function)))
7ebea144 535 (if (> (length menulist) imenu-max-items)
dd631e8a
SM
536 (setq menulist
537 (mapcar
538 (lambda (menu)
539 (cons (format "From: %s" (caar menu)) menu))
540 (imenu--split menulist imenu-max-items))))
7ebea144
RS
541 (cons title
542 (nconc (nreverse keep-at-top) menulist))))
0c20ee61
RS
543
544;;; Split up each long alist that are nested within ALIST
545;;; into nested alists.
546(defun imenu--split-submenus (alist)
fe2908be
RS
547 (mapcar (function
548 (lambda (elt)
549 (if (and (consp elt)
550 (stringp (car elt))
551 (listp (cdr elt)))
552 (imenu--split-menu (cdr elt) (car elt))
553 elt)))
0c20ee61 554 alist))
0a688fd0 555
e7c8378c
RS
556;;; Truncate all strings in MENULIST to imenu-max-item-length
557(defun imenu--truncate-items (menulist)
117be359
DL
558 (mapcar (function
559 (lambda (item)
560 (cond
561 ((consp (cdr item))
562 (imenu--truncate-items (cdr item)))
563 (t
564 ;; truncate if necessary
565 (if (and (numberp imenu-max-item-length)
566 (> (length (car item)) imenu-max-item-length))
567 (setcar item (substring (car item) 0
568 imenu-max-item-length)))))))
569 menulist))
e7c8378c
RS
570
571
0a8e8bc6 572(defun imenu--make-index-alist (&optional noerror)
7e563e04
RS
573 "Create an index-alist for the definitions in the current buffer.
574
fe2908be
RS
575Report an error if the list is empty unless NOERROR is supplied and
576non-nil.
577
7e563e04
RS
578Simple elements in the alist look like (INDEX-NAME . INDEX-POSITION).
579Special elements look like (INDEX-NAME FUNCTION ARGUMENTS...).
580A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
581The function `imenu--subalist-p' tests an element and returns t
fe2908be 582if it is a sub-alist.
7e563e04
RS
583
584There is one simple element with negative POSITION; that's intended
585as a way for the user to ask to recalculate the buffer's index alist."
2d24227e
RS
586 (or (and imenu--index-alist
587 (or (not imenu-auto-rescan)
588 (and imenu-auto-rescan
589 (> (buffer-size) imenu-auto-rescan-maxout))))
e7c8378c
RS
590 ;; Get the index; truncate if necessary
591 (progn
592 (setq imenu--index-alist
593 (save-excursion
594 (save-restriction
595 (widen)
596 (funcall imenu-create-index-function))))
597 (imenu--truncate-items imenu--index-alist)))
0a8e8bc6 598 (or imenu--index-alist noerror
6c1bf12b 599 (error "No items suitable for an index found in this buffer"))
0a8e8bc6
KH
600 (or imenu--index-alist
601 (setq imenu--index-alist (list nil)))
0a688fd0
RS
602 ;; Add a rescan option to the index.
603 (cons imenu--rescan-item imenu--index-alist))
79e098ca 604
5d3b0f18
RS
605;;; Find all markers in alist and makes
606;;; them point nowhere.
79e098ca
RS
607;;; The top-level call uses nil as the argument;
608;;; non-nil arguments are in recursivecalls.
609(defvar imenu--cleanup-seen)
610
5d3b0f18 611(defun imenu--cleanup (&optional alist)
fe2908be 612 ;; If alist is provided use that list.
79e098ca
RS
613 ;; If not, empty the table of lists already seen
614 ;; and use imenu--index-alist.
615 (if alist
616 (setq imenu--cleanup-seen (cons alist imenu--cleanup-seen))
617 (setq alist imenu--index-alist imenu--cleanup-seen (list alist)))
618
4818d210 619 (and alist
e26b2a28
DL
620 (mapc
621 (lambda (item)
622 (cond
623 ((markerp (cdr item))
624 (set-marker (cdr item) nil))
625 ;; Don't process one alist twice.
626 ((memq (cdr item) imenu--cleanup-seen))
627 ((imenu--subalist-p item)
628 (imenu--cleanup (cdr item)))))
4818d210 629 alist)
615b306c
KH
630 t))
631
dd631e8a
SM
632(defun imenu--create-keymap (title alist &optional cmd)
633 (list* 'keymap title
634 (mapcar
635 (lambda (item)
636 (list* (car item) (car item)
637 (cond
638 ((imenu--subalist-p item)
639 (imenu--create-keymap (car item) (cdr item) cmd))
640 (t
641 `(lambda () (interactive)
642 ,(if cmd `(,cmd ',item) (list 'quote item)))))))
643 alist)))
2d24227e 644
2d24227e
RS
645(defun imenu--in-alist (str alist)
646 "Check whether the string STR is contained in multi-level ALIST."
647 (let (elt head tail res)
648 (setq res nil)
649 (while alist
fe2908be 650 (setq elt (car alist)
2d24227e 651 tail (cdr elt)
fe2908be
RS
652 alist (cdr alist)
653 head (car elt))
8396299d
RS
654 ;; A nested ALIST element looks like
655 ;; (INDEX-NAME (INDEX-NAME . INDEX-POSITION) ...)
656 ;; while a bottom-level element looks like
657 ;; (INDEX-NAME . INDEX-POSITION)
658 ;; We are only interested in the bottom-level elements, so we need to
659 ;; recurse if TAIL is a list.
660 (cond ((listp tail)
661 (if (setq res (imenu--in-alist str tail))
662 (setq alist nil)))
020e8fdf
PR
663 ((if imenu-name-lookup-function
664 (funcall imenu-name-lookup-function str head)
665 (string= str head))
8396299d 666 (setq alist nil res elt))))
2d24227e
RS
667 res))
668
fea79780 669(defvar imenu-syntax-alist nil
0cdb3baa 670 "Alist of syntax table modifiers to use while in `imenu--generic-function'.
fea79780
DL
671
672The car of the assocs may be either a character or a string and the
23d468da 673cdr is a syntax description appropriate for `modify-syntax-entry'. For
fea79780
DL
674a string, all the characters in the string get the specified syntax.
675
676This is typically used to give word syntax to characters which
90806abc 677normally have symbol syntax to simplify `imenu-expression'
fea79780 678and speed-up matching.")
005913e4 679;;;###autoload
fea79780
DL
680(make-variable-buffer-local 'imenu-syntax-alist)
681
0a688fd0
RS
682(defun imenu-default-create-index-function ()
683 "*Wrapper for index searching functions.
684
685Moves point to end of buffer and then repeatedly calls
68e01f5a 686`imenu-prev-index-position-function' and `imenu-extract-index-name-function'.
0a688fd0 687Their results are gathered into an index alist."
3e062f78
RS
688 ;; These should really be done by setting imenu-create-index-function
689 ;; in these major modes. But save that change for later.
e536ef56
KH
690 (cond ((and imenu-prev-index-position-function
691 imenu-extract-index-name-function)
3e062f78 692 (let ((index-alist '())
615b306c 693 prev-pos name)
3e062f78 694 (goto-char (point-max))
7dea4e70 695 (imenu-progress-message prev-pos 0 t)
3e062f78 696 ;; Search for the function
fe2908be 697 (while (funcall imenu-prev-index-position-function)
7dea4e70 698 (imenu-progress-message prev-pos nil t)
3e062f78
RS
699 (save-excursion
700 (setq name (funcall imenu-extract-index-name-function)))
701 (and (stringp name)
e7c8378c
RS
702 ;; [ydi] updated for imenu-use-markers
703 (push (cons name (if imenu-use-markers (point-marker) (point)))
704 index-alist)))
7dea4e70 705 (imenu-progress-message prev-pos 100 t)
615b306c
KH
706 index-alist))
707 ;; Use generic expression if possible.
708 ((and imenu-generic-expression)
fe2908be 709 (imenu--generic-function imenu-generic-expression))
615b306c 710 (t
e7c8378c 711 (error "This buffer cannot use `imenu-default-create-index-function'"))))
0a688fd0 712
fe2908be 713;; Not used and would require cl at run time
dd631e8a
SM
714;; (defun imenu--flatten-index-alist (index-alist &optional concat-names prefix)
715;; ;; Takes a nested INDEX-ALIST and returns a flat index alist.
716;; ;; If optional CONCAT-NAMES is non-nil, then a nested index has its
717;; ;; name and a space concatenated to the names of the children.
718;; ;; Third argument PREFIX is for internal use only.
719;; (mapcan
720;; (lambda (item)
721;; (let* ((name (car item))
722;; (pos (cdr item))
723;; (new-prefix (and concat-names
724;; (if prefix
725;; (concat prefix imenu-level-separator name)
726;; name))))
727;; (cond
728;; ((or (markerp pos) (numberp pos))
729;; (list (cons new-prefix pos)))
730;; (t
731;; (imenu--flatten-index-alist pos new-prefix)))))
732;; index-alist))
0a688fd0 733
615b306c
KH
734;;;
735;;; Generic index gathering function.
736;;;
2d24227e 737
73f48953
DL
738(defvar imenu-case-fold-search t
739 "Defines whether `imenu--generic-function' should fold case when matching.
740
0cdb3baa 741This variable should be set (only) by initialization code
95e60ff9
SM
742for modes which use `imenu--generic-function'. If it is not set, but
743`font-lock-defaults' is set, then font-lock's setting is used.")
fe2908be 744;;;###autoload
73f48953
DL
745(make-variable-buffer-local 'imenu-case-fold-search)
746
fe2908be
RS
747;; Originally "Built on some ideas that Erik Naggum <erik@naggum.no>
748;; once posted to comp.emacs" but since substantially re-written.
2d24227e 749(defun imenu--generic-function (patterns)
2d24227e
RS
750 "Return an index of the current buffer as an alist.
751
fe2908be
RS
752PATTERNS is an alist with elements that look like this:
753 (MENU-TITLE REGEXP INDEX).
6b61353c
KH
754or like this:
755 (MENU-TITLE REGEXP INDEX FUNCTION ARGUMENTS...)
756with zero or more ARGUMENTS.
2d24227e
RS
757
758MENU-TITLE is a string used as the title for the submenu or nil if the
759entries are not nested.
760
761REGEXP is a regexp that should match a construct in the buffer that is
6c1bf12b
RS
762to be displayed in the menu; i.e., function or variable definitions,
763etc. It contains a substring which is the name to appear in the
764menu. See the info section on Regexps for more information.
2d24227e
RS
765
766INDEX points to the substring in REGEXP that contains the name (of the
767function, variable or type) that is to appear in the menu.
768
fe2908be 769See `lisp-imenu-generic-expression' for an example of PATTERNS.
2d24227e 770
6c1bf12b 771Returns an index of the current buffer as an alist. The elements in
6b61353c
KH
772the alist look like:
773 (INDEX-NAME . INDEX-POSITION)
774or like:
775 (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...)
776They may also be nested index alists like:
777 (INDEX-NAME . INDEX-ALIST)
778depending on PATTERNS."
2d24227e
RS
779
780 (let ((index-alist (list 'dummy))
fe2908be 781 prev-pos beg
95e60ff9
SM
782 (case-fold-search (if (or (local-variable-p 'imenu-case-fold-search)
783 (not (local-variable-p 'font-lock-defaults)))
784 imenu-case-fold-search
785 (nth 2 font-lock-defaults)))
fea79780
DL
786 (old-table (syntax-table))
787 (table (copy-syntax-table (syntax-table)))
788 (slist imenu-syntax-alist))
789 ;; Modify the syntax table used while matching regexps.
0cdb3baa 790 (dolist (syn slist)
fe2908be 791 ;; The character(s) to modify may be a single char or a string.
0cdb3baa
SM
792 (if (numberp (car syn))
793 (modify-syntax-entry (car syn) (cdr syn) table)
5b89a8c9
GM
794 (mapc (lambda (c)
795 (modify-syntax-entry c (cdr syn) table))
796 (car syn))))
615b306c
KH
797 (goto-char (point-max))
798 (imenu-progress-message prev-pos 0 t)
fe2908be
RS
799 (unwind-protect ; for syntax table
800 (save-match-data
801 (set-syntax-table table)
802 ;; map over the elements of imenu-generic-expression
803 ;; (typically functions, variables ...)
0cdb3baa
SM
804 (dolist (pat patterns)
805 (let ((menu-title (car pat))
806 (regexp (nth 1 pat))
807 (index (nth 2 pat))
808 (function (nth 3 pat))
809 (rest (nthcdr 4 pat)))
810 ;; Go backwards for convenience of adding items in order.
811 (goto-char (point-max))
812 (while (re-search-backward regexp nil t)
813 (imenu-progress-message prev-pos nil t)
814 (setq beg (match-beginning index))
815 ;; Add this sort of submenu only when we've found an
816 ;; item for it, avoiding empty, duff menus.
817 (unless (assoc menu-title index-alist)
818 (push (list menu-title) index-alist))
819 (if imenu-use-markers
820 (setq beg (copy-marker beg)))
821 (let ((item
822 (if function
823 (nconc (list (match-string-no-properties index)
824 beg function)
825 rest)
826 (cons (match-string-no-properties index)
827 beg)))
828 ;; This is the desired submenu,
829 ;; starting with its title (or nil).
830 (menu (assoc menu-title index-alist)))
831 ;; Insert the item unless it is already present.
832 (unless (member item (cdr menu))
833 (setcdr menu
834 (cons item (cdr menu))))))))
fe2908be 835 (set-syntax-table old-table)))
0c20ee61 836 (imenu-progress-message prev-pos 100 t)
c01ee596
KH
837 ;; Sort each submenu by position.
838 ;; This is in case one submenu gets items from two different regexps.
0cdb3baa
SM
839 (dolist (item index-alist)
840 (when (listp item)
841 (setcdr item (sort (cdr item) 'imenu--sort-by-position))))
0c20ee61 842 (let ((main-element (assq nil index-alist)))
7ebea144
RS
843 (nconc (delq main-element (delq 'dummy index-alist))
844 (cdr main-element)))))
615b306c 845
0a688fd0
RS
846;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
847;;;
848;;; The main functions for this package!
849;;;
850;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
851
0cdb3baa
SM
852;; See also info-lookup-find-item
853(defun imenu-find-default (guess completions)
854 "Fuzzily find an item based on GUESS inside the alist COMPLETIONS."
855 (catch 'found
856 (let ((case-fold-search t))
857 (if (assoc guess completions) guess
858 (dolist (re (list (concat "\\`" (regexp-quote guess) "\\'")
859 (concat "\\`" (regexp-quote guess))
860 (concat (regexp-quote guess) "\\'")
861 (regexp-quote guess)))
862 (dolist (x completions)
863 (if (string-match re (car x)) (throw 'found (car x)))))))))
864
0a688fd0
RS
865(defun imenu--completion-buffer (index-alist &optional prompt)
866 "Let the user select from INDEX-ALIST in a completion buffer with PROMPT.
867
868Returns t for rescan and otherwise a position number."
869 ;; Create a list for this buffer only when needed.
fe2908be
RS
870 (let ((name (thing-at-point 'symbol))
871 choice
872 (prepared-index-alist
5988bd27
SM
873 (if (not imenu-space-replacement) index-alist
874 (mapcar
875 (lambda (item)
876 (cons (subst-char-in-string ?\ (aref imenu-space-replacement 0)
877 (car item))
878 (cdr item)))
879 index-alist))))
0cdb3baa
SM
880 (when (stringp name)
881 (setq name (or (imenu-find-default name prepared-index-alist) name)))
fe2908be
RS
882 (cond (prompt)
883 ((and name (imenu--in-alist name prepared-index-alist))
884 (setq prompt (format "Index item (default %s): " name)))
885 (t (setq prompt "Index item: ")))
5988bd27
SM
886 (let ((minibuffer-setup-hook minibuffer-setup-hook))
887 ;; Display the completion buffer.
888 (if (not imenu-eager-completion-buffer)
889 (add-hook 'minibuffer-setup-hook 'minibuffer-completion-help))
890 (setq name (completing-read prompt
891 prepared-index-alist
892 nil t nil 'imenu--history-list name)))
0cdb3baa
SM
893 (cond ((not (stringp name)) nil)
894 ((string= name (car imenu--rescan-item)) t)
3e062f78
RS
895 (t
896 (setq choice (assoc name prepared-index-alist))
215b077e 897 (if (imenu--subalist-p choice)
3e062f78
RS
898 (imenu--completion-buffer (cdr choice) prompt)
899 choice)))))
68e01f5a 900
0a688fd0
RS
901(defun imenu--mouse-menu (index-alist event &optional title)
902 "Let the user select from a buffer index from a mouse menu.
903
904INDEX-ALIST is the buffer index and EVENT is a mouse event.
905
32c1a22e 906Returns t for rescan and otherwise an element or subelement of INDEX-ALIST."
0c20ee61 907 (setq index-alist (imenu--split-submenus index-alist))
0cdb3baa 908 (let* ((menu (imenu--split-menu index-alist (or title (buffer-name))))
dd631e8a
SM
909 (map (imenu--create-keymap (car menu)
910 (cdr (if (< 1 (length (cdr menu)))
911 menu
912 (car (cdr menu)))))))
0cdb3baa 913 (popup-menu map event)))
0a688fd0 914
26d6bb60 915(defun imenu-choose-buffer-index (&optional prompt alist)
0a688fd0
RS
916 "Let the user select from a buffer index and return the chosen index.
917
918If the user originally activated this function with the mouse, a mouse
0a688fd0
RS
919menu is used. Otherwise a completion buffer is used and the user is
920prompted with PROMPT.
921
26d6bb60
RS
922If you call this function with index alist ALIST, then it lets the user
923select from ALIST.
924
0ee4f8ad 925With no index alist ALIST, it calls `imenu--make-index-alist' to
26d6bb60
RS
926create the index alist.
927
5988bd27 928If `imenu-use-popup-menu' is non-nil, then the
0a688fd0
RS
929completion buffer is always used, no matter if the mouse was used or
930not.
931
7e563e04 932The returned value is of the form (INDEX-NAME . INDEX-POSITION)."
0a688fd0 933 (let (index-alist
7dea4e70 934 (mouse-triggered (listp last-nonmenu-event))
0cdb3baa 935 (result t))
0a688fd0
RS
936 ;; If selected by mouse, see to that the window where the mouse is
937 ;; really is selected.
938 (and mouse-triggered
4cde72b4 939 (not (equal last-nonmenu-event '(menu-bar)))
7dea4e70 940 (let ((window (posn-window (event-start last-nonmenu-event))))
4a840d8b 941 (or (framep window) (null window) (select-window window))))
0a688fd0
RS
942 ;; Create a list for this buffer only when needed.
943 (while (eq result t)
26d6bb60 944 (setq index-alist (if alist alist (imenu--make-index-alist)))
0a688fd0 945 (setq result
5988bd27
SM
946 (if (and imenu-use-popup-menu
947 (or (eq imenu-use-popup-menu t) mouse-triggered))
7dea4e70 948 (imenu--mouse-menu index-alist last-nonmenu-event)
0a688fd0
RS
949 (imenu--completion-buffer index-alist prompt)))
950 (and (eq result t)
5d3b0f18 951 (imenu--cleanup)
0a688fd0
RS
952 (setq imenu--index-alist nil)))
953 result))
954
2d24227e 955;;;###autoload
5d3b0f18 956(defun imenu-add-to-menubar (name)
fe2908be 957 "Add an `imenu' entry to the menu bar for the current buffer.
0a8e8bc6 958NAME is a string used to name the menu bar item.
d1757026 959See the command `imenu' for more information."
0a8e8bc6 960 (interactive "sImenu menu item name: ")
e536ef56
KH
961 (if (or (and imenu-prev-index-position-function
962 imenu-extract-index-name-function)
963 imenu-generic-expression
964 (not (eq imenu-create-index-function
965 'imenu-default-create-index-function)))
e26b2a28
DL
966 (let ((newmap (make-sparse-keymap)))
967 (set-keymap-parent newmap (current-local-map))
0cff96e7 968 (setq imenu--last-menubar-index-alist nil)
f1d7969d 969 (define-key newmap [menu-bar index]
fbfb705c 970 `(menu-item ,name ,(make-sparse-keymap "Imenu")))
e26b2a28 971 (use-local-map newmap)
e536ef56 972 (add-hook 'menu-bar-update-hook 'imenu-update-menubar))
37954a9a 973 (error "The mode `%s' does not support Imenu" mode-name)))
0a8e8bc6 974
fe2908be
RS
975;;;###autoload
976(defun imenu-add-menubar-index ()
977 "Add an Imenu \"Index\" entry on the menu bar for the current buffer.
978
979A trivial interface to `imenu-add-to-menubar' suitable for use in a hook."
980 (interactive)
981 (imenu-add-to-menubar "Index"))
982
6d7a4832
KH
983(defvar imenu-buffer-menubar nil)
984
9fb980fc 985(defvar imenu-menubar-modified-tick 0
a3841d3b
RS
986 "The value of (buffer-modified-tick) as of last call to `imenu-update-menubar'.
987This value becomes local in every buffer when it is set.")
9fb980fc 988(make-variable-buffer-local 'imenu-menubar-modified-tick)
a3841d3b 989
0a8e8bc6 990(defun imenu-update-menubar ()
9fb980fc
RS
991 (when (and (current-local-map)
992 (keymapp (lookup-key (current-local-map) [menu-bar index]))
993 (not (eq (buffer-modified-tick)
994 imenu-menubar-modified-tick)))
995 (setq imenu-menubar-modified-tick (buffer-modified-tick))
996 (let ((index-alist (imenu--make-index-alist t)))
997 ;; Don't bother updating if the index-alist has not changed
998 ;; since the last time we did it.
999 (unless (equal index-alist imenu--last-menubar-index-alist)
1000 (let (menu menu1 old)
1001 (setq imenu--last-menubar-index-alist index-alist)
1002 (setq index-alist (imenu--split-submenus index-alist))
1003 (setq menu (imenu--split-menu index-alist
1004 (buffer-name)))
dd631e8a
SM
1005 (setq menu1 (imenu--create-keymap (car menu)
1006 (cdr (if (< 1 (length (cdr menu)))
1007 menu
1008 (car (cdr menu))))
1009 'imenu--menubar-select))
9fb980fc
RS
1010 (setq old (lookup-key (current-local-map) [menu-bar index]))
1011 (setcdr old (cdr menu1)))))))
0a8e8bc6
KH
1012
1013(defun imenu--menubar-select (item)
0cdb3baa 1014 "Use Imenu to select the function or variable named in this menu ITEM."
37954a9a 1015 (if (equal item imenu--rescan-item)
e63679b8
RS
1016 (progn
1017 (imenu--cleanup)
1018 (setq imenu--index-alist nil)
0cdb3baa
SM
1019 (imenu-update-menubar)
1020 t)
1021 (imenu item)
1022 nil))
5d3b0f18 1023
37954a9a 1024(defun imenu-default-goto-function (name position &optional rest)
fe2908be
RS
1025 "Move the point to the given position.
1026
1027NAME is ignored. POSITION is where to move. REST is also ignored.
1028The ignored args just make this function have the same interface as a
1029function placed in a special index-item."
e7c8378c
RS
1030 (if (or (< position (point-min))
1031 (> position (point-max)))
37954a9a
RS
1032 ;; widen if outside narrowing
1033 (widen))
e7c8378c 1034 (goto-char position))
37954a9a 1035
68e01f5a 1036;;;###autoload
6c1bf12b 1037(defun imenu (index-item)
68e01f5a 1038 "Jump to a place in the buffer chosen using a buffer menu or mouse menu.
fe2908be
RS
1039INDEX-ITEM specifies the position. See `imenu-choose-buffer-index'
1040for more information."
01e980fb 1041 (interactive (list (imenu-choose-buffer-index)))
0a8e8bc6
KH
1042 ;; Convert a string to an alist element.
1043 (if (stringp index-item)
1044 (setq index-item (assoc index-item (imenu--make-index-alist))))
0cdb3baa
SM
1045 (when index-item
1046 (push-mark)
1047 (let* ((is-special-item (listp (cdr index-item)))
1048 (function
1049 (if is-special-item
1050 (nth 2 index-item) imenu-default-goto-function))
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))
1055 (run-hooks 'imenu-after-jump-hook)))
5d3b0f18 1056
f1ed9461
DL
1057(dolist (mess
1058 '("^No items suitable for an index found in this buffer$"
1059 "^This buffer cannot use `imenu-default-create-index-function'$"
1060 "^The mode `.*' does not support Imenu$"))
1061 (add-to-list 'debug-ignored-errors mess))
1062
0a688fd0
RS
1063(provide 'imenu)
1064
6b61353c 1065;;; arch-tag: 98a2f5f5-4b91-4704-b18c-3aacf77d77a7
0a688fd0 1066;;; imenu.el ends here