;;; imenu.el --- Framework for mode-specific buffer indexes.
-;; Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+;; Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
;; Author: Ake Stenhoff <etxaksf@aom.ericsson.se>
;; Lars Lindberg <lli@sypro.cap.se>
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defvar imenu-auto-rescan nil
- "*Non-nil means Imenu should always rescan the buffers.")
+(defgroup imenu nil
+ "Mode-specific buffer indexes."
+ :group 'matching
+ :group 'frames)
-(defvar imenu-auto-rescan-maxout 60000
- "* auto-rescan is disabled in buffers larger than this.
-This variable is buffer-local.")
+(defcustom imenu-use-markers t
+ "*Non-nil means use markers instead of integers for Imenu buffer positions.
+Setting this to nil makes Imenu work faster.
-(defvar imenu-always-use-completion-buffer-p nil
+This might not yet be honored by all index-building functions."
+ :type 'boolean
+ :group 'imenu)
+
+
+(defcustom imenu-max-item-length 60
+ "*If a number, truncate Imenu entries to that length."
+ :type 'integer
+ :group 'imenu)
+
+(defcustom imenu-auto-rescan nil
+ "*Non-nil means Imenu should always rescan the buffers."
+ :type 'boolean
+ :group 'imenu)
+
+(defcustom imenu-auto-rescan-maxout 60000
+ "*Imenu auto-rescan is disabled in buffers larger than this size.
+This variable is buffer-local."
+ :type 'integer
+ :group 'imenu)
+
+(defcustom imenu-always-use-completion-buffer-p nil
"*Set this to non-nil for displaying the index in a completion buffer.
-Non-nil means always display the index in a completion buffer.
-Nil means display the index as a mouse menu when the mouse was
-used to invoke `imenu'.
-`never' means never automatically display a listing of any kind.")
+`never' means never automatically display a listing of any kind.
+A value of nil (the default) means display the index as a mouse menu
+if the mouse was used to invoke `imenu'.
+Another non-nil value means always display the index in a completion buffer."
+ :type '(choice (const :tag "On Mouse" nil)
+ (const :tag "Never" never)
+ (sexp :tag "Always" :format "%t\n" t))
+ :group 'imenu)
-(defvar imenu-sort-function nil
+(defcustom imenu-sort-function nil
"*The function to use for sorting the index mouse-menu.
Affects only the mouse index menu.
The function should take two arguments and return T if the first
element should come before the second. The arguments are cons cells;
-\(NAME . POSITION). Look at `imenu--sort-by-name' for an example.")
+\(NAME . POSITION). Look at `imenu--sort-by-name' for an example."
+ :type 'function
+ :group 'imenu)
-(defvar imenu-max-items 25
- "*Maximum number of elements in an mouse menu for Imenu.")
+(defcustom imenu-max-items 25
+ "*Maximum number of elements in a mouse menu for Imenu."
+ :type 'integer
+ :group 'imenu)
-(defvar imenu-scanning-message "Scanning buffer for index (%3d%%)"
+(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
+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'.")
+index use `imenu-progress-message'."
+ :type 'string
+ :group 'imenu)
-(defvar imenu-space-replacement "^"
+(defcustom imenu-space-replacement "^"
"*The replacement string for spaces in index names.
Used when presenting the index in a completion-buffer to make the
-names work as tokens.")
+names work as tokens."
+ :type 'string
+ :group 'imenu)
-(defvar imenu-level-separator ":"
+(defcustom imenu-level-separator ":"
"*The separator between index names of different levels.
Used for making mouse-menu titles and for flattening nested indexes
-with name concatenation.")
+with name concatenation."
+ :type 'string
+ :group 'imenu)
;;;###autoload
(defvar imenu-generic-expression nil
"The regex pattern to use for creating a buffer index.
-If non-nil this pattern is passed to `imenu-create-index-with-pattern'
+If non-nil this pattern is passed to `imenu--generic-function'
to create a buffer index.
The value should be an alist with elements that look like this:
`imenu-prev-index-position-function'.")
(make-variable-buffer-local 'imenu-extract-index-name-function)
+(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.")
+(make-variable-buffer-local 'imenu-default-goto-function)
+
+
(defun imenu--subalist-p (item)
(and (consp (cdr item)) (listp (cadr item))
(not (eq (caadr item) 'lambda))))
(defun imenu-example--name-and-position ()
(save-excursion
(forward-sexp -1)
- (let ((beg (point))
- (end (progn (forward-sexp) (point)))
- (marker (make-marker)))
- (set-marker marker beg)
+ ;; [ydi] modified for imenu-use-markers
+ (let ((beg (if imenu-use-markers (point-marker) (point)))
+ (end (progn (forward-sexp) (point))))
(cons (buffer-substring beg end)
- marker))))
+ beg))))
;;;
;;; Lisp
elt)))
alist))
+;;; Truncate all strings in MENULIST to imenu-max-item-length
+(defun imenu--truncate-items (menulist)
+ (mapcar (function
+ (lambda (item)
+ (cond
+ ((consp (cdr item))
+ (imenu--truncate-items (cdr item)))
+ (t
+ ;; truncate if necessary
+ (if (and (numberp imenu-max-item-length)
+ (> (length (car item)) imenu-max-item-length))
+ (setcar item (substring (car item) 0 imenu-max-item-length)))))))
+ menulist))
+
+
(defun imenu--make-index-alist (&optional noerror)
"Create an index-alist for the definitions in the current buffer.
(or (not imenu-auto-rescan)
(and imenu-auto-rescan
(> (buffer-size) imenu-auto-rescan-maxout))))
- ;; Get the index
- (setq imenu--index-alist
- (save-excursion
- (funcall imenu-create-index-function))))
+ ;; 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)))
(or imenu--index-alist noerror
(error "No items suitable for an index found in this buffer"))
(or imenu--index-alist
(save-excursion
(setq name (funcall imenu-extract-index-name-function)))
(and (stringp name)
- (push (cons name (point)) index-alist)))
+ ;; [ydi] updated for imenu-use-markers
+ (push (cons name (if imenu-use-markers (point-marker) (point)))
+ index-alist)))
(imenu-progress-message prev-pos 100 t)
index-alist))
;; Use generic expression if possible.
((and imenu-generic-expression)
(imenu--generic-function imenu-generic-expression))
(t
- (error "The mode `%s' does not support Imenu" mode-name))))
+ (error "This buffer cannot use `imenu-default-create-index-function'"))))
(defun imenu--replace-spaces (name replacement)
;; Replace all spaces in NAME with REPLACEMENT.
(rest (cddddr pat)))
(if (and (not found) ; Only allow one entry;
(looking-at regexp))
- (let ((beg (make-marker))
+ (let ((beg (match-beginning index))
(end (match-end index)))
- (set-marker beg (match-beginning index))
(setq found t)
(push
(let ((name
(buffer-substring-no-properties beg end)))
+ ;; [ydi] updated for imenu-use-markers
+ (if imenu-use-markers
+ (setq beg (set-marker (make-marker) beg)))
(if function
- (nconc (list name function name beg)
+ (nconc (list name beg function)
rest)
(cons name beg)))
(cdr
NAME is a string used to name the menu bar item.
See the command `imenu' for more information."
(interactive "sImenu menu item name: ")
- (let ((newmap (make-sparse-keymap))
- (menu-bar (lookup-key (current-local-map) [menu-bar])))
- (define-key newmap [menu-bar]
- (append (make-sparse-keymap) menu-bar))
- (define-key newmap [menu-bar index]
- (cons name (nconc (make-sparse-keymap "Imenu")
- (make-sparse-keymap))))
- (use-local-map (append newmap (current-local-map))))
- (add-hook 'menu-bar-update-hook 'imenu-update-menubar))
+ (if (or (and (fboundp imenu-prev-index-position-function)
+ (fboundp imenu-extract-index-name-function))
+ (and imenu-generic-expression))
+ (let ((newmap (make-sparse-keymap))
+ (menu-bar (lookup-key (current-local-map) [menu-bar])))
+ (define-key newmap [menu-bar]
+ (append (make-sparse-keymap) menu-bar))
+ (define-key newmap [menu-bar index]
+ (cons name (nconc (make-sparse-keymap "Imenu")
+ (make-sparse-keymap))))
+ (use-local-map (append newmap (current-local-map)))
+ (add-hook 'menu-bar-update-hook 'imenu-update-menubar))
+ (error "The mode `%s' does not support Imenu" mode-name)))
(defvar imenu-buffer-menubar nil)
(defun imenu--menubar-select (item)
"Use Imenu to select the function or variable named in this menu item."
- (if (equal item '("*Rescan*" . -99))
+ (if (equal item imenu--rescan-item)
(progn
(imenu--cleanup)
(setq imenu--index-alist nil)
(imenu-update-menubar))
(imenu item)))
+(defun imenu-default-goto-function (name position &optional rest)
+ "This function is used for moving the point to POSITION.
+The NAME and REST parameters are not used, they are here just to make
+this function have the same interface as a function placed in a special
+index-item."
+ (if (or (< position (point-min))
+ (> position (point-max)))
+ ;; widen if outside narrowing
+ (widen))
+ (goto-char position))
+
;;;###autoload
(defun imenu (index-item)
"Jump to a place in the buffer chosen using a buffer menu or mouse menu.
See `imenu-choose-buffer-index' for more information."
- (interactive
- (list (save-restriction
- (widen)
- (imenu-choose-buffer-index))))
+ (interactive (list (imenu-choose-buffer-index)))
;; Convert a string to an alist element.
(if (stringp index-item)
(setq index-item (assoc index-item (imenu--make-index-alist))))
(and index-item
(progn
(push-mark)
- (cond
- ((markerp (cdr index-item))
- (if (or (< (marker-position (cdr index-item)) (point-min))
- (> (marker-position (cdr index-item)) (point-max)))
- ;; widen if outside narrowing
- (widen))
- (goto-char (marker-position (cdr index-item))))
- ((imenu--subalist-p index-item)
- (if (or (< (cdr index-item) (point-min))
- (> (cdr index-item) (point-max)))
- ;; widen if outside narrowing
- (widen))
- (goto-char (cdr index-item)))
- (t
- ;; A special item with a function.
- (let ((function (cadr index-item))
- (rest (cddr index-item)))
- (apply function (car index-item) rest)))))))
+ (let* ((is-special-item (listp (cdr index-item)))
+ (function
+ (if is-special-item
+ (caddr index-item) imenu-default-goto-function))
+ (position (if is-special-item
+ (cadr index-item) (cdr index-item)))
+ (rest (if is-special-item (cddr index-item))))
+ (apply function (car index-item) position rest)))))
(provide 'imenu)