(Flist_fonts): EXFUN it.
[bpt/emacs.git] / lisp / speedbar.el
index 4f0e2ed..e5ab181 100644 (file)
@@ -57,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.
@@ -436,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)
 
@@ -854,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.")
@@ -980,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))
@@ -1157,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"
@@ -2462,25 +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
          (let* ((window (get-buffer-window speedbar-buffer 0))
-                (p (window-point window)))
+                (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-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))
@@ -2541,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 ()
@@ -2576,8 +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)
@@ -2608,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
@@ -2635,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))