Commit | Line | Data |
---|---|---|
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 | ||
79 | Non-nil means always display the index in a completion buffer. | |
80 | Nil means display the index as a mouse menu when the mouse was | |
af447694 RS |
81 | used 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 | ||
87 | Affects only the mouse index menu. | |
88 | ||
89 | Set this to nil if you don't want any sorting (faster). | |
90 | The items in the menu are then presented in the order they were found | |
91 | in the buffer. | |
92 | ||
0ee4f8ad | 93 | Set it to `imenu--sort-by-name' if you want alphabetic sorting. |
0a688fd0 RS |
94 | |
95 | The function should take two arguments and return T if the first | |
96 | element 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 | 104 | If non-nil, user gets a message during the scanning of the buffer |
0a688fd0 RS |
105 | |
106 | Relevant only if the mode-specific function that creates the buffer | |
0ee4f8ad | 107 | index use `imenu-progress-message'.") |
0a688fd0 RS |
108 | |
109 | (defvar imenu-space-replacement "^" | |
110 | "*The replacement string for spaces in index names. | |
111 | Used when presenting the index in a completion-buffer to make the | |
112 | names work as tokens.") | |
113 | ||
114 | (defvar imenu-level-separator ":" | |
115 | "*The separator between index names of different levels. | |
116 | Used for making mouse-menu titles and for flattening nested indexes | |
117 | with 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 | ||
126 | If non-nil this pattern is passed to `imenu-create-index-with-pattern' | |
127 | to create a buffer index. | |
128 | ||
129 | It is an alist with elements that look like this: (MENU-TITLE | |
130 | REGEXP INDEX). | |
131 | ||
132 | MENU-TITLE is a string used as the title for the submenu or nil if the | |
133 | entries are not nested. | |
134 | ||
135 | REGEXP is a regexp that should match a construct in the buffer that is | |
136 | to be displayed in the menu i.e. function or variable definitions, | |
137 | etc. It contains a substring which is the name to appear in the | |
138 | menu. See the info section on Regexps for more information. | |
139 | ||
140 | INDEX points to the substring in REGEXP that contains the name (of the | |
141 | function, variable or type) that is to appear in the menu. | |
615b306c | 142 | |
2d24227e RS |
143 | For 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 | ||
149 | The 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 | ||
162 | It should be a function that takes no arguments and returns an index | |
163 | of the current buffer as an alist. The elements in the alist look | |
164 | like: (INDEX-NAME . INDEX-POSITION). You may also nest index list like | |
a4e104bf | 165 | \(INDEX-NAME . INDEX-ALIST). |
0a688fd0 | 166 | |
0ee4f8ad | 167 | This function is called within a `save-excursion'. |
0a688fd0 RS |
168 | |
169 | The 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 |
175 | If `imenu-create-index-function' is set to |
176 | `imenu-default-create-index-function', then you must set this variable | |
0a688fd0 RS |
177 | to a function that will find the next index, looking backwards in the |
178 | file. | |
179 | ||
180 | The function should leave point at the place to be connected to the | |
181 | index 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 | 187 | This 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 | |
485 | To overide this example, Either set 'imenu-generic-expression | |
486 | or '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 | ||
539 | Each item should be a list of the form: (MAJOR-MODE | |
540 | IMENU-SCANNING-METHOD) where both MAJOR-MODE and IMENU-SCANNING-METHOD | |
541 | are symbols. If IMENU-SCANNING-METHOD is a function then it is called | |
542 | to create an index. If it is a `pattern' (See `imenu-generic-expression') | |
543 | it 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 | ||
692 | Moves point to end of buffer and then repeatedly calls | |
68e01f5a | 693 | `imenu-prev-index-position-function' and `imenu-extract-index-name-function'. |
0a688fd0 | 694 | Their 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 | ||
770 | PATTERN is an alist with elements that look like this: (MENU-TITLE | |
771 | REGEXP INDEX). | |
772 | ||
773 | MENU-TITLE is a string used as the title for the submenu or nil if the | |
774 | entries are not nested. | |
775 | ||
776 | REGEXP is a regexp that should match a construct in the buffer that is | |
777 | to be displayed in the menu i.e. function or variable definitions, | |
778 | etc. It contains a substring which is the name to appear in the | |
779 | menu. See the info section on Regexps for more information. | |
780 | ||
781 | INDEX points to the substring in REGEXP that contains the name (of the | |
782 | function, variable or type) that is to appear in the menu. | |
783 | ||
784 | For 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 | ||
790 | Returns an index of the current buffer as an alist. The elements in | |
791 | the alist look like: (INDEX-NAME . INDEX-POSITION). They may also be | |
792 | nested index lists like (INDEX-NAME . INDEX-ALIST) depending on | |
793 | pattern. | |
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 | ||
851 | Returns 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 | ||
893 | INDEX-ALIST is the buffer index and EVENT is a mouse event. | |
894 | ||
895 | Returns 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 | ||
946 | If the user originally activated this function with the mouse, a mouse | |
0a688fd0 RS |
947 | menu is used. Otherwise a completion buffer is used and the user is |
948 | prompted with PROMPT. | |
949 | ||
26d6bb60 RS |
950 | If you call this function with index alist ALIST, then it lets the user |
951 | select from ALIST. | |
952 | ||
0ee4f8ad | 953 | With no index alist ALIST, it calls `imenu--make-index-alist' to |
26d6bb60 RS |
954 | create the index alist. |
955 | ||
0ee4f8ad | 956 | If `imenu-always-use-completion-buffer-p' is non-nil, then the |
0a688fd0 RS |
957 | completion buffer is always used, no matter if the mouse was used or |
958 | not. | |
959 | ||
960 | The 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 | |
986 | current local keymap. | |
987 | NAME is the string naming the menu to be added. | |
988 | See '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 | 997 | See `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 |