;; Author: Ake Stenhoff <etxaksf@aom.ericsson.se>
;; Lars Lindberg <lli@sypro.cap.se>
;; Created: 8 Feb 1994
-;; Version: 1.7
+;; Version: 1.11
;; Keywords: tools
;;
;; This program is free software; you can redistribute it and/or modify
;;; Commentary:
;;
;; Purpose of this package:
-;;
-;; Installation instructions
-;;
-;; Usage instructions:
-;;
-;; Known bugs:
-;;
-;; 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.
;; Lisp/Emacs Lisp but it is easy to customize for other modes. A
;; function for jumping to the chosen index position is also
;; supplied.
-;;
-;; Installation:
-;; Put this file in your load-path and insert the following in .emacs
-;;
-;; (autoload 'imenu-choose-buffer-index "imenu" "Menu of buffer index." t)
-;; (autoload 'goto-index-pos "imenu" "Goto buffer index position." t)
-;; (define-key global-map "\C-cj" 'goto-index-pos) ;; Or some other key
-;; (cond (window-system
-;; (define-key global-map [S-down-mouse-3] 'goto-index-pos)))
-;; Also run the 'add-hook' examples at the bottom of imenu.el.
;;; Change Log:
+;; v1.11 Jul 26 1994 Ake Stenhoff
+;; Fixed bugs in 'imenu-add-to-menubar'.
+;; v1.10 Jul 21 1994 Ake Stenhoff
+;; Added support for markers.
+;; Changed the examples to use
+;; markers.
+;; Thanks [alon].
+;; v1.9 Jun 14 1994 Ake Stenhoff
+;; Added 'imenu-add-to-menubar'.
;; v1.7 Apr 12 1994 Ake Stenhoff
;; Changed doc strings refering to symbols.
;; Require 'cl' when compiling only.
;;; Thanks goes to
;; [simon] - Simon Leinen simon@lia.di.epfl.ch
;; [dean] - Dean Andrews ada@unison.com
-;;
+;; [alon] - Alon Albert al@mercury.co.il
;;; Code
(eval-when-compile (require 'cl))
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 trigger `goto-index-pos'.")
+used to invoke `imenu'.")
(defvar imenu-sort-function nil
"*The function to use for sorting the index mouse-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.")
(defvar imenu-max-items 25
"*Maximum number of elements in an index mouse-menu.")
(defvar 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'.")
It should be a function that takes no arguments and returns an index
of the current buffer as an alist. The elements in the alist look
like: (INDEX-NAME . INDEX-POSITION). You may also nest index list like
-(INDEX-NAME . INDEX-ALIST).
+\(INDEX-NAME . INDEX-ALIST).
This function is called within a `save-excursion'.
The variable is buffer-local.")
(make-variable-buffer-local 'imenu-create-index-function)
-(defvar prev-index-position-function 'beginning-of-defun
+(defvar imenu-prev-index-position-function 'beginning-of-defun
"Function for finding the next index position.
If `imenu-create-index-function' is set to
The function should leave point at the place to be connected to the
index and it should return nil when it doesn't find another index. ")
-(make-variable-buffer-local 'prev-index-position-function)
+(make-variable-buffer-local 'imenu-prev-index-position-function)
-(defvar extract-index-name-function nil
+(defvar imenu-extract-index-name-function nil
"Function for extracting the index name.
This function is called after the function pointed out by
-`prev-index-position-function'.")
-(make-variable-buffer-local 'extract-index-name-function)
+`imenu-prev-index-position-function'.")
+(make-variable-buffer-local 'imenu-extract-index-name-function)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
(/ (* 100 (1- pos)) (max total 1)))))
;;;
-;;; Macro to display a progress message. This will probably be used
-;;; in a tight loop, that is why we use a macro.
+;;; 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.
-(defmacro imenu-progress-message (&optional relpos reverse)
+;;; PREVPOS is the variable in which we store the last position displayed.
+(defmacro imenu-progress-message (prevpos &optional relpos reverse)
(` (and
imenu-scanning-message
- (message imenu-scanning-message
- (, (if relpos
+ (let ((pos (, (if relpos
relpos
- (` (imenu--relative-position (, reverse)))))))))
+ (` (imenu--relative-position (, reverse)))))))
+ (if (, (if relpos t
+ (` (> pos (+ 5 (, prevpos))))))
+ (progn
+ (message imenu-scanning-message pos)
+ (setq (, prevpos) pos)))))))
;;;
;;; Function for suporting general looking submenu names.
(error "No items suitable for an index found in this buffer."))
;; Add a rescan option to the index.
(cons imenu--rescan-item imenu--index-alist))
-
+;;;
+;;; Find all markers in alist and makes
+;;; them point nowhere.
+;;;
+(defun imenu--cleanup (&optional alist)
+ ;; Sets the markers in imenu--index-alist
+ ;; point nowhere.
+ ;; if alist is provided use that list.
+ (and imenu--index-alist
+ (mapc
+ (function
+ (lambda (item)
+ (cond
+ ((markerp (cdr item))
+ (set-marker (cdr item) nil))
+ ((listp (cdr item))
+ (imenu--cleanup (cdr item))))))
+ (if alist alist imenu--index-alist))
+ t))
(defun imenu-default-create-index-function ()
"*Wrapper for index searching functions.
Moves point to end of buffer and then repeatedly calls
-`prev-index-position-function' and `extract-index-name-function'.
+`imenu-prev-index-position-function' and `imenu-extract-index-name-function'.
Their results are gathered into an index alist."
-
- (or (and (fboundp prev-index-position-function)
- (fboundp extract-index-name-function))
- (error "The mode \"%s\" does not take full advantage of imenu.el yet."
- mode-name))
- (let ((index-alist '())
- name)
- (goto-char (point-max))
- (imenu-progress-message 0 t)
- ;; Search for the function
- (while (funcall prev-index-position-function)
- (imenu-progress-message nil t)
- (save-excursion
- (setq name (funcall extract-index-name-function)))
- (and (stringp name)
- (push (cons name (point)) index-alist)))
- (imenu-progress-message 100 t)
- index-alist))
+ ;; These should really be done by setting imenu-create-index-function
+ ;; in these major modes. But save that change for later.
+ (cond ((eq major-mode 'emacs-lisp-mode)
+ (imenu-example--create-lisp-index))
+ ((eq major-mode 'lisp-mode)
+ (imenu-example--create-lisp-index))
+ ((eq major-mode 'c++-mode)
+ (imenu-example--create-c++-index))
+ ((eq major-mode 'c-mode)
+ (imenu-example--create-c-index))
+ (t
+ (or (and (fboundp imenu-prev-index-position-function)
+ (fboundp imenu-extract-index-name-function))
+ (error "The mode \"%s\" does not take full advantage of imenu.el yet."
+ mode-name))
+ (let ((index-alist '())
+ name prev-pos)
+ (goto-char (point-max))
+ (imenu-progress-message prev-pos 0 t)
+ ;; Search for the function
+ (while (funcall imenu-prev-index-position-function)
+ (imenu-progress-message prev-pos nil t)
+ (save-excursion
+ (setq name (funcall imenu-extract-index-name-function)))
+ (and (stringp name)
+ (push (cons name (point)) index-alist)))
+ (imenu-progress-message prev-pos 100 t)
+ index-alist))))
(defun imenu--replace-spaces (name replacement)
;; Replace all spaces in NAME with REPLACEMENT.
(concat prefix imenu-level-separator name)
name))))
(cond
- ((numberp pos)
+ ((or (markerp pos) (numberp pos))
(list (cons new-prefix pos)))
(t
(imenu--flatten-index-alist pos new-prefix))))))
(with-output-to-temp-buffer "*Completions*"
(display-completion-list
(all-completions "" prepared-index-alist )))
- ;; Make a completion question
- (setq name (completing-read (or prompt "Index item: ")
+ (let ((minibuffer-setup-hook
+ (function (lambda ()
+ (let ((buffer (current-buffer)))
+ (save-excursion
+ (set-buffer "*Completions*")
+ (setq completion-reference-buffer buffer)))))))
+ ;; Make a completion question
+ (setq name (completing-read (or prompt "Index item: ")
prepared-index-alist
- nil t nil 'imenu--history-list)))
- (cond
- ((not (stringp name))
- nil)
- ((string= name (car imenu--rescan-item))
- t)
- (t
- (setq choice (assoc name prepared-index-alist))
- (cond
- ((listp (cdr choice))
- (imenu--completion-buffer (cdr choice) prompt))
- (t
- choice))))))
+ nil t nil 'imenu--history-list))))
+ (cond ((not (stringp name))
+ nil)
+ ((string= name (car imenu--rescan-item))
+ t)
+ (t
+ (setq choice (assoc name prepared-index-alist))
+ (if (listp (cdr choice))
+ (imenu--completion-buffer (cdr choice) prompt)
+ choice)))))
+
(defun imenu--mouse-menu (index-alist event &optional title)
"Let the user select from a buffer index from a mouse menu.
The returned value is on the form (INDEX-NAME . INDEX-POSITION)."
(let (index-alist
- (mouse-triggered (listp last-command-event))
+ (mouse-triggered (listp last-nonmenu-event))
(result t) )
;; If selected by mouse, see to that the window where the mouse is
;; really is selected.
(and mouse-triggered
- (let ((window (posn-window (event-start last-command-event))))
+ (let ((window (posn-window (event-start last-nonmenu-event))))
(or (framep window) (select-window window))))
;; Create a list for this buffer only when needed.
(while (eq result t)
(setq result
(if (and mouse-triggered
(not imenu-always-use-completion-buffer-p))
- (imenu--mouse-menu index-alist last-command-event)
+ (imenu--mouse-menu index-alist last-nonmenu-event)
(imenu--completion-buffer index-alist prompt)))
(and (eq result t)
+ (imenu--cleanup)
(setq imenu--index-alist nil)))
result))
-(defun goto-index-pos ()
- "Jump to selected part of buffer, using a buffer menu or mouse menu.
-
+(defun imenu-add-to-menubar (name)
+ "Adds an \"imenu\" entry to the menubar for the
+current local keymap.
+NAME is the string naming the menu to be added.
+See 'imenu' for more information."
+ (interactive "sMenu name: ")
+ (and window-system
+ (define-key (current-local-map) [menu-bar index]
+ (cons name 'imenu))))
+
+;;;###autoload
+(defun imenu ()
+ "Jump to a place in the buffer chosen using a buffer menu or mouse menu.
See `imenu-choose-buffer-index' for more information."
(interactive)
(let ((index-item (imenu-choose-buffer-index)))
(and index-item
(progn
(push-mark)
- (goto-char (cdr index-item))))))
+ (cond
+ ((markerp (cdr index-item))
+ (goto-char (marker-position (cdr index-item))))
+ (t
+ (goto-char (cdr index-item))))))))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Return the current/previous sexp and the location of the sexp (it's
+;; Return the current/previous sexp and the location of the sexp (its
;; beginning) without moving the point.
(defun imenu-example--name-and-position ()
(save-excursion
(forward-sexp -1)
(let ((beg (point))
- (end (progn (forward-sexp) (point))))
+ (end (progn (forward-sexp) (point)))
+ (marker (make-marker)))
+ (set-marker marker beg)
(cons (buffer-substring beg end)
- beg))))
+ marker))))
;;;
;;; Lisp
(let ((index-alist '())
(index-var-alist '())
(index-type-alist '())
- (index-unknown-alist '()))
+ (index-unknown-alist '())
+ prev-pos)
(goto-char (point-max))
- (imenu-progress-message 0)
+ (imenu-progress-message prev-pos 0)
;; Search for the function
(while (beginning-of-defun)
- (imenu-progress-message nil t)
+ (imenu-progress-message prev-pos nil t)
(save-match-data
(and (looking-at "(def")
(save-excursion
(forward-sexp 2)
(push (imenu-example--name-and-position)
index-unknown-alist)))))))
- (imenu-progress-message 100)
+ (imenu-progress-message prev-pos 100)
(and index-var-alist
(push (cons (imenu-create-submenu-name "Variables") index-var-alist)
index-alist))
(defun imenu-example--create-c-index (&optional regexp)
(let ((index-alist '())
- (char))
+ prev-pos char)
(goto-char (point-min))
- (imenu-progress-message 0)
+ (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)
+ (imenu-progress-message prev-pos)
(backward-up-list 1)
(save-excursion
(goto-char (scan-sexps (point) 1))
;; 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 100)
+ (imenu-progress-message prev-pos 100)
(nreverse index-alist)))
;;;
(defun imenu-example--create-c++-index ()
(imenu-example--create-c-index imenu-example--function-name-regexp-c++))
-
-;;;
-;;; Example of hooks for the examples above
-;;; Put this in your .emacs.
-;;;
-;; (add-hook 'emacs-lisp-mode-hook
-;; (function
-;; (lambda ()
-;; (setq imenu-create-index-function
-;; (function imenu-example--create-lisp-index)))))
-
-;; (add-hook 'lisp-mode-hook
-;; (function
-;; (lambda ()
-;; (setq imenu-create-index-function
-;; (function imenu-example--create-lisp-index)))))
-
-;; (add-hook 'c++-mode-hook
-;; (function
-;; (lambda ()
-;; (setq imenu-create-index-function
-;; (function imenu-example--create-c++-index)))))
-
-;; (add-hook 'c-mode-hook
-;; (function
-;; (lambda ()
-;; (setq imenu-create-index-function
-;; (function imenu-example--create-c-index)))))
-
(provide 'imenu)
;;; imenu.el ends here