]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/which-func.el
Merge from emacs-23
[gnu-emacs] / lisp / progmodes / which-func.el
index 5307445dc0435c525099a8c3800911518413eaf6..9138ce1d01213a78d3f65b35eb66876f0a669fda 100644 (file)
@@ -1,7 +1,7 @@
 ;;; which-func.el --- print current function in mode line
 
-;; Copyright (C) 1994, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-;;           Free Software Foundation, Inc.
+;; Copyright (C) 1994, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006
+;;   2007, 2008, 2009, 2010, 2011  Free Software Foundation, Inc.
 
 ;; Author:   Alex Rezinsky <alexr@msil.sps.mot.com>
 ;;           (doesn't seem to be responsive any more)
@@ -9,10 +9,10 @@
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,9 +20,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -77,7 +75,8 @@
 
 (defcustom which-func-modes
   '(emacs-lisp-mode c-mode c++-mode perl-mode cperl-mode python-mode
-                   makefile-mode sh-mode fortran-mode f90-mode ada-mode)
+                   makefile-mode sh-mode fortran-mode f90-mode ada-mode
+                   diff-mode)
   "List of major modes for which Which Function mode should be used.
 For other modes it is disabled.  If this is equal to t,
 then Which Function mode is enabled in any major mode that supports it."
@@ -146,13 +145,21 @@ Zero means compute the Imenu menu regardless of size."
                 local-map ,which-func-keymap
                 face which-func
                 ;;mouse-face highlight ; currently not evaluated :-(
-                help-echo "mouse-1: go to beginning, mouse-2: toggle rest visibility, mouse-3: go to end")
+                help-echo "mouse-1: go to beginning\n\
+mouse-2: toggle rest visibility\n\
+mouse-3: go to end")
     "]")
   "Format for displaying the function in the mode line."
   :group 'which-func
   :type 'sexp)
 ;;;###autoload (put 'which-func-format 'risky-local-variable t)
 
+(defvar which-func-imenu-joiner-function (lambda (x) (car (last x)))
+  "Function to join together multiple levels of imenu nomenclature.
+Called with a single argument, a list of strings giving the names
+of the menus we had to traverse to get to the item.  Returns a
+single string, the new name of the item.")
+
 (defvar which-func-cleanup-function nil
   "Function to transform a string before displaying it in the mode line.
 The function is called with one argument, the string to display.
@@ -191,7 +198,7 @@ It creates the Imenu index for the buffer, if necessary."
             (or (eq which-func-modes t)
                 (member major-mode which-func-modes))))
 
-  (condition-case nil
+  (condition-case err
       (if (and which-func-mode
               (not (member major-mode which-func-non-auto-modes))
               (or (null which-func-maxout)
@@ -200,6 +207,7 @@ It creates the Imenu index for the buffer, if necessary."
          (setq imenu--index-alist
                (save-excursion (funcall imenu-create-index-function))))
     (error
+     (message "which-func-ff-hook error: %S" err)
      (setq which-func-mode nil))))
 
 (defun which-func-update ()
@@ -218,7 +226,7 @@ It creates the Imenu index for the buffer, if necessary."
              (force-mode-line-update)))
        (error
         (setq which-func-mode nil)
-        (error "Error in which-func-update: %s" info))))))
+        (error "Error in which-func-update: %S" info))))))
 
 ;;;###autoload
 (defalias 'which-func-mode 'which-function-mode)
@@ -235,6 +243,9 @@ continuously displayed in the mode line, in certain major modes.
 With prefix ARG, turn Which Function mode on if arg is positive,
 and off otherwise."
   :global t :group 'which-func
+  (when (timerp which-func-update-timer)
+    (cancel-timer which-func-update-timer))
+  (setq which-func-update-timer nil)
   (if which-function-mode
       ;;Turn it on
       (progn
@@ -246,9 +257,6 @@ and off otherwise."
                   (or (eq which-func-modes t)
                       (member major-mode which-func-modes))))))
     ;; Turn it off
-    (when (timerp which-func-update-timer)
-      (cancel-timer which-func-update-timer))
-    (setq which-func-update-timer nil)
     (dolist (buf (buffer-list))
       (with-current-buffer buf (setq which-func-mode nil)))))
 
@@ -275,32 +283,43 @@ If no function name is found, return nil."
               (null which-function-imenu-failed))
       (imenu--make-index-alist t)
       (unless imenu--index-alist
-       (make-local-variable 'which-function-imenu-failed)
-       (setq which-function-imenu-failed t)))
+        (set (make-local-variable 'which-function-imenu-failed) t)))
     ;; If we have an index alist, use it.
     (when (and (null name)
               (boundp 'imenu--index-alist) imenu--index-alist)
       (let ((alist imenu--index-alist)
             (minoffset (point-max))
-            offset elem pair mark)
-        (while alist
-          (setq elem  (car-safe alist)
-                alist (cdr-safe alist))
-          ;; Elements of alist are either ("name" . marker), or
-          ;; ("submenu" ("name" . marker) ... ).
-          (unless (listp (cdr elem))
-              (setq elem (list elem)))
-          (while elem
-            (setq pair (car elem)
-                  elem (cdr elem))
-            (and (consp pair)
-                 (number-or-marker-p (setq mark (cdr pair)))
-                 (if (>= (setq offset (- (point) mark)) 0)
-                     (if (< offset minoffset) ; find the closest item
-                         (setq minoffset offset
-                               name (car pair)))
-                   ;; Entries in order, so can skip all those after point.
-                   (setq elem nil)))))))
+            offset pair mark imstack namestack)
+        ;; Elements of alist are either ("name" . marker), or
+        ;; ("submenu" ("name" . marker) ... ). The list can be
+        ;; arbitrarily nested.
+        (while (or alist imstack)
+          (if (null alist)
+              (setq alist     (car imstack)
+                    namestack (cdr namestack)
+                    imstack   (cdr imstack))
+
+            (setq pair (car-safe alist)
+                  alist (cdr-safe alist))
+
+            (cond
+             ((atom pair))              ; Skip anything not a cons.
+
+             ((imenu--subalist-p pair)
+              (setq imstack   (cons alist imstack)
+                    namestack (cons (car pair) namestack)
+                    alist     (cdr pair)))
+
+             ((number-or-marker-p (setq mark (cdr pair)))
+              (when (and (>= (setq offset (- (point) mark)) 0)
+                         (< offset minoffset)) ; Find the closest item.
+                (setq minoffset offset
+                      name (if (null which-func-imenu-joiner-function)
+                               (car pair)
+                             (funcall
+                              which-func-imenu-joiner-function
+                              (reverse (cons (car pair) namestack))))))))))))
+
     ;; Try using add-log support.
     (when (and (null name) (boundp 'add-log-current-defun-function)
               add-log-current-defun-function)