(Flist_fonts): EXFUN it.
[bpt/emacs.git] / lisp / speedbar.el
index a48f480..e5ab181 100644 (file)
@@ -1,6 +1,7 @@
 ;;; speedbar --- quick access to files and tags in a frame
 
-;;; Copyright (C) 1996, 97, 98, 99, 00, 01, 02, 03, 04, 05 Free Software Foundation
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+;;   2005, 2006 Free Software Foundation, Inc.
 
 ;; Author: Eric M. Ludlam <zappo@gnu.org>
 ;; Keywords: file, tags, tools
@@ -56,6 +57,73 @@ this version is not backward compatible to 0.14 or earlier.")
 ;;     http://www.dina.kvl.dk/~abraham/custom/
 ;;     custom is available in all versions of Emacs version 20 or better.
 ;;
+;;; Developing for speedbar
+;;
+;; Adding a speedbar specialized display mode:
+;;
+;; Speedbar can be configured to create a special display for certain
+;; modes that do not display traditional file/tag data.  Rmail, Info,
+;; and the debugger are examples.  These modes can, however, benefit
+;; from a speedbar style display in their own way.
+;;
+;; If your `major-mode' is `foo-mode', the only requirement is to
+;; create a function called `foo-speedbar-buttons' which takes one
+;; argument, BUFFER.  BUFFER will be the buffer speedbar wants filled.
+;; In `foo-speedbar-buttons' there are several functions that make
+;; building a speedbar display easy.  See the documentation for
+;; `speedbar-with-writable' (needed because the buffer is usually
+;; read-only) `speedbar-make-tag-line', `speedbar-insert-button', and
+;; `speedbar-insert-generic-list'.  If you use
+;; `speedbar-insert-generic-list', also read the doc for
+;; `speedbar-tag-hierarchy-method' in case you wish to override it.
+;; The macro `speedbar-with-attached-buffer' brings you back to the
+;; buffer speedbar is displaying for.
+;;
+;; For those functions that make buttons, the "function" should be a
+;; symbol that is the function to call when clicked on.  The "token"
+;; is extra data you can pass along.  The "function" must take three
+;; parameters.  They are (TEXT TOKEN INDENT).  TEXT is the text of the
+;; button clicked on.  TOKEN is the data passed in when you create the
+;; button.  INDENT is an indentation level, or 0.  You can store
+;; indentation levels with `speedbar-make-tag-line' which creates a
+;; line with an expander (eg.  [+]) and a text button.
+;;
+;; Some useful functions when writing expand functions, and click
+;; functions are `speedbar-change-expand-button-char',
+;; `speedbar-delete-subblock', and `speedbar-center-buffer-smartly'.
+;; The variable `speedbar-power-click' is set to t in your functions
+;; when the user shift-clicks.  This is an indication of anything from
+;; refreshing cached data to making a buffer appear in a new frame.
+;;
+;; If you wish to add to the default speedbar menu for the case of
+;; `foo-mode', create a variable `foo-speedbar-menu-items'.  This
+;; should be a list compatible with the `easymenu' package.  It will
+;; be spliced into the main menu.  (Available with click-mouse-3).  If
+;; you wish to have extra key bindings in your special mode, create a
+;; variable `foo-speedbar-key-map'.  Instead of using `make-keymap',
+;; or `make-sparse-keymap', use the function
+;; `speedbar-make-specialized-keymap'.  This lets you inherit all of
+;; speedbar's default bindings with low overhead.
+;;
+;; Adding a speedbar top-level display mode:
+;;
+;; Unlike the specialized modes, there are no name requirements,
+;; however the methods for writing a button display, menu, and keymap
+;; are the same.  Once you create these items, you can call the
+;; function `speedbar-add-expansion-list'.  It takes one parameter
+;; which is a list element of the form (NAME MENU KEYMAP &rest
+;; BUTTON-FUNCTIONS).  NAME is a string that will show up in the
+;; Displays menu item.  MENU is a symbol containing the menu items to
+;; splice in.  KEYMAP is a symbol holding the keymap to use, and
+;; BUTTON-FUNCTIONS are the function names to call, in order, to create
+;; the display.
+;;  Another tweakable variable is `speedbar-stealthy-function-list'
+;; which is of the form (NAME &rest FUNCTION ...).  NAME is the string
+;; name matching `speedbar-add-expansion-list'.  (It does not need to
+;; exist.). This provides additional display info which might be
+;; time-consuming to calculate.
+;;  Lastly, `speedbar-mode-functions-list' allows you to set special
+;; function overrides.
 
 ;;; TODO:
 ;; - Timeout directories we haven't visited in a while.
@@ -435,7 +503,7 @@ hierarchy would be replaced with the new directory."
   :type 'hook)
 
 (defcustom speedbar-after-create-hook '(speedbar-frame-reposition-smartly)
-  "*Hooks called before popping up the speedbar frame."
+  "*Hooks called after popping up the speedbar frame."
   :group 'speedbar
   :type 'hook)
 
@@ -853,8 +921,6 @@ This basically creates a sparse keymap, and makes it's parent be
    (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
        (list ["Customize..." speedbar-customize t]))
    (list
-    ["Detach" speedbar-detach (and speedbar-frame
-                                   (eq (selected-frame) speedbar-frame)) ]
     ["Close" dframe-close-frame t]
     ["Quit" delete-frame t] ))
   "Menu items appearing at the end of the speedbar menu.")
@@ -979,21 +1045,6 @@ supported at a time.
                                  (dframe-attached-frame speedbar-frame)
                                  speedbar-default-position))))
 
-(defun speedbar-detach ()
-  "Detach the current Speedbar from auto-updating.
-Doing this allows the creation of a second speedbar."
-  (interactive)
-  (let ((buffer speedbar-buffer))
-    (dframe-detach 'speedbar-frame 'speedbar-cached-frame 'speedbar-buffer)
-    (save-excursion
-      (set-buffer buffer)
-      ;; Permanently disable auto-updating in this speedbar buffer.
-      (set (make-local-variable 'speedbar-update-flag) nil)
-      (set (make-local-variable 'speedbar-update-flag-disable) t)
-      ;; Make local copies of all the different variables to prevent
-      ;; funny stuff later...
-      )))
-
 (defsubst speedbar-current-frame ()
   "Return the frame to use for speedbar based on current context."
   (dframe-current-frame 'speedbar-frame 'speedbar-mode))
@@ -1018,10 +1069,10 @@ selected.  If the speedbar frame is active, then select the attached frame."
                    (lambda () (let ((speedbar-update-flag t))
                                 (speedbar-timer-fn)))))
 
-(defmacro speedbar-frame-width ()
+(defsubst speedbar-frame-width ()
   "Return the width of the speedbar frame in characters.
 nil if it doesn't exist."
-  '(window-width (get-buffer-window speedbar-buffer)))
+  (frame-width speedbar-frame))
 
 (defun speedbar-mode ()
   "Major mode for managing a display of directories and tags.
@@ -1156,11 +1207,8 @@ and the existence of packages."
                 (speedbar-initial-menu)
               (save-excursion
                 (dframe-select-attached-frame speedbar-frame)
-                (if (local-variable-p
-                     'speedbar-easymenu-definition-special
-                     (current-buffer))
-                    ;; If bound locally, we can use it
-                    speedbar-easymenu-definition-special)))
+                 (eval (nth 1 (assoc speedbar-initial-expansion-list-name
+                               speedbar-initial-expansion-mode-alist)))))
             ;; Dynamic menu stuff
             '("-")
            (list (cons "Displays"
@@ -1707,9 +1755,13 @@ Separators are not active, have no labels, depth, or actions."
 (defun speedbar-make-button (start end face mouse function &optional token)
   "Create a button from START to END, with FACE as the display face.
 MOUSE is the mouse face.  When this button is clicked on FUNCTION
-will be run with the TOKEN parameter (any Lisp object)"
+will be run with the TOKEN parameter (any Lisp object).  If FACE
+is t use the text properties of the string that is passed as an
+argument."
+  (unless (eq face t)
+    (put-text-property start end 'face face))
   (add-text-properties
-   start end `(face ,face mouse-face ,mouse invisible nil
+   start end `(mouse-face ,mouse invisible nil
                speedbar-text ,(buffer-substring-no-properties start end)))
   (if speedbar-use-tool-tips-flag
       (put-text-property start end 'help-echo #'dframe-help-echo))
@@ -2122,7 +2174,7 @@ Groups may optionally contain a position."
   "A wrapper for `try-completion'.
 Passes STRING and ALIST to `try-completion' if ALIST
 passes some tests."
-  (if (and (listp alist) (not (null alist))
+  (if (and (consp alist)
           (listp (car alist)) (stringp (car (car alist))))
       (try-completion string alist)
     nil))
@@ -2422,8 +2474,7 @@ name will have the function FIND-FUN and not token."
 
   ;; Choose the correct method of doodling.
   (if (and speedbar-mode-specific-contents-flag
-          (listp speedbar-special-mode-expansion-list)
-          speedbar-special-mode-expansion-list
+          (consp speedbar-special-mode-expansion-list)
           (local-variable-p
            'speedbar-special-mode-expansion-list
            (current-buffer)))
@@ -2458,23 +2509,22 @@ name will have the function FIND-FUN and not token."
                                  default-directory)
                (speedbar-message nil))))
       ;; Else, we can do a short cut.  No text cache.
-      (let ((cbd (expand-file-name default-directory))
-           )
+      (let ((cbd (expand-file-name default-directory)))
        (set-buffer speedbar-buffer)
        (speedbar-with-writable
-         (erase-buffer)
-         (dolist (func funclst)
-           (setq default-directory cbd)
-           (funcall func cbd 0))
-       (speedbar-reconfigure-keymaps)
-       (goto-char (point-min)))
-       ))))
+         (let* ((window (get-buffer-window speedbar-buffer 0))
+                (p (window-point window))
+                (start (window-start window)))
+           (erase-buffer)
+           (dolist (func funclst)
+             (setq default-directory cbd)
+             (funcall func cbd 0))
+           (speedbar-reconfigure-keymaps)
+           (set-window-point window p)
+           (set-window-start window start)))))))
 
 (defun speedbar-update-directory-contents ()
   "Update the contents of the speedbar buffer based on the current directory."
-
-  (save-excursion
-
     (let ((cbd (expand-file-name default-directory))
          cbd-parent
          (funclst (speedbar-initial-expansion-list))
@@ -2535,17 +2585,21 @@ name will have the function FIND-FUN and not token."
                 (speedbar-directory-line cbd))
            ;; Open it.
            (speedbar-expand-line)
-         (erase-buffer)
-         (cond (use-cache
-                (setq default-directory
-                      (nth (1- (length speedbar-shown-directories))
-                           speedbar-shown-directories))
-                (insert (cdr cache)))
-               (t
-         (dolist (func funclst)
-           (setq default-directory cbd)
-           (funcall func cbd 0)))))
-       (goto-char (point-min)))))
+         (let* ((window (get-buffer-window speedbar-buffer 0))
+                (p (window-point window))
+                (start (window-start window)))
+           (erase-buffer)
+           (cond (use-cache
+                  (setq default-directory
+                        (nth (1- (length speedbar-shown-directories))
+                             speedbar-shown-directories))
+                  (insert (cdr cache)))
+                 (t
+                  (dolist (func funclst)
+                    (setq default-directory cbd)
+           (funcall func cbd 0))))
+           (set-window-point window p)
+           (set-window-start window start)))))
   (speedbar-reconfigure-keymaps))
 
 (defun speedbar-update-special-contents ()
@@ -2570,9 +2624,7 @@ This should only be used by modes classified as special."
          (dolist (func funclst)
            ;; We do not erase the buffer because these functions may
            ;; decide NOT to update themselves.
-           (funcall func specialbuff)))
-
-      (goto-char (point-min))))
+           (funcall func specialbuff)))))
   (speedbar-reconfigure-keymaps))
 
 (defun speedbar-set-timer (timeout)
@@ -2603,7 +2655,6 @@ Also resets scanner functions."
               (frame-visible-p (speedbar-current-frame))
               (not (eq (frame-visible-p (speedbar-current-frame)) 'icon)))
          (let ((af (selected-frame)))
-           (save-window-excursion
              (dframe-select-attached-frame speedbar-frame)
              ;; make sure we at least choose a window to
              ;; get a good directory from
@@ -2613,8 +2664,7 @@ Also resets scanner functions."
                (speedbar-maybe-add-localized-support (current-buffer))
                ;; Update for special mode all the time!
                (if (and speedbar-mode-specific-contents-flag
-                        (listp speedbar-special-mode-expansion-list)
-                        speedbar-special-mode-expansion-list
+                        (consp speedbar-special-mode-expansion-list)
                         (local-variable-p
                          'speedbar-special-mode-expansion-list
                          (current-buffer)))
@@ -2631,14 +2681,8 @@ Also resets scanner functions."
                             "Updating speedbar to special mode: %s...done"
                             major-mode)
                            (speedbar-message nil))))
-                 ;; Update all the contents if directories change!
-                 (if (or (member major-mode speedbar-ignored-modes)
-                         (eq af (speedbar-current-frame))
-                         (not (buffer-file-name)))
-                     nil
-                   (speedbar-update-localized-contents)
-                   ))
-               (select-frame af)))
+                   (speedbar-update-localized-contents))
+               (select-frame af))
            ;; Now run stealthy updates of time-consuming items
            (speedbar-stealthy-updates)))))
   (run-hooks 'speedbar-timer-hook))