diff options
| author | Richard M. Stallman | 1994-03-07 03:00:30 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1994-03-07 03:00:30 +0000 |
| commit | 0a688fd0fcca19716d44e548b280bd1decaab6ef (patch) | |
| tree | 420ce49a3619532d8e34190323ae8c7b33d895f2 | |
| parent | f88b8cee6fade3cd9ddb435267c217c22091c804 (diff) | |
| download | emacs-0a688fd0fcca19716d44e548b280bd1decaab6ef.tar.gz emacs-0a688fd0fcca19716d44e548b280bd1decaab6ef.zip | |
Initial revision
| -rw-r--r-- | lisp/imenu.el | 613 |
1 files changed, 613 insertions, 0 deletions
diff --git a/lisp/imenu.el b/lisp/imenu.el new file mode 100644 index 00000000000..30bf2374b10 --- /dev/null +++ b/lisp/imenu.el | |||
| @@ -0,0 +1,613 @@ | |||
| 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 | ||
| 8 | ;; Version: 1.4 | ||
| 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 | |||
| 40 | ;; There are *examples* for index gathering functions for C/C++ and | ||
| 41 | ;; Lisp/Emacs Lisp but it is easy to customize for other modes. A | ||
| 42 | ;; function for jumping to the chosen index position is also | ||
| 43 | ;; supplied. | ||
| 44 | ;; | ||
| 45 | ;; Installation: | ||
| 46 | ;; Put this file in your load-path and insert the following in .emacs | ||
| 47 | ;; | ||
| 48 | ;; (autoload 'imenu-choose-buffer-index "imenu" "Menu of buffer index." t) | ||
| 49 | ;; (autoload 'goto-index-pos "imenu" "Goto buffer index position." t) | ||
| 50 | ;; (define-key global-map "\C-cj" 'goto-index-pos) ;; Or some other key | ||
| 51 | ;; (cond (window-system | ||
| 52 | ;; (define-key global-map [S-down-mouse-3] 'goto-index-pos)) | ||
| 53 | |||
| 54 | ;;; Change Log: | ||
| 55 | ;; v1.4 Feb 18 1994ine-key global-map [S-down-mouse-3] 'goto-index-pos)) | ||
| 56 | |||
| 57 | ;;; Change Log: | ||
| 58 | ;; v1.4 Feb 18 1994 Ake Stenhoff | ||
| 59 | ;; Added 'imenu-create-submenu-name' for creating a submenu name. | ||
| 60 | ;; This is for getting a general look of submenu names. | ||
| 61 | ;; Added variable 'imenu-submenu-name-format' used by | ||
| 62 | ;; 'imenu-create-submenu-name'. | ||
| 63 | ;; v1.3 Feb 17 1994 Lars Lindberg | ||
| 64 | ;; Added 'imenu--flatten-index-alist' for flatten nexted index | ||
| 65 | ;; alists. | ||
| 66 | ;; New examples for lisp mode that utilizes the features better. | ||
| 67 | ;; Added the variable 'imenu-space-replacement'. | ||
| 68 | ;; The completion-buffer version of the index menu now replaces | ||
| 69 | ;; spaces in the index-names to make tokens of them. | ||
| 70 | ;; v1.2 Feb 14 1994 Ake Stenhoff & Lars Lindberg | ||
| 71 | ;; Now handles nested index lists. | ||
| 72 | ;; v1.1 Feb 9 1994 Ake Stenhoff & Lars Lindberg | ||
| 73 | ;; Better comments (?). | ||
| 74 | ;; v1.0 Feb 8 1994 Ake Stenhoff & Lars Lindberg | ||
| 75 | ;; Based on func-menu.el 3.5. | ||
| 76 | |||
| 77 | ;;; Code | ||
| 78 | (require 'cl) | ||
| 79 | |||
| 80 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 81 | ;;; | ||
| 82 | ;;; Customizable variables | ||
| 83 | ;;; | ||
| 84 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 85 | |||
| 86 | (defvar imenu-always-use-completion-buffer-p nil | ||
| 87 | "*Set this to non-nil for displaying the index in a completion buffer. | ||
| 88 | |||
| 89 | Non-nil means always display the index in a completion buffer. | ||
| 90 | Nil means display the index as a mouse menu when the mouse was | ||
| 91 | used to trigger 'goto-index-pos'.") | ||
| 92 | |||
| 93 | (defvar imenu-sort-function nil | ||
| 94 | "*The function to use for sorting the index mouse-menu. | ||
| 95 | |||
| 96 | Affects only the mouse index menu. | ||
| 97 | |||
| 98 | Set this to nil if you don't want any sorting (faster). | ||
| 99 | The items in the menu are then presented in the order they were found | ||
| 100 | in the buffer. | ||
| 101 | |||
| 102 | Set it to 'imenu--sort-by-name if you want alphabetic sorting. | ||
| 103 | |||
| 104 | The function should take two arguments and return T if the first | ||
| 105 | element should come before the second. The arguments are cons cells; | ||
| 106 | (NAME . POSITION). Look at 'imenu--sort-by-name' for an example.") | ||
| 107 | |||
| 108 | (defvar imenu-max-items 25 | ||
| 109 | "*Maximum number of elements in an index mouse-menu.") | ||
| 110 | |||
| 111 | (defvar imenu-scanning-message "Scanning buffer for index. (%3d%%)" | ||
| 112 | "*Progress message during the index scanning of the buffer. | ||
| 113 | If non NIL, user gets a message during the scanning of the buffer | ||
| 114 | |||
| 115 | Relevant only if the mode-specific function that creates the buffer | ||
| 116 | index use 'imenu-progress-message'.") | ||
| 117 | |||
| 118 | (defvar imenu-space-replacement "^" | ||
| 119 | "*The replacement string for spaces in index names. | ||
| 120 | Used when presenting the index in a completion-buffer to make the | ||
| 121 | names work as tokens.") | ||
| 122 | |||
| 123 | (defvar imenu-level-separator ":" | ||
| 124 | "*The separator between index names of different levels. | ||
| 125 | Used for making mouse-menu titles and for flattening nested indexes | ||
| 126 | with name concatenation.") | ||
| 127 | |||
| 128 | (defvar imenu-submenu-name-format "%s..." | ||
| 129 | "*The format for making a submenu name.") | ||
| 130 | |||
| 131 | ;;;; Hooks | ||
| 132 | |||
| 133 | (defvar imenu-create-index-function 'imenu-default-create-index-function | ||
| 134 | "The function to use for creating a buffer index. | ||
| 135 | |||
| 136 | It should be a function that takes no arguments and returns an index | ||
| 137 | of the current buffer as an alist. The elements in the alist look | ||
| 138 | like: (INDEX-NAME . INDEX-POSITION). You may also nest index list like | ||
| 139 | (INDEX-NAME . INDEX-ALIST). | ||
| 140 | |||
| 141 | This function is called within a 'save-excursion'. | ||
| 142 | |||
| 143 | The variable is buffer-local.") | ||
| 144 | (make-variable-buffer-local 'imenu-create-index-function) | ||
| 145 | |||
| 146 | (defvar prev-index-position-function 'beginning-of-defun | ||
| 147 | "Function for finding the next index position. | ||
| 148 | |||
| 149 | If 'imenu-create-index-function' is set to | ||
| 150 | 'imenu-default-create-index-function, then you must set this variable | ||
| 151 | to a function that will find the next index, looking backwards in the | ||
| 152 | file. | ||
| 153 | |||
| 154 | The function should leave point at the place to be connected to the | ||
| 155 | index and it should return nil when it doesn't find another index. ") | ||
| 156 | (make-variable-buffer-local 'prev-index-position-function) | ||
| 157 | |||
| 158 | (defvar extract-index-name-function nil | ||
| 159 | "Function for extracting the index name. | ||
| 160 | |||
| 161 | This function is called after the function pointed out by | ||
| 162 | 'prev-index-position-functioname. | ||
| 163 | |||
| 164 | This function is called after the function pointed out by | ||
| 165 | 'prev-index-position-function'.") | ||
| 166 | (make-variable-buffer-local 'extract-index-name-function) | ||
| 167 | |||
| 168 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 169 | ;;; | ||
| 170 | ;;; Internal variables | ||
| 171 | ;;; | ||
| 172 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 173 | |||
| 174 | ;; The item to use in the index for rescanning the buffer. | ||
| 175 | (defconst imenu--rescan-item '("*Rescan*" . -99)) | ||
| 176 | |||
| 177 | ;; The latest buffer index. | ||
| 178 | ;; Buffer local. | ||
| 179 | (defvar imenu--index-alist nil) | ||
| 180 | (make-variable-buffer-local 'imenu--index-alist) | ||
| 181 | |||
| 182 | ;; History list for 'jump-to-function-in-buffer'. | ||
| 183 | ;; Buffer local. | ||
| 184 | (defvar imenu--history-list nil) | ||
| 185 | (make-variable-buffer-local 'imenu--history-list) | ||
| 186 | |||
| 187 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 188 | ;;; | ||
| 189 | ;;; Internal support functions | ||
| 190 | ;;; | ||
| 191 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 192 | |||
| 193 | ;;; | ||
| 194 | ;;; Sort function | ||
| 195 | ;;; Sorts the items depending on their index name. | ||
| 196 | ;;; An item look like (NAME . POSITION). | ||
| 197 | ;;; | ||
| 198 | (defun imenu--sort-by-name (item1 item2) | ||
| 199 | (string-lessp (car item1) (car item2))) | ||
| 200 | |||
| 201 | (defun imenu--relative-position (&optional reverse) | ||
| 202 | ;; Support function to calculate relative position in buffer | ||
| 203 | ;; Beginning of buffer is 0 and end of buffer is 100 | ||
| 204 | ;; If REVERSE is non-nil then the beginning is 100 and the end is 0. | ||
| 205 | (let ((pos (point)) | ||
| 206 | (total (buffer-size))) | ||
| 207 | (and reverse (setq pos (- total pos))) | ||
| 208 | (if (> total 50000) | ||
| 209 | ;; Avoid overflow from multiplying by 100! | ||
| 210 | (/ (1- pos) (max (/ total 100) 1)) | ||
| 211 | (/ (* 100 (1- pos)) (max total 1))))) | ||
| 212 | |||
| 213 | ;;; | ||
| 214 | ;;; Macro to display a progress message. This will probably be used | ||
| 215 | ;;; in a tight loop, that is why we use a macro. | ||
| 216 | ;;; RELPOS is the relative position to display. | ||
| 217 | ;;; If RELPOS is nil, then the relative position in the buffer | ||
| 218 | ;;; is calculated. | ||
| 219 | (defmacro imenu-progress-message (&optional relpos reverse) | ||
| 220 | (` (and | ||
| 221 | imenu-scanning-message | ||
| 222 | (message imenu-scanning-message | ||
| 223 | (, (if relpos | ||
| 224 | relpos | ||
| 225 | (` (imenu--relative-position (, reverse))))))))) | ||
| 226 | |||
| 227 | ;;; | ||
| 228 | ;;; Function for suporting general looking submenu names. | ||
| 229 | ;;; Uses 'imenu-submenu-name-format' for creating the name. | ||
| 230 | ;;; NAME is the base of the new submenu name. | ||
| 231 | ;;; | ||
| 232 | (defun imenu-create-submenu-name (name) | ||
| 233 | (format imenu-submenu-name-format name)) | ||
| 234 | |||
| 235 | ;; Split LIST into sublists of max length N. | ||
| 236 | ;; Example (imenu--split '(1 2 3 4 5 6 7 8) 3)-> '((1 2 3) (4 5 6) (7 8)) | ||
| 237 | (defun imenu--split (list n) | ||
| 238 | (let ((remain list) | ||
| 239 | (result '()) | ||
| 240 | (sublist '()) | ||
| 241 | (i 0)) | ||
| 242 | (while remain | ||
| 243 | (push (pop remain) sublist) | ||
| 244 | (incf i) | ||
| 245 | (and (= i n) | ||
| 246 | ;; We have finished a sublist | ||
| 247 | (progn (push (nreverse sublist) result) | ||
| 248 | (setq i 0) | ||
| 249 | (setq sublist '())))) | ||
| 250 | ;; There might be a sublist (if the length of LIST mod n is != 0) | ||
| 251 | ;; that has to be added to the result list. | ||
| 252 | (and sublist | ||
| 253 | (push (nreverse sublist) result)) | ||
| 254 | (nreverse result))) | ||
| 255 | |||
| 256 | ;;; | ||
| 257 | ;;; Split a menu in to several menus. | ||
| 258 | ;;; | ||
| 259 | (defun imenu--split-menu (menulist title) | ||
| 260 | (cons "Function menus" | ||
| 261 | (mapcar | ||
| 262 | (function | ||
| 263 | (lambda (menu) | ||
| 264 | (cons (format "(%s)" title) menu))) | ||
| 265 | (imenu--split menulist imenu-max-items)))) | ||
| 266 | |||
| 267 | ;;; | ||
| 268 | ;;; Find all items in this buffer that should be in the index. | ||
| 269 | ;;; Returns an alist on the form | ||
| 270 | ;;; ((NAME . POSITION) (NAME . POSITION) ...) | ||
| 271 | ;;; | ||
| 272 | |||
| 273 | (defun imenu--make-index-alist () | ||
| 274 | ;; Create a list for this buffer only when needed. | ||
| 275 | (or imenu--index-alist | ||
| 276 | ;; Get the index | ||
| 277 | (setq imenu--index-alist | ||
| 278 | (save-excursion | ||
| 279 | (funcall imenu-create-index-function)))) | ||
| 280 | (or imenu--index-alist | ||
| 281 | (error "No items suitable for an index found in this buffer.")) | ||
| 282 | ;; Add a rescan option to the index. | ||
| 283 | (cons imenu--rescan-item imenu--index-alist)) | ||
| 284 | |||
| 285 | (defun imenu-default-create-index-function () | ||
| 286 | "*Wrapper for index searching functions. | ||
| 287 | |||
| 288 | Moves point to end of buffer and then repeatedly calls | ||
| 289 | 'prev-index-position-function' and 'extract-index-name-function'. | ||
| 290 | Their results are gathered into an index aliition-function' and 'extract-index-name-function'. | ||
| 291 | Their results are gathered into an index alist." | ||
| 292 | |||
| 293 | (or (and (fboundp prev-index-position-function) | ||
| 294 | (fboundp extract-index-name-function)) | ||
| 295 | (error "The mode \"%s\" does not take full advantage of imenu.el yet." | ||
| 296 | mode-name)) | ||
| 297 | (let ((index-alist '()) | ||
| 298 | name) | ||
| 299 | (goto-char (point-max)) | ||
| 300 | (imenu-progress-message 0 t) | ||
| 301 | ;; Search for the function | ||
| 302 | (while (funcall prev-index-position-function) | ||
| 303 | (imenu-progress-message nil t) | ||
| 304 | (save-excursion | ||
| 305 | (setq name (funcall extract-index-name-function))) | ||
| 306 | (and (stringp name) | ||
| 307 | (push (cons name (point)) index-alist))) | ||
| 308 | (imenu-progress-message 100 t) | ||
| 309 | index-alist)) | ||
| 310 | |||
| 311 | (defun imenu--replace-spaces (name replacement) | ||
| 312 | ;; Replace all spaces in NAME with REPLACEMENT. | ||
| 313 | ;; That second argument should be a string. | ||
| 314 | (mapconcat | ||
| 315 | (function | ||
| 316 | (lambda (ch) | ||
| 317 | (if (char-equal ch ?\ ) | ||
| 318 | replacement | ||
| 319 | (char-to-string ch)))) | ||
| 320 | name | ||
| 321 | "")) | ||
| 322 | |||
| 323 | (defun imenu--flatten-index-alist (index-alist &optional concat-names prefix) | ||
| 324 | ;; Takes a nested INDEX-ALIST and returns a flat index alist. | ||
| 325 | ;; If optional CONCAT-NAMES is non-nil, then a nested index has its | ||
| 326 | ;; name and a space concatenated to the names of the children. | ||
| 327 | ;; Third argument PREFIX is for internal use only. | ||
| 328 | (mapcan | ||
| 329 | (function | ||
| 330 | (lambda (item) | ||
| 331 | (let* ((name (car item)) | ||
| 332 | (pos (cdr item)) | ||
| 333 | (new-prefix (and concat-names | ||
| 334 | (if prefix | ||
| 335 | (concat prefix imenu-level-separator name) | ||
| 336 | name)))) | ||
| 337 | (cond | ||
| 338 | ((numberp pos) | ||
| 339 | (list (cons new-prefix pos))) | ||
| 340 | (t | ||
| 341 | (imenu--flatten-index-alist pos new-prefix)))))) | ||
| 342 | index-alist)) | ||
| 343 | |||
| 344 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 345 | ;;; | ||
| 346 | ;;; The main functions for this package! | ||
| 347 | ;;; | ||
| 348 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 349 | |||
| 350 | (defun imenu--completion-buffer (index-alist &optional prompt) | ||
| 351 | "Let the user select from INDEX-ALIST in a completion buffer with PROMPT. | ||
| 352 | |||
| 353 | Returns t for rescan and otherwise a position number." | ||
| 354 | ;; Create a list for this buffer only when needed. | ||
| 355 | (let (name choice | ||
| 356 | (prepared-index-alist | ||
| 357 | (mapcar | ||
| 358 | (function | ||
| 359 | (lambda (item) | ||
| 360 | (cons (imenu--replace-spaces (car item) imenu-space-replacement) | ||
| 361 | (cdr item)))) | ||
| 362 | index-alist))) | ||
| 363 | (save-window-excursion | ||
| 364 | ;; Display the completion buffer | ||
| 365 | (with-output-to-temp-buffer "*Completions*" | ||
| 366 | (display-completion-list | ||
| 367 | (all-completions "" prepared-index-alist ))) | ||
| 368 | ;; Make a completion question | ||
| 369 | (setq name (completing-read (or prompt "Index item: ") | ||
| 370 | prepared-index-alist | ||
| 371 | nil t nil 'imenu--history-list))) | ||
| 372 | (cond | ||
| 373 | ((not (stringp name)) | ||
| 374 | nil) | ||
| 375 | ((string= name (car imenu--rescan-item)) | ||
| 376 | t) | ||
| 377 | (t | ||
| 378 | (setq choice (assoc name prepared-index-alist)) | ||
| 379 | (cond | ||
| 380 | ((listp (cdr choice)) | ||
| 381 | (imenu--completion-buffer (cdr choice) prompt)) | ||
| 382 | (t | ||
| 383 | choice)))))) | ||
| 384 | |||
| 385 | (defun imenu--mouse-menu (index-alist event &optional title) | ||
| 386 | "Let the user select from a buffer index from a mouse menu. | ||
| 387 | |||
| 388 | INDEX-ALIST is the buffer index and EVENT is a mouse event. | ||
| 389 | |||
| 390 | Returns t for rescan and otherwise a position number." | ||
| 391 | (let* ((menu (imenu--split-menu | ||
| 392 | (if imenu-sort-function | ||
| 393 | (sort (copy-list index-alist) imenu-sort-function) | ||
| 394 | index-alist) | ||
| 395 | (or title (buffer-name)))) | ||
| 396 | position) | ||
| 397 | (setq position (x-popup-menu event menu)) | ||
| 398 | (cond | ||
| 399 | ((eq position nil) | ||
| 400 | position) | ||
| 401 | ((not (numberp position)) | ||
| 402 | (imenu--mouse-menu position event | ||
| 403 | (if title | ||
| 404 | (concat title imenu-level-separator | ||
| 405 | (car (rassq position index-alist))) | ||
| 406 | (car (rassq position index-alist))))) | ||
| 407 | ((= position (cdr imenu--rescan-item)) | ||
| 408 | t) | ||
| 409 | (t | ||
| 410 | (rassq position index-alist))))) | ||
| 411 | |||
| 412 | (defun imenu-choose-buffer-index (&optional prompt) | ||
| 413 | "Let the user select from a buffer index and return the chosen index. | ||
| 414 | |||
| 415 | If the user originally activated this function with the mouse, a mouse | ||
| 416 | menu is used. Otherwise f the user originally activated this function with the mouse, a mouse | ||
| 417 | menu is used. Otherwise a completion buffer is used and the user is | ||
| 418 | prompted with PROMPT. | ||
| 419 | |||
| 420 | If 'imenu-always-use-completion-buffer-p' is non-nil, then the | ||
| 421 | completion buffer is always used, no matter if the mouse was used or | ||
| 422 | not. | ||
| 423 | |||
| 424 | The returned value is on the form (INDEX-NAME . INDEX-POSITION)." | ||
| 425 | (let (index-alist | ||
| 426 | (mouse-triggered (listp last-command-event)) | ||
| 427 | (result t) ) | ||
| 428 | ;; If selected by mouse, see to that the window where the mouse is | ||
| 429 | ;; really is selected. | ||
| 430 | (and mouse-triggered | ||
| 431 | (let ((window (posn-window (event-start last-command-event)))) | ||
| 432 | (or (framep window) (select-window window)))) | ||
| 433 | ;; Create a list for this buffer only when needed. | ||
| 434 | (while (eq result t) | ||
| 435 | (setq index-alist (imenu--make-index-alist)) | ||
| 436 | (setq result | ||
| 437 | (if (and mouse-triggered | ||
| 438 | (not imenu-always-use-completion-buffer-p)) | ||
| 439 | (imenu--mouse-menu index-alist last-command-event) | ||
| 440 | (imenu--completion-buffer index-alist prompt))) | ||
| 441 | (and (eq result t) | ||
| 442 | (setq imenu--index-alist nil))) | ||
| 443 | result)) | ||
| 444 | |||
| 445 | (defun goto-index-pos () | ||
| 446 | "Jump to selected part of buffer, using a buffer menu or mouse menu. | ||
| 447 | |||
| 448 | See 'imenu-choose-buffer-index' for more information." | ||
| 449 | (interactive) | ||
| 450 | (let ((index-item (imenu-choose-buffer-index))) | ||
| 451 | (and index-item | ||
| 452 | (progn | ||
| 453 | (push-mark) | ||
| 454 | (goto-char (cdr index-item)))))) | ||
| 455 | |||
| 456 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 457 | ;;;; | ||
| 458 | ;;;; Some examples of functions utilizing the framework of this | ||
| 459 | ;;;; package. | ||
| 460 | ;;;; | ||
| 461 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 462 | |||
| 463 | ;; Return the current/previous sexp and the location of the sexp (it's | ||
| 464 | ;; beginning) without moving the point. | ||
| 465 | (defun imenu-example--name-and-position () | ||
| 466 | (save-excursion | ||
| 467 | (forward-sexp -1) | ||
| 468 | (let ((beg (point)) | ||
| 469 | (end (progn (forward-sexp) (point)))) | ||
| 470 | (cons (buffer-substring beg end) | ||
| 471 | beg)))) | ||
| 472 | |||
| 473 | ;;; | ||
| 474 | ;;; Lisp | ||
| 475 | ;;; | ||
| 476 | |||
| 477 | (defun imenu-example--lisp-extract-index-name () | ||
| 478 | ;; Example of a candidate for 'imenu-extract-index-name-function'. | ||
| 479 | ;; This will generate a flat index of definitions in a lisp file. | ||
| 480 | (save-match-data | ||
| 481 | (and (looking-at "(def") | ||
| 482 | (condition-case nil | ||
| 483 | (progn | ||
| 484 | (down-list 1) | ||
| 485 | (forward-sexp 2) | ||
| 486 | (let ((beg (point)) | ||
| 487 | (end (progn (forward-sexp -1) (point)))) | ||
| 488 | (buffer-substring beg end))) | ||
| 489 | (error nil))))) | ||
| 490 | |||
| 491 | (defun imenu-example--create-lisp-index () | ||
| 492 | ;; Example of a candidate for 'imenu-create-index-function'. | ||
| 493 | ;; It will generate a nested index of definitions. | ||
| 494 | (let ((index-alist '()) | ||
| 495 | (index-var-alist '()) | ||
| 496 | (index-unknown-alist '())) | ||
| 497 | (goto-char (point-max)) | ||
| 498 | (imenu-progress-message 0) | ||
| 499 | ;; Search for the function | ||
| 500 | (while (beginning-of-defun) | ||
| 501 | (imenu-progress-message nil t) | ||
| 502 | (save-match-data | ||
| 503 | (and (looking-at "(def") | ||
| 504 | (save-excursion | ||
| 505 | (down-list 1) | ||
| 506 | (cond | ||
| 507 | ((looking-at "def\\(var\\|const\\)") | ||
| 508 | (forward-sexp 2) | ||
| 509 | (push (imenu-example--name-and-position) | ||
| 510 | index-var-alist)) | ||
| 511 | ((looking-at "def\\(un\\|subst\\|macro\\|advice\\)") | ||
| 512 | (forward-sexp 2) | ||
| 513 | (push (imenu-example--name-and-position) | ||
| 514 | index-alist)) | ||
| 515 | (t | ||
| 516 | (forward-sexp 2) | ||
| 517 | (push (imenu-example--name-and-position) | ||
| 518 | index-unknown-alist))))))) | ||
| 519 | (imenu-progress-message 100) | ||
| 520 | (and index-var-alist | ||
| 521 | (push (cons (imenu-create-submenu-name "Variables") index-var-alist) | ||
| 522 | index-alist)) | ||
| 523 | (and index-unknown-alist | ||
| 524 | (push (cons (imenu-create-submenu-name "Syntax-unknown") index-unknown-alist) | ||
| 525 | index-alist)) | ||
| 526 | index-alist)) | ||
| 527 | |||
| 528 | |||
| 529 | ;;; | ||
| 530 | ;;; C | ||
| 531 | ;;; | ||
| 532 | ;; Regular expression to find C functions | ||
| 533 | (defvar imenu-example--function-name-regexp-c | ||
| 534 | (concat | ||
| 535 | "^[a-zA-Z0-9]+[ \t]?" ; type specs; there can be no | ||
| 536 | "\\([a-zA-Z0-9_*]+[ \t]+\\)?" ; more than 3 tokens, right? | ||
| 537 | "\\([a-zA-Z0-9_*]+[ \t]+\\)?" | ||
| 538 | "\\([*&]+[ \t]*\\)?" ; pointer | ||
| 539 | "\\([a-zA-Z0-9_*]+\\)[ \t]*(" ; name | ||
| 540 | )) | ||
| 541 | |||
| 542 | (defun imenu-example--create-c-index (&opter | ||
| 543 | "\\([a-zA-Z0-9_*]+\\)[ \t]*(" ; name | ||
| 544 | )) | ||
| 545 | |||
| 546 | (defun imenu-example--create-c-index (&optional regexp) | ||
| 547 | (let ((index-alist '()) | ||
| 548 | (char)) | ||
| 549 | (goto-char (point-min)) | ||
| 550 | (imenu-progress-message 0) | ||
| 551 | ;; Search for the function | ||
| 552 | (save-match-data | ||
| 553 | (while (re-search-forward | ||
| 554 | (or regexp imenu-example--function-name-regexp-c) | ||
| 555 | nil t) | ||
| 556 | (imenu-progress-message) | ||
| 557 | (backward-up-list 1) | ||
| 558 | (save-excursion | ||
| 559 | (goto-char (scan-sexps (point) 1)) | ||
| 560 | (setq char (following-char))) | ||
| 561 | ;; Skip this function name if it is a prototype declaration. | ||
| 562 | (if (not (eq char ?\;)) | ||
| 563 | (push (imenu-example--name-and-position) index-alist)))) | ||
| 564 | (imenu-progress-message 100) | ||
| 565 | (nreverse index-alist))) | ||
| 566 | |||
| 567 | ;;; | ||
| 568 | ;;; C++ | ||
| 569 | ;;; | ||
| 570 | ;; Regular expression to find C++ functions | ||
| 571 | (defvar imenu-example--function-name-regexp-c++ | ||
| 572 | (concat | ||
| 573 | "^[a-zA-Z0-9:]+[ \t]?" ; type specs; there can be no | ||
| 574 | "\\([a-zA-Z0-9_:~*]+[ \t]+\\)?" ; more than 3 tokens, right? | ||
| 575 | "\\([a-zA-Z0-9_:~*]+[ \t]+\\)?" | ||
| 576 | "\\([*&]+[ \t]*\\)?" ; pointer | ||
| 577 | "\\([a-zA-Z0-9_:*]+\\)[ \t]*(" ; name | ||
| 578 | )) | ||
| 579 | (defun imenu-example--create-c++-index () | ||
| 580 | (imenu-example--create-c-index imenu-example--function-name-regexp-c++)) | ||
| 581 | |||
| 582 | |||
| 583 | ;;; | ||
| 584 | ;;; Example of hooks for the examples above | ||
| 585 | ;;; Put this in your .emacs. | ||
| 586 | ;;; | ||
| 587 | ;; (add-hook 'emacs-lisp-mode-hook | ||
| 588 | ;; (function | ||
| 589 | ;; (lambda () | ||
| 590 | ;; (setq imenu-create-index-function | ||
| 591 | ;; (function imenu-example--create-lisp-index))))) | ||
| 592 | |||
| 593 | ;; (add-hook 'lisp-mode-hook | ||
| 594 | ;; (function | ||
| 595 | ;; (lambda () | ||
| 596 | ;; (setq imenu-create-index-function | ||
| 597 | ;; (function imenu-example--create-lisp-index))))) | ||
| 598 | |||
| 599 | ;; (add-hook 'c++-mode-hook | ||
| 600 | ;; (function | ||
| 601 | ;; (lambda () | ||
| 602 | ;; (setq imenu-create-index-function | ||
| 603 | ;; (function imenu-example--create-c++-index))))) | ||
| 604 | |||
| 605 | ;; (add-hook 'c-mode-hook | ||
| 606 | ;; (function | ||
| 607 | ;; (lambda () | ||
| 608 | ;; (setq imenu-create-index-function | ||
| 609 | ;; (function imenu-example--create-c-index))))) | ||
| 610 | |||
| 611 | (provide 'imenu) | ||
| 612 | |||
| 613 | ;;; imenu.el ends here | ||