imenu.el 36.1 KB
Newer Older
1
;;; imenu.el --- framework for mode-specific buffer indexes
Richard M. Stallman's avatar
Richard M. Stallman committed
2

Glenn Morris's avatar
Glenn Morris committed
3
;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 2001, 2002, 2003, 2004,
4
;;   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
5 6 7

;; Author: Ake Stenhoff <etxaksf@aom.ericsson.se>
;;         Lars Lindberg <lli@sypro.cap.se>
Richard M. Stallman's avatar
Richard M. Stallman committed
8
;; Maintainer: FSF
Richard M. Stallman's avatar
Richard M. Stallman committed
9
;; Created: 8 Feb 1994
Dan Nicolaescu's avatar
Dan Nicolaescu committed
10
;; Keywords: tools convenience
Erik Naggum's avatar
Erik Naggum committed
11 12 13 14

;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
Richard M. Stallman's avatar
Richard M. Stallman committed
15
;; it under the terms of the GNU General Public License as published by
16
;; the Free Software Foundation; either version 3, or (at your option)
Richard M. Stallman's avatar
Richard M. Stallman committed
17
;; any later version.
Erik Naggum's avatar
Erik Naggum committed
18 19

;; GNU Emacs is distributed in the hope that it will be useful,
Richard M. Stallman's avatar
Richard M. Stallman committed
20 21 22
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
Erik Naggum's avatar
Erik Naggum committed
23

Richard M. Stallman's avatar
Richard M. Stallman committed
24
;; You should have received a copy of the GNU General Public License
Erik Naggum's avatar
Erik Naggum committed
25
;; along with GNU Emacs; see the file COPYING.  If not, write to the
Lute Kamstra's avatar
Lute Kamstra committed
26 27
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
Richard M. Stallman's avatar
Richard M. Stallman committed
28 29

;;; Commentary:
Erik Naggum's avatar
Erik Naggum committed
30

Richard M. Stallman's avatar
Richard M. Stallman committed
31 32 33 34 35
;; Purpose of this package:
;;   To present a framework for mode-specific buffer indexes.
;;   A buffer index is an alist of names and buffer positions.
;;   For instance all functions in a C-file and their positions.
;;
36 37
;;   It is documented in the Emacs Lisp manual.
;;
Richard M. Stallman's avatar
Richard M. Stallman committed
38 39 40 41 42 43 44 45
;; How it works:

;;   A mode-specific function is called to generate the index.  It is
;;   then presented to the user, who can choose from this index.
;;
;;   The package comes with a set of example functions for how to
;;   utilize this package.

46 47 48 49
;;   There are *examples* for index gathering functions/regular
;;   expressions for C/C++ and Lisp/Emacs Lisp but it is easy to
;;   customize for other modes.  A function for jumping to the chosen
;;   index position is also supplied.
Richard M. Stallman's avatar
Richard M. Stallman committed
50

51 52
;;; History:
;;  Thanks go to
Richard M. Stallman's avatar
Richard M. Stallman committed
53 54
;;  [simon] - Simon Leinen simon@lia.di.epfl.ch
;;  [dean] - Dean Andrews ada@unison.com
55
;;  [alon] - Alon Albert al@mercury.co.il
56
;;  [greg] - Greg Thompson gregt@porsche.visix.COM
57
;;  [wolfgang] - Wolfgang Bangerth zcg51122@rpool1.rus.uni-stuttgart.de
58
;;  [kai] - Kai Grossjohann grossjoh@linus.informatik.uni-dortmund.de
59
;;  [david] - David M. Smith dsmith@stats.adelaide.edu.au
60 61 62
;;  [christian] - Christian Egli Christian.Egli@hcsd.hac.com
;;  [karl] - Karl Fogel kfogel@floss.life.uiuc.edu

63
;;; Code:
Erik Naggum's avatar
Erik Naggum committed
64

65
(eval-when-compile (require 'cl))
Richard M. Stallman's avatar
Richard M. Stallman committed
66 67 68 69 70 71

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Customizable variables
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
72

73 74 75
(defgroup imenu nil
  "Mode-specific buffer indexes."
  :group 'matching
76
  :group 'frames
Dan Nicolaescu's avatar
Dan Nicolaescu committed
77
  :group 'convenience
78
  :link '(custom-manual "(elisp)Imenu"))
79 80

(defcustom imenu-use-markers t
81
  "*Non-nil means use markers instead of integers for Imenu buffer positions.
82 83 84

Setting this to nil makes Imenu work a little faster but editing the
buffer will make the generated index positions wrong.
85

86 87 88 89
This might not yet be honored by all index-building functions."
  :type 'boolean
  :group 'imenu)

90

91 92
(defcustom imenu-max-item-length 60
  "*If a number, truncate Imenu entries to that length."
93 94
  :type '(choice integer
		 (const :tag "Unlimited"))
95
  :group 'imenu)
96

97
(defcustom imenu-auto-rescan nil
98 99 100
  "*Non-nil means Imenu should always rescan the buffers."
  :type 'boolean
  :group 'imenu)
101

102 103
(defcustom imenu-auto-rescan-maxout 60000
  "*Imenu auto-rescan is disabled in buffers larger than this size (in bytes).
104 105 106
This variable is buffer-local."
  :type 'integer
  :group 'imenu)
Richard M. Stallman's avatar
Richard M. Stallman committed
107

108 109
(defvar imenu-always-use-completion-buffer-p nil)
(make-obsolete-variable 'imenu-always-use-completion-buffer-p
110
			'imenu-use-popup-menu "22.1")
111 112 113 114 115 116 117 118 119 120 121

(defcustom imenu-use-popup-menu
  (if imenu-always-use-completion-buffer-p
      (not (eq imenu-always-use-completion-buffer-p 'never))
    'on-mouse)
  "Use a popup menu rather than a minibuffer prompt.
If nil, always use a minibuffer prompt.
If t, always use a popup menu,
If `on-mouse' use a popup menu when `imenu' was invoked with the mouse."
  :type '(choice (const :tag "On Mouse" on-mouse)
		 (const :tag "Never" nil)
122 123
		 (other :tag "Always" t))
  :group 'imenu)
124 125 126 127

(defcustom imenu-eager-completion-buffer
  (not (eq imenu-always-use-completion-buffer-p 'never))
  "If non-nil, eagerly popup the completion buffer."
128 129
  :type 'boolean
  :group 'imenu
130
  :version "22.1")
Richard M. Stallman's avatar
Richard M. Stallman committed
131

132 133 134 135 136 137 138 139
(defcustom imenu-after-jump-hook nil
  "*Hooks called after jumping to a place in the buffer.

Useful things to use here include `reposition-window', `recenter', and
\(lambda () (recenter 0)) to show at top of screen."
  :type 'hook
  :group 'imenu)

140
;;;###autoload
141
(defcustom imenu-sort-function nil
Richard M. Stallman's avatar
Richard M. Stallman committed
142 143 144 145 146 147 148 149
  "*The function to use for sorting the index mouse-menu.

Affects only the mouse index menu.

Set this to nil if you don't want any sorting (faster).
The items in the menu are then presented in the order they were found
in the buffer.

150
Set it to `imenu--sort-by-name' if you want alphabetic sorting.
Richard M. Stallman's avatar
Richard M. Stallman committed
151

152
The function should take two arguments and return t if the first
Richard M. Stallman's avatar
Richard M. Stallman committed
153
element should come before the second.  The arguments are cons cells;
154
\(NAME . POSITION).  Look at `imenu--sort-by-name' for an example."
155
  :type '(choice (const :tag "No sorting" nil)
156
		 (const :tag "Sort by name" imenu--sort-by-name)
157
		 (function :tag "Another function"))
158
  :group 'imenu)
Richard M. Stallman's avatar
Richard M. Stallman committed
159

160 161 162 163
(defcustom imenu-max-items 25
  "*Maximum number of elements in a mouse menu for Imenu."
  :type 'integer
  :group 'imenu)
Richard M. Stallman's avatar
Richard M. Stallman committed
164

165 166 167 168 169 170 171 172 173 174 175
;; No longer used.  KFS 2004-10-27
;; (defcustom imenu-scanning-message "Scanning buffer for index (%3d%%)"
;;   "*Progress message during the index scanning of the buffer.
;; If non-nil, user gets a message during the scanning of the buffer.
;;
;; Relevant only if the mode-specific function that creates the buffer
;; index use `imenu-progress-message', and not useful if that is fast, in
;; which case you might as well set this to nil."
;;   :type '(choice string
;;  		 (const :tag "None" nil))
;;   :group 'imenu)
Richard M. Stallman's avatar
Richard M. Stallman committed
176

177
(defcustom imenu-space-replacement "."
Richard M. Stallman's avatar
Richard M. Stallman committed
178
  "*The replacement string for spaces in index names.
179
Used when presenting the index in a completion buffer to make the
180
names work as tokens."
181
  :type '(choice string (const nil))
182
  :group 'imenu)
Richard M. Stallman's avatar
Richard M. Stallman committed
183

184
(defcustom imenu-level-separator ":"
Richard M. Stallman's avatar
Richard M. Stallman committed
185 186
  "*The separator between index names of different levels.
Used for making mouse-menu titles and for flattening nested indexes
187 188 189
with name concatenation."
  :type 'string
  :group 'imenu)
Richard M. Stallman's avatar
Richard M. Stallman committed
190

191
;;;###autoload
192
(defvar imenu-generic-expression nil
193 194
  "The regex pattern to use for creating a buffer index.

195 196 197
If non-nil this pattern is passed to `imenu--generic-function' to
create a buffer index.  Look there for the documentation of this
pattern's structure.
198

199
For example, see the value of `fortran-imenu-generic-expression' used by
200 201 202
`fortran-mode' with `imenu-syntax-alist' set locally to give the
characters which normally have \"symbol\" syntax \"word\" syntax
during matching.")
203

204
;;;###autoload
205
(make-variable-buffer-local 'imenu-generic-expression)
206

Richard M. Stallman's avatar
Richard M. Stallman committed
207 208
;;;; Hooks

209
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
210
(defvar imenu-create-index-function 'imenu-default-create-index-function
211
  "The function to use for creating an index alist of the current buffer.
Richard M. Stallman's avatar
Richard M. Stallman committed
212

213 214 215
It should be a function that takes no arguments and returns
an index alist of the current buffer.  The function is
called within a `save-excursion'.
216

217
See `imenu--index-alist' for the format of the buffer index alist.")
218
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
219 220
(make-variable-buffer-local 'imenu-create-index-function)

221
;;;###autoload
222
(defvar imenu-prev-index-position-function 'beginning-of-defun
Richard M. Stallman's avatar
Richard M. Stallman committed
223 224
  "Function for finding the next index position.

225 226
If `imenu-create-index-function' is set to
`imenu-default-create-index-function', then you must set this variable
Richard M. Stallman's avatar
Richard M. Stallman committed
227 228 229 230
to a function that will find the next index, looking backwards in the
file.

The function should leave point at the place to be connected to the
231
index and it should return nil when it doesn't find another index.")
232
;;;###autoload
233
(make-variable-buffer-local 'imenu-prev-index-position-function)
Richard M. Stallman's avatar
Richard M. Stallman committed
234

235
;;;###autoload
236
(defvar imenu-extract-index-name-function nil
237
  "Function for extracting the index item name, given a position.
238 239 240

This function is called after `imenu-prev-index-position-function'
finds a position for an index item, with point at that position.
241
It should return the name for that index item.")
242
;;;###autoload
243
(make-variable-buffer-local 'imenu-extract-index-name-function)
Richard M. Stallman's avatar
Richard M. Stallman committed
244

245 246 247 248 249 250 251 252 253 254
;;;###autoload
(defvar imenu-name-lookup-function nil
  "Function to compare string with index item.

This function will be called with two strings, and should return
non-nil if they match.

If nil, comparison is done with `string='.
Set this to some other function for more advanced comparisons,
such as \"begins with\" or \"name matches and number of
255
arguments match\".")
256 257 258
;;;###autoload
(make-variable-buffer-local 'imenu-name-lookup-function)

259
;;;###autoload
260 261 262
(defvar imenu-default-goto-function 'imenu-default-goto-function
  "The default function called when selecting an Imenu item.
The function in this variable is called when selecting a normal index-item.")
263
;;;###autoload
264 265 266
(make-variable-buffer-local 'imenu-default-goto-function)


267 268
(defun imenu--subalist-p (item)
  (and (consp (cdr item)) (listp (cadr item))
269
       (not (eq (car (cadr item)) 'lambda))))
270

271 272 273 274 275
;; Macro to display a progress message.
;; RELPOS is the relative position to display.
;; If RELPOS is nil, then the relative position in the buffer
;; is calculated.
;; PREVPOS is the variable in which we store the last position displayed.
276
(defmacro imenu-progress-message (prevpos &optional relpos reverse)
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292

;; Made obsolete/empty, as computers are now faster than the eye, and
;; it had problems updating the messages correctly, and could shadow
;; more important messages/prompts in the minibuffer.  KFS 2004-10-27.

;;  `(and
;;    imenu-scanning-message
;;    (let ((pos ,(if relpos
;; 		    relpos
;; 		  `(imenu--relative-position ,reverse))))
;;      (if ,(if relpos t
;; 	     `(> pos (+ 5 ,prevpos)))
;; 	  (progn
;; 	    (message imenu-scanning-message pos)
;; 	    (setq ,prevpos pos)))))
)
293 294 295 296 297 298 299 300 301


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; Some examples of functions utilizing the framework of this
;;;; package.
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

302 303 304
;; FIXME: This is the only imenu-example-* definition that's actually used,
;; and it seems to only be used by cperl-mode.el.  We should just move it to
;; cperl-mode.el and remove the rest.
305
(defun imenu-example--name-and-position ()
306 307
  "Return the current/previous sexp and its (beginning) location.
Don't move point."
308 309
  (save-excursion
    (forward-sexp -1)
310 311 312
    ;; [ydi] modified for imenu-use-markers
    (let ((beg (if imenu-use-markers (point-marker) (point)))
	  (end (progn (forward-sexp) (point))))
313
      (cons (buffer-substring beg end)
314
	    beg))))
315 316 317

;;;
;;; Lisp
318
;;;
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346

(defun imenu-example--lisp-extract-index-name ()
  ;; Example of a candidate for `imenu-extract-index-name-function'.
  ;; This will generate a flat index of definitions in a lisp file.
  (save-match-data
    (and (looking-at "(def")
	 (condition-case nil
	     (progn
	       (down-list 1)
	       (forward-sexp 2)
	       (let ((beg (point))
		     (end (progn (forward-sexp -1) (point))))
		 (buffer-substring beg end)))
	   (error nil)))))

(defun imenu-example--create-lisp-index ()
  ;; Example of a candidate for `imenu-create-index-function'.
  ;; It will generate a nested index of definitions.
  (let ((index-alist '())
	(index-var-alist '())
	(index-type-alist '())
	(index-unknown-alist '())
	prev-pos)
    (goto-char (point-max))
    (imenu-progress-message prev-pos 0)
    ;; Search for the function
    (while (beginning-of-defun)
      (imenu-progress-message prev-pos nil t)
347 348 349
	  (save-match-data
	    (and (looking-at "(def")
		 (save-excursion
350
	       (down-list 1)
351
		   (cond
352
		((looking-at "def\\(var\\|const\\)")
353 354 355
		     (forward-sexp 2)
		     (push (imenu-example--name-and-position)
			   index-var-alist))
356
		((looking-at "def\\(un\\|subst\\|macro\\|advice\\)")
357 358 359
		     (forward-sexp 2)
		     (push (imenu-example--name-and-position)
			   index-alist))
360
		((looking-at "def\\(type\\|struct\\|class\\|ine-condition\\)")
361
		     (forward-sexp 2)
362
 		 (if (= (char-after (1- (point))) ?\))
363
			 (progn
364
 		       (forward-sexp -1)
365
			   (down-list 1)
366
 		       (forward-sexp 1)))
367 368 369 370 371
		     (push (imenu-example--name-and-position)
			   index-type-alist))
		    (t
		     (forward-sexp 2)
		     (push (imenu-example--name-and-position)
372 373 374
		       index-unknown-alist)))))))
    (imenu-progress-message prev-pos 100)
    (and index-var-alist
375
	 (push (cons "Variables" index-var-alist)
376 377
	       index-alist))
    (and index-type-alist
378
 	 (push (cons "Types" index-type-alist)
379 380
  	       index-alist))
    (and index-unknown-alist
381
	 (push (cons "Syntax-unknown" index-unknown-alist)
382 383 384 385 386
	       index-alist))
    index-alist))

;; Regular expression to find C functions
(defvar imenu-example--function-name-regexp-c
387
  (concat
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
   "^[a-zA-Z0-9]+[ \t]?"		; type specs; there can be no
   "\\([a-zA-Z0-9_*]+[ \t]+\\)?"	; more than 3 tokens, right?
   "\\([a-zA-Z0-9_*]+[ \t]+\\)?"
   "\\([*&]+[ \t]*\\)?"			; pointer
   "\\([a-zA-Z0-9_*]+\\)[ \t]*("	; name
   ))

(defun imenu-example--create-c-index (&optional regexp)
  (let ((index-alist '())
	prev-pos char)
    (goto-char (point-min))
    (imenu-progress-message prev-pos 0)
    ;; Search for the function
    (save-match-data
      (while (re-search-forward
	      (or regexp imenu-example--function-name-regexp-c)
	      nil t)
	(imenu-progress-message prev-pos)
	(backward-up-list 1)
	(save-excursion
	  (goto-char (scan-sexps (point) 1))
	  (setq char (following-char)))
	;; Skip this function name if it is a prototype declaration.
	(if (not (eq char ?\;))
	    (push (imenu-example--name-and-position) index-alist))))
    (imenu-progress-message prev-pos 100)
    (nreverse index-alist)))

416

Richard M. Stallman's avatar
Richard M. Stallman committed
417 418 419 420 421 422 423 424 425 426 427
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Internal variables
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; The item to use in the index for rescanning the buffer.
(defconst imenu--rescan-item '("*Rescan*" . -99))

;; The latest buffer index.
;; Buffer local.
428
(defvar imenu--index-alist nil
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
  "The buffer index alist computed for this buffer in Imenu.

Simple elements in the alist look like (INDEX-NAME . POSITION).
POSITION is the buffer position of the item; to go to the item
is simply to move point to that position.

Special elements look like (INDEX-NAME POSITION FUNCTION ARGUMENTS...).
To \"go to\" a special element means applying FUNCTION
to INDEX-NAME, POSITION, and the ARGUMENTS.

A nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
The function `imenu--subalist-p' tests an element and returns t
if it is a sub-alist.

There is one simple element with negative POSITION; selecting that
444
element recalculates the buffer's index alist.")
445

Richard M. Stallman's avatar
Richard M. Stallman committed
446 447
(make-variable-buffer-local 'imenu--index-alist)

448
(defvar imenu--last-menubar-index-alist nil
449
  "The latest buffer index alist used to update the menu bar menu.")
450

451 452
(make-variable-buffer-local 'imenu--last-menubar-index-alist)

Richard M. Stallman's avatar
Richard M. Stallman committed
453
;; History list for 'jump-to-function-in-buffer'.
454
;; Making this buffer local caused it not to work!
Richard M. Stallman's avatar
Richard M. Stallman committed
455 456 457 458 459 460 461 462 463 464 465
(defvar imenu--history-list nil)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Internal support functions
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;
;;; Sort function
;;; Sorts the items depending on their index name.
466
;;; An item looks like (NAME . POSITION).
Richard M. Stallman's avatar
Richard M. Stallman committed
467 468 469 470
;;;
(defun imenu--sort-by-name (item1 item2)
  (string-lessp (car item1) (car item2)))

471 472 473
(defun imenu--sort-by-position (item1 item2)
  (< (cdr item1) (cdr item2)))

Richard M. Stallman's avatar
Richard M. Stallman committed
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
(defun imenu--relative-position (&optional reverse)
  ;; Support function to calculate relative position in buffer
  ;; Beginning of buffer is 0 and end of buffer is 100
  ;; If REVERSE is non-nil then the beginning is 100 and the end is 0.
  (let ((pos (point))
	(total (buffer-size)))
    (and reverse (setq pos (- total pos)))
    (if (> total 50000)
	;; Avoid overflow from multiplying by 100!
	(/ (1- pos) (max (/ total 100) 1))
      (/ (* 100 (1- pos)) (max total 1)))))

;; Split LIST into sublists of max length N.
;; Example (imenu--split '(1 2 3 4 5 6 7 8) 3)-> '((1 2 3) (4 5 6) (7 8))
(defun imenu--split (list n)
  (let ((remain list)
	(result '())
	(sublist '())
	(i 0))
    (while remain
      (push (pop remain) sublist)
      (incf i)
      (and (= i n)
	   ;; We have finished a sublist
	   (progn (push (nreverse sublist) result)
		  (setq i 0)
		  (setq sublist '()))))
    ;; There might be a sublist (if the length of LIST mod n is != 0)
    ;; that has to be added to the result list.
    (and sublist
	 (push (nreverse sublist) result))
    (nreverse result)))

507 508
;;; Split the alist MENULIST into a nested alist, if it is long enough.
;;; In any case, add TITLE to the front of the alist.
Richard M. Stallman's avatar
Richard M. Stallman committed
509
(defun imenu--split-menu (menulist title)
510 511 512 513 514
  (let (keep-at-top tail)
    (if (memq imenu--rescan-item menulist)
	(setq keep-at-top (cons imenu--rescan-item nil)
	      menulist (delq imenu--rescan-item menulist)))
    (setq tail menulist)
515
    (dolist (item tail)
516 517 518
      (when (imenu--subalist-p item)
	(push item keep-at-top)
	(setq menulist (delq item menulist))))
519
    (if imenu-sort-function
520
	(setq menulist (sort (copy-sequence menulist) imenu-sort-function)))
521
    (if (> (length menulist) imenu-max-items)
522 523 524 525 526
	(setq menulist
	      (mapcar
	       (lambda (menu)
		 (cons (format "From: %s" (caar menu)) menu))
	       (imenu--split menulist imenu-max-items))))
527 528
    (cons title
	  (nconc (nreverse keep-at-top) menulist))))
529 530 531 532

;;; Split up each long alist that are nested within ALIST
;;; into nested alists.
(defun imenu--split-submenus (alist)
533 534 535 536 537 538 539
  (mapcar (function
	   (lambda (elt)
	     (if (and (consp elt)
		      (stringp (car elt))
		      (listp (cdr elt)))
		 (imenu--split-menu (cdr elt) (car elt))
	       elt)))
540
	  alist))
Richard M. Stallman's avatar
Richard M. Stallman committed
541

542 543
;;; Truncate all strings in MENULIST to imenu-max-item-length
(defun imenu--truncate-items (menulist)
544 545 546 547 548
  (mapcar (function
	   (lambda (item)
	     (cond
	      ((consp (cdr item))
	       (imenu--truncate-items (cdr item)))
549 550 551 552
	      ;; truncate if necessary
	      ((and (numberp imenu-max-item-length)
		    (> (length (car item)) imenu-max-item-length))
	       (setcar item (substring (car item) 0 imenu-max-item-length))))))
553
	  menulist))
554 555


556
(defun imenu--make-index-alist (&optional noerror)
557 558
  "Create an index alist for the definitions in the current buffer.
This works by using the hook function `imenu-create-index-function'.
559 560 561
Report an error if the list is empty unless NOERROR is supplied and
non-nil.

562
See `imenu--index-alist' for the format of the index alist."
563 564 565 566
  (or (and imenu--index-alist
	   (or (not imenu-auto-rescan)
	       (and imenu-auto-rescan
		    (> (buffer-size)  imenu-auto-rescan-maxout))))
567 568 569 570 571 572 573 574
      ;; Get the index; truncate if necessary
      (progn
	(setq imenu--index-alist
	      (save-excursion
		(save-restriction
		  (widen)
		  (funcall imenu-create-index-function))))
	(imenu--truncate-items imenu--index-alist)))
575
  (or imenu--index-alist noerror
576
      (error "No items suitable for an index found in this buffer"))
577 578
  (or imenu--index-alist
      (setq imenu--index-alist (list nil)))
Richard M. Stallman's avatar
Richard M. Stallman committed
579 580
  ;; Add a rescan option to the index.
  (cons imenu--rescan-item imenu--index-alist))
581

582 583
;;; Find all markers in alist and makes
;;; them point nowhere.
584 585 586 587
;;; The top-level call uses nil as the argument;
;;; non-nil arguments are in recursivecalls.
(defvar imenu--cleanup-seen)

588
(defun imenu--cleanup (&optional alist)
589
  ;; If alist is provided use that list.
590 591 592 593 594 595
  ;; If not, empty the table of lists already seen
  ;; and use imenu--index-alist.
  (if alist
      (setq imenu--cleanup-seen (cons alist imenu--cleanup-seen))
    (setq alist imenu--index-alist imenu--cleanup-seen (list alist)))

596
  (and alist
597 598 599 600 601 602 603 604 605
       (mapc
	(lambda (item)
	  (cond
	   ((markerp (cdr item))
	    (set-marker (cdr item) nil))
	   ;; Don't process one alist twice.
	   ((memq (cdr item) imenu--cleanup-seen))
	   ((imenu--subalist-p item)
	    (imenu--cleanup (cdr item)))))
606
	alist)
607 608
       t))

609 610 611 612 613 614 615 616 617 618 619 620
(defun imenu--create-keymap (title alist &optional cmd)
  (list* 'keymap title
	 (mapcar
	  (lambda (item)
	    (list* (car item) (car item)
		   (cond
		    ((imenu--subalist-p item)
		     (imenu--create-keymap (car item) (cdr item) cmd))
		    (t
		     `(lambda () (interactive)
			,(if cmd `(,cmd ',item) (list 'quote item)))))))
	  alist)))
621 622 623 624 625 626

(defun imenu--in-alist (str alist)
  "Check whether the string STR is contained in multi-level ALIST."
  (let (elt head tail res)
    (setq res nil)
    (while alist
627
      (setq elt (car alist)
628
	    tail (cdr elt)
629 630
	    alist (cdr alist)
	    head (car elt))
631 632 633 634 635 636 637 638 639
      ;; A nested ALIST element looks like
      ;;   (INDEX-NAME (INDEX-NAME . INDEX-POSITION) ...)
      ;; while a bottom-level element looks like
      ;;   (INDEX-NAME . INDEX-POSITION)
      ;; We are only interested in the bottom-level elements, so we need to
      ;; recurse if TAIL is a list.
      (cond ((listp tail)
	     (if (setq res (imenu--in-alist str tail))
		 (setq alist nil)))
640 641 642
	    ((if imenu-name-lookup-function
                 (funcall imenu-name-lookup-function str head)
               (string= str head))
643
	     (setq alist nil res elt))))
644 645
    res))

646
(defvar imenu-syntax-alist nil
647
  "Alist of syntax table modifiers to use while in `imenu--generic-function'.
648 649

The car of the assocs may be either a character or a string and the
Glenn Morris's avatar
Glenn Morris committed
650
cdr is a syntax description appropriate for `modify-syntax-entry'.  For
651 652 653
a string, all the characters in the string get the specified syntax.

This is typically used to give word syntax to characters which
Dave Love's avatar
Dave Love committed
654
normally have symbol syntax to simplify `imenu-expression'
655
and speed-up matching.")
656
;;;###autoload
657 658
(make-variable-buffer-local 'imenu-syntax-alist)

Richard M. Stallman's avatar
Richard M. Stallman committed
659
(defun imenu-default-create-index-function ()
660
  "*Default function to create an index alist of the current buffer.
Richard M. Stallman's avatar
Richard M. Stallman committed
661

662
The most general method is to move point to end of buffer, then repeatedly call
663
`imenu-prev-index-position-function' and `imenu-extract-index-name-function'.
664 665 666 667 668
All the results returned by the latter are gathered into an index alist.
This method is used if those two variables are non-nil.

The alternate method, which is the one most often used, is to call
`imenu--generic-function' with `imenu-generic-expression' as argument."
669 670
  ;; These should really be done by setting imenu-create-index-function
  ;; in these major modes.  But save that change for later.
671 672
  (cond ((and imenu-prev-index-position-function
	      imenu-extract-index-name-function)
673
	 (let ((index-alist '())
674
	       prev-pos name)
675
	   (goto-char (point-max))
676
	   (imenu-progress-message prev-pos 0 t)
677
	   ;; Search for the function
678
	   (while (funcall imenu-prev-index-position-function)
679
	     (imenu-progress-message prev-pos nil t)
680 681 682
	     (save-excursion
	       (setq name (funcall imenu-extract-index-name-function)))
	     (and (stringp name)
683 684 685
 		  ;; [ydi] updated for imenu-use-markers
		  (push (cons name (if imenu-use-markers (point-marker) (point)))
			index-alist)))
686
	   (imenu-progress-message prev-pos 100 t)
687 688 689
	   index-alist))
	;; Use generic expression if possible.
	((and imenu-generic-expression)
690
	 (imenu--generic-function imenu-generic-expression))
691
	(t
692
	 (error "This buffer cannot use `imenu-default-create-index-function'"))))
Richard M. Stallman's avatar
Richard M. Stallman committed
693

694 695 696
;;;
;;; Generic index gathering function.
;;;
697

698 699 700
(defvar imenu-case-fold-search t
  "Defines whether `imenu--generic-function' should fold case when matching.

701
This variable should be set (only) by initialization code
702 703
for modes which use `imenu--generic-function'.  If it is not set, but
`font-lock-defaults' is set, then font-lock's setting is used.")
704
;;;###autoload
705 706
(make-variable-buffer-local 'imenu-case-fold-search)

707 708
;; This function can be called with quitting disabled,
;; so it needs to be careful never to loop!
709
(defun imenu--generic-function (patterns)
710
  "Return an index alist of the current buffer based on PATTERNS.
711

712
PATTERNS is an alist with elements that look like this:
713
 (MENU-TITLE REGEXP INDEX)
714 715
or like this:
 (MENU-TITLE REGEXP INDEX FUNCTION ARGUMENTS...)
716 717
with zero or more ARGUMENTS.  The former format creates a simple
element in the index alist when it matches; the latter creates a
718 719
special element of the form (INDEX-NAME POSITION-MARKER FUNCTION
ARGUMENTS...) with FUNCTION and ARGUMENTS copied from PATTERNS.
720 721 722 723 724 725 726 727 728 729

MENU-TITLE is a string used as the title for the submenu or nil
if the entries are not nested.

REGEXP is a regexp that should match a construct in the buffer
that is to be displayed in the menu; i.e., function or variable
definitions, etc.  It contains a substring which is the name to
appear in the menu.  See the info section on Regexps for more
information.  REGEXP may also be a function, called without
arguments.  It is expected to search backwards.  It shall return
730
true and set `match-data' if it finds another element.
731 732 733 734

INDEX points to the substring in REGEXP that contains the
name (of the function, variable or type) that is to appear in the
menu.
735

736 737 738
The variable `imenu-case-fold-search' determines whether or not the
regexp matches are case sensitive, and `imenu-syntax-alist' can be
used to alter the syntax table for the search.
739

740
See `lisp-imenu-generic-expression' for an example of PATTERNS.
741

742
Returns an index of the current buffer as an alist.  The elements in
743 744 745 746
the alist look like:
 (INDEX-NAME . INDEX-POSITION)
or like:
 (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...)
747
They may also be nested index alists like:
748 749
 (INDEX-NAME . INDEX-ALIST)
depending on PATTERNS."
750 751

  (let ((index-alist (list 'dummy))
752
	prev-pos
753 754 755 756
        (case-fold-search (if (or (local-variable-p 'imenu-case-fold-search)
				  (not (local-variable-p 'font-lock-defaults)))
			      imenu-case-fold-search
			    (nth 2 font-lock-defaults)))
757 758 759 760
        (old-table (syntax-table))
        (table (copy-syntax-table (syntax-table)))
        (slist imenu-syntax-alist))
    ;; Modify the syntax table used while matching regexps.
761
    (dolist (syn slist)
762
      ;; The character(s) to modify may be a single char or a string.
763 764
      (if (numberp (car syn))
	  (modify-syntax-entry (car syn) (cdr syn) table)
765 766 767
        (mapc (lambda (c)
                (modify-syntax-entry c (cdr syn) table))
              (car syn))))
768 769
    (goto-char (point-max))
    (imenu-progress-message prev-pos 0 t)
770 771 772
    (unwind-protect			; for syntax table
	(save-match-data
	  (set-syntax-table table)
773

774 775
	  ;; map over the elements of imenu-generic-expression
	  ;; (typically functions, variables ...)
776 777 778 779 780
	  (dolist (pat patterns)
	    (let ((menu-title (car pat))
		  (regexp (nth 1 pat))
		  (index (nth 2 pat))
		  (function (nth 3 pat))
781
		  (rest (nthcdr 4 pat))
782
		  start beg)
783 784
	      ;; Go backwards for convenience of adding items in order.
	      (goto-char (point-max))
785 786 787
	      (while (and (if (functionp regexp)
			      (funcall regexp)
			    (re-search-backward regexp nil t))
788 789 790
			  ;; Exit the loop if we get an empty match,
			  ;; because it means a bad regexp was specified.
			  (not (= (match-beginning 0) (match-end 0))))
791
		(setq start (point))
792
		;; Record the start of the line in which the match starts.
793
		;; That's the official position of this definition.
794 795 796
		(goto-char (match-beginning index))
		(beginning-of-line)
		(setq beg (point))
797 798 799 800 801 802
		(imenu-progress-message prev-pos nil t)
		;; Add this sort of submenu only when we've found an
		;; item for it, avoiding empty, duff menus.
		(unless (assoc menu-title index-alist)
		  (push (list menu-title) index-alist))
		(if imenu-use-markers
803
		    (setq beg (copy-marker beg)))
804 805 806
		(let ((item
		       (if function
			   (nconc (list (match-string-no-properties index)
807
					beg function)
808 809
				  rest)
			 (cons (match-string-no-properties index)
810
			       beg)))
811 812 813 814 815 816
		      ;; This is the desired submenu,
		      ;; starting with its title (or nil).
		      (menu (assoc menu-title index-alist)))
		  ;; Insert the item unless it is already present.
		  (unless (member item (cdr menu))
		    (setcdr menu
817 818 819 820
			    (cons item (cdr menu)))))
		;; Go to the start of the match, to make sure we
		;; keep making progress backwards.
		(goto-char start))))
821
	  (set-syntax-table old-table)))
822
    (imenu-progress-message prev-pos 100 t)
823 824
    ;; Sort each submenu by position.
    ;; This is in case one submenu gets items from two different regexps.
825 826 827
    (dolist (item index-alist)
      (when (listp item)
	(setcdr item (sort (cdr item) 'imenu--sort-by-position))))
828
    (let ((main-element (assq nil index-alist)))
829 830
      (nconc (delq main-element (delq 'dummy index-alist))
	     (cdr main-element)))))
831

Richard M. Stallman's avatar
Richard M. Stallman committed
832 833 834 835 836 837
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; The main functions for this package!
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

838 839 840 841 842 843 844 845 846 847 848 849 850
;; See also info-lookup-find-item
(defun imenu-find-default (guess completions)
  "Fuzzily find an item based on GUESS inside the alist COMPLETIONS."
  (catch 'found
    (let ((case-fold-search t))
      (if (assoc guess completions) guess
	(dolist (re (list (concat "\\`" (regexp-quote guess) "\\'")
			  (concat "\\`" (regexp-quote guess))
			  (concat (regexp-quote guess) "\\'")
			  (regexp-quote guess)))
	  (dolist (x completions)
	    (if (string-match re (car x)) (throw 'found (car x)))))))))

Richard M. Stallman's avatar
Richard M. Stallman committed
851 852 853
(defun imenu--completion-buffer (index-alist &optional prompt)
  "Let the user select from INDEX-ALIST in a completion buffer with PROMPT.

854
Return one of the entries in index-alist or nil."
Richard M. Stallman's avatar
Richard M. Stallman committed
855
  ;; Create a list for this buffer only when needed.
856 857 858
  (let ((name (thing-at-point 'symbol))
	choice
	(prepared-index-alist
859 860 861
	 (if (not imenu-space-replacement) index-alist
	   (mapcar
	    (lambda (item)
862
	      (cons (subst-char-in-string ?\s (aref imenu-space-replacement 0)
863 864 865
					  (car item))
		    (cdr item)))
	    index-alist))))
866 867
    (when (stringp name)
      (setq name (or (imenu-find-default name prepared-index-alist) name)))
868 869 870 871
    (cond (prompt)
	  ((and name (imenu--in-alist name prepared-index-alist))
	   (setq prompt (format "Index item (default %s): " name)))
	  (t (setq prompt "Index item: ")))
872 873 874 875 876 877 878
    (let ((minibuffer-setup-hook minibuffer-setup-hook))
      ;; Display the completion buffer.
      (if (not imenu-eager-completion-buffer)
	  (add-hook 'minibuffer-setup-hook 'minibuffer-completion-help))
      (setq name (completing-read prompt
				  prepared-index-alist
				  nil t nil 'imenu--history-list name)))
879

880 881 882 883 884
    (when (stringp name)
      (setq choice (assoc name prepared-index-alist))
      (if (imenu--subalist-p choice)
	  (imenu--completion-buffer (cdr choice) prompt)
	choice))))
885

Richard M. Stallman's avatar
Richard M. Stallman committed
886 887 888 889 890
(defun imenu--mouse-menu (index-alist event &optional title)
  "Let the user select from a buffer index from a mouse menu.

INDEX-ALIST is the buffer index and EVENT is a mouse event.

891
Returns t for rescan and otherwise an element or subelement of INDEX-ALIST."
892
  (setq index-alist (imenu--split-submenus index-alist))
893
  (let* ((menu (imenu--split-menu index-alist (or title (buffer-name))))
894 895 896 897
	 (map (imenu--create-keymap (car menu)
				    (cdr (if (< 1 (length (cdr menu)))
					     menu
					   (car (cdr menu)))))))
898
    (popup-menu map event)))
Richard M. Stallman's avatar
Richard M. Stallman committed
899

Richard M. Stallman's avatar
Richard M. Stallman committed
900
(defun imenu-choose-buffer-index (&optional prompt alist)
Richard M. Stallman's avatar
Richard M. Stallman committed
901 902 903 904 905 906
  "Let the user select from a buffer index and return the chosen index.

If the user originally activated this function with the mouse, a mouse
menu is used.  Otherwise a completion buffer is used and the user is
prompted with PROMPT.

Richard M. Stallman's avatar
Richard M. Stallman committed
907 908 909
If you call this function with index alist ALIST, then it lets the user
select from ALIST.

910
With no index alist ALIST, it calls `imenu--make-index-alist' to
Richard M. Stallman's avatar
Richard M. Stallman committed
911 912
create the index alist.

913 914
If `imenu-use-popup-menu' is nil, then the completion buffer
is always used, no matter if the mouse was used or not.
Richard M. Stallman's avatar
Richard M. Stallman committed
915

916
The returned value is of the form (INDEX-NAME . INDEX-POSITION)."
Richard M. Stallman's avatar
Richard M. Stallman committed
917
  (let (index-alist
918
	(mouse-triggered (listp last-nonmenu-event))
919
	(result t))
Richard M. Stallman's avatar
Richard M. Stallman committed
920 921 922
    ;; If selected by mouse, see to that the window where the mouse is
    ;; really is selected.
    (and mouse-triggered
923
	 (not (equal last-nonmenu-event '(menu-bar)))
924
	 (let ((window (posn-window (event-start last-nonmenu-event))))
925
	   (or (framep window) (null window) (select-window window))))
Richard M. Stallman's avatar
Richard M. Stallman committed
926 927
    ;; Create a list for this buffer only when needed.
    (while (eq result t)
Richard M. Stallman's avatar
Richard M. Stallman committed
928
      (setq index-alist (if alist alist (imenu--make-index-alist)))
Richard M. Stallman's avatar
Richard M. Stallman committed
929
      (setq result
930 931
	    (if (and imenu-use-popup-menu
		     (or (eq imenu-use-popup-menu t) mouse-triggered))