(run-hook-with-args): Fix previous code.
[bpt/emacs.git] / lisp / imenu.el
CommitLineData
0a688fd0
RS
1;;; imenu.el --- Framework for mode-specific buffer indexes.
2
3;; Copyright (C) 1994 Free Software Foundation, Inc.
4
5;; Author: Ake Stenhoff <etxaksf@aom.ericsson.se>
6;; Lars Lindberg <lli@sypro.cap.se>
7;; Created: 8 Feb 1994
2d24227e 8;; Version: 1.17
0a688fd0
RS
9;; Keywords: tools
10;;
11;; This program is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation; either version 2, or (at your option)
14;; any later version.
15;;
16;; This program is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20;;
21;; You should have received a copy of the GNU General Public License
22;; along with this program; if not, write to the Free Software
23;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
25;;; Commentary:
26;;
27;; Purpose of this package:
28;; To present a framework for mode-specific buffer indexes.
29;; A buffer index is an alist of names and buffer positions.
30;; For instance all functions in a C-file and their positions.
31;;
32;; How it works:
33
34;; A mode-specific function is called to generate the index. It is
35;; then presented to the user, who can choose from this index.
36;;
37;; The package comes with a set of example functions for how to
38;; utilize this package.
39
2d24227e
RS
40;; There are *examples* for index gathering functions/regular
41;; expressions for C/C++ and Lisp/Emacs Lisp but it is easy to
42;; customize for other modes. A function for jumping to the chosen
43;; index position is also supplied.
0a688fd0 44
26d6bb60
RS
45;;; Thanks goes to
46;; [simon] - Simon Leinen simon@lia.di.epfl.ch
47;; [dean] - Dean Andrews ada@unison.com
5d3b0f18 48;; [alon] - Alon Albert al@mercury.co.il
7804cd27 49;; [greg] - Greg Thompson gregt@porsche.visix.COM
615b306c 50;; [wolfgang] - Wolfgang Bangerth zcg51122@rpool1.rus.uni-stuttgart.de
056ab244 51;; [kai] - Kai Grossjohann grossjoh@linus.informatik.uni-dortmund.de
af447694 52;; [david] - David M. Smith dsmith@stats.adelaide.edu.au
2d24227e
RS
53;; [christian] - Christian Egli Christian.Egli@hcsd.hac.com
54;; [karl] - Karl Fogel kfogel@floss.life.uiuc.edu
55
0a688fd0 56;;; Code
0ee4f8ad 57(eval-when-compile (require 'cl))
0a688fd0
RS
58
59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
60;;;
61;;; Customizable variables
62;;;
63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2d24227e
RS
64(defvar imenu-use-keymap-menu nil
65 "* Set this to non-nil for using a keymap when making
66 the mouse menu.")
67
68(defvar imenu-auto-rescan nil
69 "* T if we always should rescan the buffers, nil to disable
70 automatic rescan.")
71
72(defvar imenu-auto-rescan-maxout 60000
73 "* auto-rescan is disabled in buffers larger than this.
74 This variable is buffer-local.")
0a688fd0
RS
75
76(defvar imenu-always-use-completion-buffer-p nil
77 "*Set this to non-nil for displaying the index in a completion buffer.
78
79Non-nil means always display the index in a completion buffer.
80Nil means display the index as a mouse menu when the mouse was
af447694
RS
81used to invoke `imenu'.
82`never' means never automatically display a listing of any kind.")
0a688fd0
RS
83
84(defvar imenu-sort-function nil
85 "*The function to use for sorting the index mouse-menu.
86
87Affects only the mouse index menu.
88
89Set this to nil if you don't want any sorting (faster).
90The items in the menu are then presented in the order they were found
91in the buffer.
92
0ee4f8ad 93Set it to `imenu--sort-by-name' if you want alphabetic sorting.
0a688fd0
RS
94
95The function should take two arguments and return T if the first
96element should come before the second. The arguments are cons cells;
a4e104bf 97\(NAME . POSITION). Look at `imenu--sort-by-name' for an example.")
0a688fd0
RS
98
99(defvar imenu-max-items 25
100 "*Maximum number of elements in an index mouse-menu.")
101
102(defvar imenu-scanning-message "Scanning buffer for index. (%3d%%)"
103 "*Progress message during the index scanning of the buffer.
7dea4e70 104If non-nil, user gets a message during the scanning of the buffer
0a688fd0
RS
105
106Relevant only if the mode-specific function that creates the buffer
0ee4f8ad 107index use `imenu-progress-message'.")
0a688fd0
RS
108
109(defvar imenu-space-replacement "^"
110 "*The replacement string for spaces in index names.
111Used when presenting the index in a completion-buffer to make the
112names work as tokens.")
113
114(defvar imenu-level-separator ":"
115 "*The separator between index names of different levels.
116Used for making mouse-menu titles and for flattening nested indexes
117with name concatenation.")
118
119(defvar imenu-submenu-name-format "%s..."
120 "*The format for making a submenu name.")
121
2d24227e 122;;;###autoload
615b306c 123(defvar imenu-generic-expression nil
2d24227e
RS
124 "The regex pattern to use for creating a buffer index.
125
126If non-nil this pattern is passed to `imenu-create-index-with-pattern'
127to create a buffer index.
128
129It is an alist with elements that look like this: (MENU-TITLE
130REGEXP INDEX).
131
132MENU-TITLE is a string used as the title for the submenu or nil if the
133entries are not nested.
134
135REGEXP is a regexp that should match a construct in the buffer that is
136to be displayed in the menu i.e. function or variable definitions,
137etc. It contains a substring which is the name to appear in the
138menu. See the info section on Regexps for more information.
139
140INDEX points to the substring in REGEXP that contains the name (of the
141function, variable or type) that is to appear in the menu.
615b306c 142
2d24227e
RS
143For emacs-lisp-mode for example PATTERN would look like:
144
145'((nil \"^\\s-*(def\\(un\\|subst\\|macro\\|advice\\)\\s-+\\([-A-Za-z0-9+]+\\)\" 2)
146 (\"*Vars*\" \"^\\s-*(def\\(var\\|const\\)\\s-+\\([-A-Za-z0-9+]+\\)\" 2)
147 (\"*Types*\" \"^\\s-*(def\\(type\\|struct\\|class\\|ine-condition\\)\\s-+\\([-A-Za-z0-9+]+\\)\" 2))
148
149The variable is buffer-local.")
150
151;;;###autoload
152(make-variable-buffer-local 'imenu-create-index-pattern)
153
154;; make sure the default is nil
155(setq-default imenu-create-index-pattern nil)
615b306c 156
0a688fd0
RS
157;;;; Hooks
158
159(defvar imenu-create-index-function 'imenu-default-create-index-function
160 "The function to use for creating a buffer index.
161
162It should be a function that takes no arguments and returns an index
163of the current buffer as an alist. The elements in the alist look
164like: (INDEX-NAME . INDEX-POSITION). You may also nest index list like
a4e104bf 165\(INDEX-NAME . INDEX-ALIST).
0a688fd0 166
0ee4f8ad 167This function is called within a `save-excursion'.
0a688fd0
RS
168
169The variable is buffer-local.")
170(make-variable-buffer-local 'imenu-create-index-function)
171
68e01f5a 172(defvar imenu-prev-index-position-function 'beginning-of-defun
0a688fd0
RS
173 "Function for finding the next index position.
174
0ee4f8ad
RS
175If `imenu-create-index-function' is set to
176`imenu-default-create-index-function', then you must set this variable
0a688fd0
RS
177to a function that will find the next index, looking backwards in the
178file.
179
180The function should leave point at the place to be connected to the
181index and it should return nil when it doesn't find another index. ")
68e01f5a 182(make-variable-buffer-local 'imenu-prev-index-position-function)
0a688fd0 183
68e01f5a 184(defvar imenu-extract-index-name-function nil
0a688fd0
RS
185 "Function for extracting the index name.
186
0a688fd0 187This function is called after the function pointed out by
68e01f5a
RS
188`imenu-prev-index-position-function'.")
189(make-variable-buffer-local 'imenu-extract-index-name-function)
0a688fd0 190
615b306c
KH
191;;;
192;;; Macro to display a progress message.
193;;; RELPOS is the relative position to display.
194;;; If RELPOS is nil, then the relative position in the buffer
195;;; is calculated.
196;;; PREVPOS is the variable in which we store the last position displayed.
197(defmacro imenu-progress-message (prevpos &optional relpos reverse)
198 (` (and
199 imenu-scanning-message
200 (let ((pos (, (if relpos
201 relpos
202 (` (imenu--relative-position (, reverse)))))))
203 (if (, (if relpos t
204 (` (> pos (+ 5 (, prevpos))))))
205 (progn
206 (message imenu-scanning-message pos)
207 (setq (, prevpos) pos)))))))
208
209
210;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
211;;;;
212;;;; Some examples of functions utilizing the framework of this
213;;;; package.
214;;;;
215;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
216
217;; Return the current/previous sexp and the location of the sexp (it's
218;; beginning) without moving the point.
219(defun imenu-example--name-and-position ()
220 (save-excursion
221 (forward-sexp -1)
222 (let ((beg (point))
223 (end (progn (forward-sexp) (point)))
224 (marker (make-marker)))
225 (set-marker marker beg)
226 (cons (buffer-substring beg end)
227 marker))))
228
229;;;
230;;; Lisp
231;;;
232
233(defun imenu-example--lisp-extract-index-name ()
234 ;; Example of a candidate for `imenu-extract-index-name-function'.
235 ;; This will generate a flat index of definitions in a lisp file.
236 (save-match-data
237 (and (looking-at "(def")
238 (condition-case nil
239 (progn
240 (down-list 1)
241 (forward-sexp 2)
242 (let ((beg (point))
243 (end (progn (forward-sexp -1) (point))))
244 (buffer-substring beg end)))
245 (error nil)))))
246
247(defun imenu-example--create-lisp-index ()
248 ;; Example of a candidate for `imenu-create-index-function'.
249 ;; It will generate a nested index of definitions.
250 (let ((index-alist '())
251 (index-var-alist '())
252 (index-type-alist '())
253 (index-unknown-alist '())
254 prev-pos)
255 (goto-char (point-max))
256 (imenu-progress-message prev-pos 0)
257 ;; Search for the function
258 (while (beginning-of-defun)
259 (imenu-progress-message prev-pos nil t)
260 (save-match-data
261 (and (looking-at "(def")
262 (save-excursion
263 (down-list 1)
264 (cond
265 ((looking-at "def\\(var\\|const\\)")
266 (forward-sexp 2)
267 (push (imenu-example--name-and-position)
268 index-var-alist))
269 ((looking-at "def\\(un\\|subst\\|macro\\|advice\\)")
270 (forward-sexp 2)
271 (push (imenu-example--name-and-position)
272 index-alist))
273 ((looking-at "def\\(type\\|struct\\|class\\|ine-condition\\)")
274 (forward-sexp 2)
275 (if (= (char-after (1- (point))) ?\))
276 (progn
277 (forward-sexp -1)
278 (down-list 1)
279 (forward-sexp 1)))
280 (push (imenu-example--name-and-position)
281 index-type-alist))
282 (t
283 (forward-sexp 2)
284 (push (imenu-example--name-and-position)
285 index-unknown-alist)))))))
286 (imenu-progress-message prev-pos 100)
287 (and index-var-alist
288 (push (cons (imenu-create-submenu-name "Variables") index-var-alist)
289 index-alist))
290 (and index-type-alist
291 (push (cons (imenu-create-submenu-name "Types") index-type-alist)
292 index-alist))
293 (and index-unknown-alist
294 (push (cons (imenu-create-submenu-name "Syntax-unknown") index-unknown-alist)
295 index-alist))
296 index-alist))
297
2d24227e
RS
298(defvar imenu-generic-lisp-expression
299 '(
300 (nil
301 "^\\s-*(def\\(un\\|subst\\|macro\\|advice\\)\\s-+\\([-A-Za-z0-9+]+\\)" 2)
302 ("Variables"
303 "^\\s-*(def\\(var\\|const\\)\\s-+\\([-A-Za-z0-9+]+\\)" 2)
304 ("Types"
305 "^\\s-*(def\\(type\\|struct\\|class\\|ine-condition\\)\\s-+\\([-A-Za-z0-9+]+\\)"
306 2))
307
308 "imenu generic expression for Lisp mode in the form
309(PATTERN), where PATTERN is a list containing entries of the form
310(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.")
311
312;;;
313;;; C++
314;;;
315;; Example of an imenu-generic-expression
316;;
317(defvar imenu-generic-c++-expression
318 (`
319 ((nil
320 (,
321 (concat
322 "^" ; beginning of line is required
323 "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
324 "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; type specs; there can be no
325 "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; more than 3 tokens, right?
326
327 "\\(" ; last type spec including */&
328 "[a-zA-Z0-9_:]+"
329 "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)" ; either pointer/ref sign or whitespace
330 "\\)?" ; if there is a last type spec
331 "\\(" ; name; take that into the imenu entry
332 "[a-zA-Z0-9_:~]+" ; member function, ctor or dtor...
333 ; (may not contain * because then
334 ; "a::operator char*" would become "char*"!)
335 "\\|"
336 "\\([a-zA-Z0-9_:~]*::\\)?operator"
337 "[^a-zA-Z1-9_][^(]*" ; ...or operator
338 " \\)"
339 "[ \t]*([^)]*)[ \t\n]*[^ ;]" ; require something other than a ; after
340 ; the (...) to avoid prototypes. Can't
341 ; catch cases with () inside the parentheses
342 ; surrounding the parameters
343 ; (like "int foo(int a=bar()) {...}"
344
345 )) 6)
346 ("Class"
347 (, (concat
348 "^" ; beginning of line is required
349 "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
350 "class[ \t]+"
351 "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
352 "[ \t]*[:{]"
353 )) 2)
354;; Example of generic expression for finding prototypes, structs, unions, enums.
355;; Uncomment if You want to find these too. It will be at bit slower gathering
356;; the indexes.
357; ("Prototypes"
358; (,
359; (concat
360; "^" ; beginning of line is required
361; "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
362; "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; type specs; there can be no
363; "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; more than 3 tokens, right?
364
365; "\\(" ; last type spec including */&
366; "[a-zA-Z0-9_:]+"
367; "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)" ; either pointer/ref sign or whitespace
368; "\\)?" ; if there is a last type spec
369; "\\(" ; name; take that into the imenu entry
370; "[a-zA-Z0-9_:~]+" ; member function, ctor or dtor...
371; ; (may not contain * because then
372; ; "a::operator char*" would become "char*"!)
373; "\\|"
374; "\\([a-zA-Z0-9_:~]*::\\)?operator"
375; "[^a-zA-Z1-9_][^(]*" ; ...or operator
376; " \\)"
377; "[ \t]*([^)]*)[ \t\n]*;" ; require ';' after
378; ; the (...) Can't
379; ; catch cases with () inside the parentheses
380; ; surrounding the parameters
381; ; (like "int foo(int a=bar());"
382; )) 6)
383; ("Struct"
384; (, (concat
385; "^" ; beginning of line is required
386; "\\(static[ \t]+\\)?" ; there may be static or const.
387; "\\(const[ \t]+\\)?"
388; "struct[ \t]+"
389; "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
390; "[ \t]*[{]"
391; )) 3)
392; ("Enum"
393; (, (concat
394; "^" ; beginning of line is required
395; "\\(static[ \t]+\\)?" ; there may be static or const.
396; "\\(const[ \t]+\\)?"
397; "enum[ \t]+"
398; "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
399; "[ \t]*[{]"
400; )) 3)
401; ("Union"
402; (, (concat
403; "^" ; beginning of line is required
404; "\\(static[ \t]+\\)?" ; there may be static or const.
405; "\\(const[ \t]+\\)?"
406; "union[ \t]+"
407; "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
408; "[ \t]*[{]"
409; )) 3)
410 ))
411 "imenu generic expression for C++ mode in the form
412(PATTERN), where PATTERN is a list containing entries of the form
413(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.")
414
615b306c
KH
415;;;
416;;; C
417;;;
2d24227e
RS
418;;;
419(defvar imenu-generic-c-expression
420 ;; Use the C++ expression above.
421 imenu-generic-c++-expression
422 "imenu generic expression for C mode in the form
423(PATTERN), where PATTERN is a list containing entries of the form
424(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.")
425
615b306c
KH
426;; Regular expression to find C functions
427(defvar imenu-example--function-name-regexp-c
428 (concat
429 "^[a-zA-Z0-9]+[ \t]?" ; type specs; there can be no
430 "\\([a-zA-Z0-9_*]+[ \t]+\\)?" ; more than 3 tokens, right?
431 "\\([a-zA-Z0-9_*]+[ \t]+\\)?"
432 "\\([*&]+[ \t]*\\)?" ; pointer
433 "\\([a-zA-Z0-9_*]+\\)[ \t]*(" ; name
434 ))
435
436(defun imenu-example--create-c-index (&optional regexp)
437 (let ((index-alist '())
438 prev-pos char)
439 (goto-char (point-min))
440 (imenu-progress-message prev-pos 0)
441 ;; Search for the function
442 (save-match-data
443 (while (re-search-forward
444 (or regexp imenu-example--function-name-regexp-c)
445 nil t)
446 (imenu-progress-message prev-pos)
447 (backward-up-list 1)
448 (save-excursion
449 (goto-char (scan-sexps (point) 1))
450 (setq char (following-char)))
451 ;; Skip this function name if it is a prototype declaration.
452 (if (not (eq char ?\;))
453 (push (imenu-example--name-and-position) index-alist))))
454 (imenu-progress-message prev-pos 100)
455 (nreverse index-alist)))
456
2d24227e
RS
457
458;;
459;; Ada
460;;
461;; Written by Christian Egli <Christian.Egli@hcsd.hac.com>
615b306c 462;;
2d24227e
RS
463(defvar imenu-generic-ada-expression
464 '((nil "^\\s-*\\(procedure\\|function\\)\\s-+\\([A-Za-z0-9_]+\\)" 2)
465 ("Type Defs" "^\\s-*\\(sub\\)?type\\s-+\\([A-Za-z0-9_]+\\)" 2))
466
467 "imenu generic expression for Ada mode in the form
468(PATTERN), where PATTERN is a list containing entries of the form
469(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.")
615b306c
KH
470
471;;;
472;;; TexInfo
473;;;
474;; Written by Wolfgang Bangerth <zcg51122@rpool1.rus.uni-stuttgart.de>
475;;
476;;
2d24227e
RS
477(defvar imenu-generic-texinfo-expression
478 '((nil "^@node[ \t]+\\([^,\n]*\\)" 1)
479 ("Chapters" "^@chapter[ \t]+\\(.*\\)$" 1))
480
615b306c 481 "imenu generic expression for TexInfo mode in the form
2d24227e
RS
482(PATTERN), where PATTERN is a list containing entries of the form
483(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.
615b306c
KH
484
485To overide this example, Either set 'imenu-generic-expression
486or 'imenu-create-index-function")
487
488;;;
489;;; LaTex
490;;;
491;; Written by Wolfgang Bangerth <zcg51122@rpool1.rus.uni-stuttgart.de>
492;;
493;;
2d24227e
RS
494(defvar imenu-generic-latex-expression
495 '(
496 ("Part" "\\\\part{\\([^}]*\\)}" 1)
497 ("Chapter" "\\\\chapter{\\([^}]*\\)}" 1)
498 ("Section" "\\\\[a-zA-Z]*section{\\([^}]*\\)}" 1)
499 ;; i put numbers like 3.15 before my
500 ;; \begin{equation}'s which tell me
501 ;; the number the equation will get when
502 ;; being printed.
503 ("Equations" "%[ \t]*\\([0-9]+\\.[0-9]+\\)[,;]?[ \t]?" 1))
504
615b306c 505 "imenu generic expression for LaTex mode in the form
2d24227e
RS
506(PATTERN), where PATTERN is a list containing entries of the form
507(MENU-TITLE REGEXP INDEX). See `imenu-generic-expression'.")
615b306c 508
0a688fd0
RS
509;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
510;;;
511;;; Internal variables
512;;;
513;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
514
515;; The item to use in the index for rescanning the buffer.
516(defconst imenu--rescan-item '("*Rescan*" . -99))
517
518;; The latest buffer index.
519;; Buffer local.
520(defvar imenu--index-alist nil)
521(make-variable-buffer-local 'imenu--index-alist)
522
523;; History list for 'jump-to-function-in-buffer'.
524;; Buffer local.
525(defvar imenu--history-list nil)
526(make-variable-buffer-local 'imenu--history-list)
527
2d24227e
RS
528(defvar imenu--scanning-method-alist
529 '((emacs-lisp-mode imenu-generic-lisp-expression)
530 (lisp-mode imenu-example--create-lisp-index)
531 (c++-mode imenu-generic-c++-expression)
532 (c-mode imenu-generic-c-expression)
533 (latex-mode imenu-generic-latex-expression)
534 (texinfo-mode imenu-generic-texinfo-expression)
535 (ada-mode imenu-generic-ada-expression))
536
537 "Alist of major mode and imenu scanning methods.
538
539Each item should be a list of the form: (MAJOR-MODE
540IMENU-SCANNING-METHOD) where both MAJOR-MODE and IMENU-SCANNING-METHOD
541are symbols. If IMENU-SCANNING-METHOD is a function then it is called
542to create an index. If it is a `pattern' (See `imenu-generic-expression')
543it is passed to imenu--generic-function to create an index.")
544
0a688fd0
RS
545;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
546;;;
547;;; Internal support functions
548;;;
549;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
550
551;;;
552;;; Sort function
553;;; Sorts the items depending on their index name.
554;;; An item look like (NAME . POSITION).
555;;;
556(defun imenu--sort-by-name (item1 item2)
557 (string-lessp (car item1) (car item2)))
558
559(defun imenu--relative-position (&optional reverse)
560 ;; Support function to calculate relative position in buffer
561 ;; Beginning of buffer is 0 and end of buffer is 100
562 ;; If REVERSE is non-nil then the beginning is 100 and the end is 0.
563 (let ((pos (point))
564 (total (buffer-size)))
565 (and reverse (setq pos (- total pos)))
566 (if (> total 50000)
567 ;; Avoid overflow from multiplying by 100!
568 (/ (1- pos) (max (/ total 100) 1))
569 (/ (* 100 (1- pos)) (max total 1)))))
570
0a688fd0
RS
571;;;
572;;; Function for suporting general looking submenu names.
0ee4f8ad 573;;; Uses `imenu-submenu-name-format' for creating the name.
0a688fd0
RS
574;;; NAME is the base of the new submenu name.
575;;;
576(defun imenu-create-submenu-name (name)
2d24227e 577 (format imenu-submenu-name-format name))
0a688fd0
RS
578
579;; Split LIST into sublists of max length N.
580;; Example (imenu--split '(1 2 3 4 5 6 7 8) 3)-> '((1 2 3) (4 5 6) (7 8))
581(defun imenu--split (list n)
582 (let ((remain list)
583 (result '())
584 (sublist '())
585 (i 0))
586 (while remain
587 (push (pop remain) sublist)
588 (incf i)
589 (and (= i n)
590 ;; We have finished a sublist
591 (progn (push (nreverse sublist) result)
592 (setq i 0)
593 (setq sublist '()))))
594 ;; There might be a sublist (if the length of LIST mod n is != 0)
595 ;; that has to be added to the result list.
596 (and sublist
597 (push (nreverse sublist) result))
598 (nreverse result)))
599
600;;;
601;;; Split a menu in to several menus.
602;;;
603(defun imenu--split-menu (menulist title)
2d24227e 604 (cons "Index menu"
0a688fd0
RS
605 (mapcar
606 (function
607 (lambda (menu)
608 (cons (format "(%s)" title) menu)))
609 (imenu--split menulist imenu-max-items))))
610
611;;;
612;;; Find all items in this buffer that should be in the index.
613;;; Returns an alist on the form
614;;; ((NAME . POSITION) (NAME . POSITION) ...)
615;;;
616
617(defun imenu--make-index-alist ()
618 ;; Create a list for this buffer only when needed.
2d24227e
RS
619 (or (and imenu--index-alist
620 (or (not imenu-auto-rescan)
621 (and imenu-auto-rescan
622 (> (buffer-size) imenu-auto-rescan-maxout))))
0a688fd0
RS
623 ;; Get the index
624 (setq imenu--index-alist
625 (save-excursion
626 (funcall imenu-create-index-function))))
627 (or imenu--index-alist
628 (error "No items suitable for an index found in this buffer."))
629 ;; Add a rescan option to the index.
630 (cons imenu--rescan-item imenu--index-alist))
5d3b0f18
RS
631;;;
632;;; Find all markers in alist and makes
633;;; them point nowhere.
634;;;
635(defun imenu--cleanup (&optional alist)
636 ;; Sets the markers in imenu--index-alist
637 ;; point nowhere.
638 ;; if alist is provided use that list.
4818d210
RS
639 (or alist
640 (setq alist imenu--index-alist))
641 (and alist
7804cd27 642 (mapcar
5d3b0f18
RS
643 (function
644 (lambda (item)
645 (cond
646 ((markerp (cdr item))
647 (set-marker (cdr item) nil))
4818d210 648 ((consp (cdr item))
5d3b0f18 649 (imenu--cleanup (cdr item))))))
4818d210 650 alist)
615b306c
KH
651 t))
652
2d24227e
RS
653(defun imenu--create-keymap-2 (alist counter)
654 (let ((map nil))
655 (mapcar
656 (function
657 (lambda (item)
658 (cond
659 ((listp (cdr item))
660 (append (list (incf counter) (car item) 'keymap (car item))
661 (imenu--create-keymap-2 (cdr item) (+ counter 10))))
662 (t
663 (let ((end (cons '(nil) t)))
664 (cons (car item)
665 (cons (car item) end))))
666 )))
667 alist)))
668
669(defun imenu--create-keymap-1 (title alist)
670 (append (list 'keymap title) (imenu--create-keymap-2 alist 0)))
671
672
673(defun imenu--in-alist (str alist)
674 "Check whether the string STR is contained in multi-level ALIST."
675 (let (elt head tail res)
676 (setq res nil)
677 (while alist
678 (setq elt (car alist)
679 tail (cdr elt)
680 alist (cdr alist)
681 head (car elt))
682 (if (string= str head)
683 (setq alist nil res elt)
684 (if (and (listp tail)
685 (setq res (imenu--in-alist str tail)))
686 (setq alist nil))))
687 res))
688
0a688fd0
RS
689(defun imenu-default-create-index-function ()
690 "*Wrapper for index searching functions.
691
692Moves point to end of buffer and then repeatedly calls
68e01f5a 693`imenu-prev-index-position-function' and `imenu-extract-index-name-function'.
0a688fd0 694Their results are gathered into an index alist."
3e062f78
RS
695 ;; These should really be done by setting imenu-create-index-function
696 ;; in these major modes. But save that change for later.
615b306c
KH
697 (cond ((and (fboundp imenu-prev-index-position-function)
698 (fboundp imenu-extract-index-name-function))
3e062f78 699 (let ((index-alist '())
615b306c 700 prev-pos name)
3e062f78 701 (goto-char (point-max))
7dea4e70 702 (imenu-progress-message prev-pos 0 t)
3e062f78
RS
703 ;; Search for the function
704 (while (funcall imenu-prev-index-position-function)
7dea4e70 705 (imenu-progress-message prev-pos nil t)
3e062f78
RS
706 (save-excursion
707 (setq name (funcall imenu-extract-index-name-function)))
708 (and (stringp name)
709 (push (cons name (point)) index-alist)))
7dea4e70 710 (imenu-progress-message prev-pos 100 t)
615b306c
KH
711 index-alist))
712 ;; Use generic expression if possible.
713 ((and imenu-generic-expression)
714 (imenu--generic-function imenu-generic-expression))
2d24227e
RS
715 ;; Use supplied example functions or expressions
716 ((assq major-mode imenu--scanning-method-alist)
717 (let ((method (cadr (assq major-mode imenu--scanning-method-alist))))
718 ;; is it a function?
719 (if (fboundp method)
720 ;; ... then call it
721 (funcall method)
722 ;; ...otherwise pass the pattern to imenu--generic-function
723 (imenu--generic-function (eval method)))))
615b306c
KH
724 (t
725 (error "The mode \"%s\" does not take full advantage of imenu.el yet."
726 mode-name))))
0a688fd0
RS
727
728(defun imenu--replace-spaces (name replacement)
729 ;; Replace all spaces in NAME with REPLACEMENT.
730 ;; That second argument should be a string.
731 (mapconcat
732 (function
733 (lambda (ch)
734 (if (char-equal ch ?\ )
735 replacement
736 (char-to-string ch))))
737 name
738 ""))
739
740(defun imenu--flatten-index-alist (index-alist &optional concat-names prefix)
741 ;; Takes a nested INDEX-ALIST and returns a flat index alist.
742 ;; If optional CONCAT-NAMES is non-nil, then a nested index has its
743 ;; name and a space concatenated to the names of the children.
744 ;; Third argument PREFIX is for internal use only.
745 (mapcan
746 (function
747 (lambda (item)
748 (let* ((name (car item))
749 (pos (cdr item))
750 (new-prefix (and concat-names
751 (if prefix
752 (concat prefix imenu-level-separator name)
753 name))))
754 (cond
5d3b0f18 755 ((or (markerp pos) (numberp pos))
0a688fd0
RS
756 (list (cons new-prefix pos)))
757 (t
758 (imenu--flatten-index-alist pos new-prefix))))))
759 index-alist))
760
615b306c
KH
761;;;
762;;; Generic index gathering function.
763;;;
2d24227e
RS
764
765(defun imenu--generic-function (patterns)
766;; Built on some ideas that Erik Naggum <erik@naggum.no> once posted
767;; to comp.emacs
768 "Return an index of the current buffer as an alist.
769
770PATTERN is an alist with elements that look like this: (MENU-TITLE
771REGEXP INDEX).
772
773MENU-TITLE is a string used as the title for the submenu or nil if the
774entries are not nested.
775
776REGEXP is a regexp that should match a construct in the buffer that is
777to be displayed in the menu i.e. function or variable definitions,
778etc. It contains a substring which is the name to appear in the
779menu. See the info section on Regexps for more information.
780
781INDEX points to the substring in REGEXP that contains the name (of the
782function, variable or type) that is to appear in the menu.
783
784For emacs-lisp-mode for example PATTERN would look like:
785
786'((nil \"^\\s-*(def\\(un\\|subst\\|macro\\|advice\\)\\s-+\\([-A-Za-z0-9]+\\)\" 2)
787 (\"*Vars*\" \"^\\s-*(def\\(var\\|const\\)\\s-+\\([-A-Za-z0-9]+\\)\" 2)
788 (\"*Types*\" \"^\\s-*(def\\(type\\|struct\\|class\\|ine-condition\\)\\s-+\\([-A-Za-z0-9]+\\)\" 2))'
789
790Returns an index of the current buffer as an alist. The elements in
791the alist look like: (INDEX-NAME . INDEX-POSITION). They may also be
792nested index lists like (INDEX-NAME . INDEX-ALIST) depending on
793pattern.
794
795\(imenu--generic-function PATTERN\)."
796
797 (let ((index-alist (list 'dummy))
798 (found nil)
799 (global-regexp
800 (concat "\\("
801 (mapconcat
802 (function (lambda (pattern) (identity (cadr pattern))))
803 patterns "\\)\\|\\(")
804 "\\)"))
805 prev-pos)
806
615b306c
KH
807 (goto-char (point-max))
808 (imenu-progress-message prev-pos 0 t)
2d24227e
RS
809 (save-match-data
810 (while (re-search-backward global-regexp nil t)
811 (imenu-progress-message prev-pos nil t)
812 (setq found nil)
813 (save-excursion
814 (goto-char (match-beginning 0))
815 (mapcar
816 (function
817 (lambda (pat)
818 (let ((menu-title (car pat))
819 (regexp (cadr pat))
820 (index (caddr pat)))
821 (if (and (not found) ; Only allow one entry;
822 (looking-at regexp))
823 (let ((beg (match-beginning index))
824 (end (match-end index)))
825 (setq found t)
826 (push
827 (cons (buffer-substring beg end) beg)
828 (cdr
829 (or (if (not (stringp menu-title)) index-alist)
830 (assoc
831 (imenu-create-submenu-name menu-title)
832 index-alist)
833 (car (push
834 (cons
835 (imenu-create-submenu-name menu-title)
836 '())
837 index-alist))))))))))
838 patterns))))
839 (imenu-progress-message prev-pos 100 t)
840 (delete 'dummy index-alist)))
615b306c 841
0a688fd0
RS
842;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
843;;;
844;;; The main functions for this package!
845;;;
846;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
847
848(defun imenu--completion-buffer (index-alist &optional prompt)
849 "Let the user select from INDEX-ALIST in a completion buffer with PROMPT.
850
851Returns t for rescan and otherwise a position number."
852 ;; Create a list for this buffer only when needed.
853 (let (name choice
615b306c
KH
854 (prepared-index-alist
855 (mapcar
856 (function
857 (lambda (item)
858 (cons (imenu--replace-spaces (car item) imenu-space-replacement)
859 (cdr item))))
860 index-alist)))
af447694
RS
861 (if (eq imenu-always-use-completion-buffer-p 'never)
862 (setq name (completing-read (or prompt "Index item: ")
863 prepared-index-alist
864 nil t nil 'imenu--history-list))
865 (save-window-excursion
866 ;; Display the completion buffer
867 (with-output-to-temp-buffer "*Completions*"
868 (display-completion-list
869 (all-completions "" prepared-index-alist )))
870 (let ((minibuffer-setup-hook
871 (function (lambda ()
872 (let ((buffer (current-buffer)))
873 (save-excursion
874 (set-buffer "*Completions*")
875 (setq completion-reference-buffer buffer)))))))
876 ;; Make a completion question
877 (setq name (completing-read (or prompt "Index item: ")
878 prepared-index-alist
879 nil t nil 'imenu--history-list)))))
3e062f78
RS
880 (cond ((not (stringp name))
881 nil)
882 ((string= name (car imenu--rescan-item))
883 t)
884 (t
885 (setq choice (assoc name prepared-index-alist))
886 (if (listp (cdr choice))
887 (imenu--completion-buffer (cdr choice) prompt)
888 choice)))))
68e01f5a 889
0a688fd0
RS
890(defun imenu--mouse-menu (index-alist event &optional title)
891 "Let the user select from a buffer index from a mouse menu.
892
893INDEX-ALIST is the buffer index and EVENT is a mouse event.
894
895Returns t for rescan and otherwise a position number."
896 (let* ((menu (imenu--split-menu
897 (if imenu-sort-function
0ee4f8ad
RS
898 (sort
899 (let ((res nil)
900 (oldlist index-alist))
901 ;; Copy list method from the cl package `copy-list'
902 (while (consp oldlist) (push (pop oldlist) res))
903 (prog1 (nreverse res) (setcdr res oldlist)))
904 imenu-sort-function)
0a688fd0
RS
905 index-alist)
906 (or title (buffer-name))))
907 position)
2d24227e
RS
908 (and imenu-use-keymap-menu
909 (setq menu (imenu--create-keymap-1 (car menu)
910 (if (< 1 (length (cdr menu)))
911 (cdr menu)
912 (cdr (cadr menu))))))
0a688fd0 913 (setq position (x-popup-menu event menu))
2d24227e
RS
914 (if imenu-use-keymap-menu
915 (progn
916 (cond
917 ((and (listp position)
918 (numberp (car position))
919 (stringp (nth (1- (length position)) position)))
920 (setq position (nth (1- (length position)) position)))
921 ((and (stringp (car position))
922 (null (cdr position)))
923 (setq position (car position))))))
0a688fd0
RS
924 (cond
925 ((eq position nil)
926 position)
26d6bb60 927 ((listp position)
0a688fd0
RS
928 (imenu--mouse-menu position event
929 (if title
930 (concat title imenu-level-separator
931 (car (rassq position index-alist)))
932 (car (rassq position index-alist)))))
2d24227e
RS
933 ((stringp position)
934 (or (string= position (car imenu--rescan-item))
935 (imenu--in-alist position index-alist)))
936 ((or (= position (cdr imenu--rescan-item))
937 (and (stringp position)
938 (string= position (car imenu--rescan-item))))
0a688fd0
RS
939 t)
940 (t
941 (rassq position index-alist)))))
942
26d6bb60 943(defun imenu-choose-buffer-index (&optional prompt alist)
0a688fd0
RS
944 "Let the user select from a buffer index and return the chosen index.
945
946If the user originally activated this function with the mouse, a mouse
0a688fd0
RS
947menu is used. Otherwise a completion buffer is used and the user is
948prompted with PROMPT.
949
26d6bb60
RS
950If you call this function with index alist ALIST, then it lets the user
951select from ALIST.
952
0ee4f8ad 953With no index alist ALIST, it calls `imenu--make-index-alist' to
26d6bb60
RS
954create the index alist.
955
0ee4f8ad 956If `imenu-always-use-completion-buffer-p' is non-nil, then the
0a688fd0
RS
957completion buffer is always used, no matter if the mouse was used or
958not.
959
960The returned value is on the form (INDEX-NAME . INDEX-POSITION)."
961 (let (index-alist
7dea4e70 962 (mouse-triggered (listp last-nonmenu-event))
0a688fd0
RS
963 (result t) )
964 ;; If selected by mouse, see to that the window where the mouse is
965 ;; really is selected.
966 (and mouse-triggered
4cde72b4 967 (not (equal last-nonmenu-event '(menu-bar)))
7dea4e70 968 (let ((window (posn-window (event-start last-nonmenu-event))))
4a840d8b 969 (or (framep window) (null window) (select-window window))))
0a688fd0
RS
970 ;; Create a list for this buffer only when needed.
971 (while (eq result t)
26d6bb60 972 (setq index-alist (if alist alist (imenu--make-index-alist)))
0a688fd0
RS
973 (setq result
974 (if (and mouse-triggered
975 (not imenu-always-use-completion-buffer-p))
7dea4e70 976 (imenu--mouse-menu index-alist last-nonmenu-event)
0a688fd0
RS
977 (imenu--completion-buffer index-alist prompt)))
978 (and (eq result t)
5d3b0f18 979 (imenu--cleanup)
0a688fd0
RS
980 (setq imenu--index-alist nil)))
981 result))
982
2d24227e 983;;;###autoload
5d3b0f18
RS
984(defun imenu-add-to-menubar (name)
985 "Adds an \"imenu\" entry to the menubar for the
986current local keymap.
987NAME is the string naming the menu to be added.
988See 'imenu' for more information."
989 (interactive "sMenu name: ")
990 (and window-system
991 (define-key (current-local-map) [menu-bar index]
992 (cons name 'imenu))))
993
68e01f5a
RS
994;;;###autoload
995(defun imenu ()
996 "Jump to a place in the buffer chosen using a buffer menu or mouse menu.
0ee4f8ad 997See `imenu-choose-buffer-index' for more information."
0a688fd0 998 (interactive)
056ab244
RS
999 (let ((index-item (save-restriction
1000 (widen)
1001 (imenu-choose-buffer-index))))
0a688fd0
RS
1002 (and index-item
1003 (progn
1004 (push-mark)
5d3b0f18
RS
1005 (cond
1006 ((markerp (cdr index-item))
056ab244
RS
1007 (if (or ( > (marker-position (cdr index-item)) (point-min))
1008 ( < (marker-position (cdr index-item)) (point-max)))
1009 ;; widen if outside narrowing
1010 (widen))
5d3b0f18
RS
1011 (goto-char (marker-position (cdr index-item))))
1012 (t
056ab244
RS
1013 (if (or ( > (cdr index-item) (point-min))
1014 ( < (cdr index-item) (point-max)))
1015 ;; widen if outside narrowing
1016 (widen))
5d3b0f18
RS
1017 (goto-char (cdr index-item))))))))
1018
0a688fd0
RS
1019(provide 'imenu)
1020
1021;;; imenu.el ends here