(insert-parentheses): Don't insert spaces at beginning and end of buffer.
[bpt/emacs.git] / lisp / imenu.el
index 64b70d2..efac45d 100644 (file)
@@ -5,7 +5,7 @@
 ;; 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.
@@ -95,7 +86,7 @@
 ;;; 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.
@@ -126,14 +117,14 @@ Set it to `imenu--sort-by-name' if you want alphabetic sorting.
 
 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'.")
@@ -159,14 +150,14 @@ with name concatenation.")
 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
@@ -176,14 +167,14 @@ file.
 
 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)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;
@@ -231,18 +222,22 @@ This function is called after the function pointed out by
       (/ (* 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.
@@ -301,31 +296,59 @@ This function is called after the function pointed out by
       (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.
@@ -354,7 +377,7 @@ Their results are gathered into an index alist."
                                  (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))))))
@@ -384,22 +407,26 @@ Returns t for rescan and otherwise a position number."
       (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.
 
@@ -452,12 +479,12 @@ not.
 
 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)
@@ -465,22 +492,38 @@ The returned value is on the form (INDEX-NAME . INDEX-POSITION)."
       (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))))))))
+
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;
@@ -489,15 +532,17 @@ See `imenu-choose-buffer-index' for more information."
 ;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-;; 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
@@ -523,12 +568,13 @@ See `imenu-choose-buffer-index' for more information."
   (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
@@ -555,7 +601,7 @@ See `imenu-choose-buffer-index' for more information."
                 (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))
@@ -583,15 +629,15 @@ See `imenu-choose-buffer-index' for more information."
 
 (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))
@@ -599,7 +645,7 @@ See `imenu-choose-buffer-index' for more information."
        ;; 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)))
 
 ;;; 
@@ -617,35 +663,6 @@ See `imenu-choose-buffer-index' for more information."
 (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