# HG changeset patch # User Karl Heuer # Date 900089286 0 # Node ID ca02f300fc411c40b1bc1629880a56b12b584c86 # Parent 09db8bddedc53ac2b1223b10a1f160ebe9fbd857 More commentary. (speedbar-xemacsp) Moved definition. (speedbar-initial-expansion-mode-list) was `speedbar-initial-expansion-list' and now has multiple modes. (speedbar-stealthy-function-list) now has mode labels. (speedbar-initial-expansion-list-name, speedbar-previously-used-expansion-list-name, speedbar-special-mode-key-map, speedbar-track-mouse-flag, speedbar-tag-hierarchy-method, speedbar-tag-split-minimum-length, speedbar-tag-regroup-maximum-length, speedbar-hide-button-brackets-flag) New variables (speedbar-special-mode-expansion-list) updated documentation. (speedbar-navigating-speed, speedbar-update-speed) phasing out. (speedbar-vc-indicator) removed space from this var. (speedbar-indicator-separator, speedbar-obj-do-check, speedbar-obj-to-do-point, speedbar-obj-indicator, speedbar-obj-alist, speedbar-indicator-regex) new variables. (speedbar-directory-unshown-regexp) New variable. (speedbar-supported-extension-expressions) Added more extensions. (speedbar-add-supported-extension, speedbar-add-ignored-path-regexp) Made interactive. (speedbar-update-flag) nil w/ no window system. (speedbar-file-key-map) Moved some key bindings from `speedbar-key-map' to this map. (speedbar-make-specialized-keymap) New function. (speedbar-file-key-map) New key map. (speedbar-easymenu-definition-special) Updated to new functions. (speedbar-easymenu-definition-trailer) Changed conditional part. (speedbar-frame-mode) Removed commented code, fixed W32 cursor bug, Updated to better handle terminal frames. (speedbar-switch-buffer-attached-frame) New function. (speedbar-mode) Updated documentation, no local keymap, correct `temp-buffer-show-function' use, enable mouse-tracking. (speedbar-show-info-under-mouse) New function. (speedbar-reconfigure-keymaps) Was `speedbar-reconfigure-menubar'. Enable major display mode specific menus & key maps. (speedbar-temp-buffer-show-function) Fix use of `temp-buffer-show-hook' (speedbar-track-mouse, speedbar-track-mouse-xemacs) New functions. (speedbar-restricted-move, speedbar-restricted-next, speedbar-restricted-prev, speedbar-navigate-list, speedbar-forward-list, speedbar-backward-list) New commands. (speedbar-refresh) Updated message printing & verbosity. (speedbar-item-load) Updated message. (speedbar-item-byte-compile) Updated doc & reset scanners. (speedbar-item-info) Overhauled with more details. (speedbar-item-copy) Update messages. (speedbar-generic-item-info) New function (speedbar-item-delete) Update messages. (speedbar-item-object-delete) New function. (speedbar-select-window) Update doc. Use `show-buffer'. (speedbar-make-button) Update doc. (speedbar-initial-expansion-list, speedbar-initial-menu, speedbar-initial-keymap, speedbar-initial-stealthy-functions, speedbar-add-expansion-list, speedbar-change-initial-expansion-list) New functions. (speedbar-maybe-add-localized-support, speedbar-add-localized-speedbar-support, speedbar-remove-localized-speedbar-support) Imported from speedbspec (speedbar-file-lists) Filter out some directories. (speedbar-make-tag-line) Can hide brackets. (speedbar-change-expand-button-char) Protect invisible text prop. (speedbar-insert-files-at-point) Ignore case during comares. (speedbar-apply-one-tag-hierarchy-method, speedbar-create-tag-hierarchy) New functions. (speedbar-insert-generic-list) Now calls hierarchy functions on tags. (speedbar-update-contents) Handles localized support. (speedbar-update-directory-contents) Uses fn for expansion list, Fixed directory cacheing bug. (speedbar-timer-fn) Calls localized support function. (speedbar-stealthy-update-recurse) New variable (speedbar-stealthy-updates) Handle new stealth function format. (speedbar-clear-current-file) Handle indicator regex. (speedbar-update-current-file) Ignores case, update handle indicator regex, Fix line positioning. (speedbar-add-indicator) Handles obj indicators now. (speedbar-check-objects, speedbar-check-obj-this-line) New functions. (speedbar-double-click) Fix tripple click error. (speedbar-line-file, speedbar-goto-this-file) Handle indicator regex. (speedbar-line-path) Only try to get a file when in "files" display. (speedbar-line-depth) Handle indicator regex. (speedbar-dir-follow) Turn of smart-adjust to disable cache use. (speedbar-directory-buttons-follow) Hack for W32 emacs directories. (speedbar-buffers-key-map) New key map. (speedbar-buffer-easymenu-definition) New meny items. (speedbar-buffer-buttons, speedbar-buffer-buttons-temp, speedbar-buffer-buttons-engine, speedbar-buffer-click, speedbar-buffer-kill-buffer, speedbar-buffer-revert-buffer) New functions. diff -r 09db8bddedc5 -r ca02f300fc41 lisp/speedbar.el --- a/lisp/speedbar.el Fri Jul 10 16:47:28 1998 +0000 +++ b/lisp/speedbar.el Fri Jul 10 16:48:06 1998 +0000 @@ -1,23 +1,24 @@ -;;; speedbar --- quick access to files and tags +;;; speedbar --- quick access to files and tags in a frame ;;; Copyright (C) 1996, 97, 98 Free Software Foundation -;; -;; Author: Eric M. Ludlam -;; Version: 0.6.2 -;; Keywords: file, tags, tools, convenience -;; + +;; Author: Eric M. Ludlam +;; Version: 0.7 +;; Keywords: file, tags, tools +;; X-RCS: $Id: speedbar.el,v 1.112 1998/06/16 12:53:18 kwzh Exp kwzh $ + ;; This file is part of GNU Emacs. -;; + ;; 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 2, 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 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; 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., 59 Temple Place - Suite 330, @@ -32,8 +33,7 @@ ;; Starting Speedbar: ;; ;; If speedbar came to you as a part of Emacs, simply type -;; `M-x speedbar', and it will be autoloaded for you. A "Speedbar" -;; submenu will be added under "Tools". +;; `M-x speedbar', and it will be autoloaded for you. ;; ;; If speedbar is not a part of your distribution, then add ;; this to your .emacs file: @@ -41,7 +41,7 @@ ;; (autoload 'speedbar-frame-mode "speedbar" "Popup a speedbar frame" t) ;; (autoload 'speedbar-get-focus "speedbar" "Jump to speedbar frame" t) ;; -;; If you want to choose it from a menu, you can do this: +;; If you want to choose it from a menu, such as "Tools", you can do this: ;; ;; Emacs: ;; (define-key-after (lookup-key global-map [menu-bar tools]) @@ -88,7 +88,7 @@ ;; done before speedbar is loaded. ;; ;; To add new file types to imenu, see the documentation in the -;; file imenu.el that comes with emacs. To add new file types which +;; file imenu.el that comes with Emacs. To add new file types which ;; etags supports, you need to modify the variable ;; `speedbar-fetch-etags-parse-list'. ;; @@ -101,7 +101,16 @@ ;; The delay time before this happens is in ;; `speedbar-navigating-speed', and defaults to 10 seconds. ;; -;; Users XEmacs previous to 20 may want to change the default +;; To enable mouse tracking with information in the minibuffer of +;; the attached frame, use the variable `speedbar-track-mouse-flag'. +;; +;; Tag layout can be modified through `speedbar-tag-hierarchy-method', +;; which controls how tags are layed out. It is actually a list of +;; functions that filter the data. The default groups large tag lists +;; into sub-lists. A long flat list can be used instead if needed. +;; Other filters could be easily added. +;; +;; Users of XEmacs previous to 20 may want to change the default ;; timeouts for `speedbar-update-speed' to something longer as XEmacs ;; doesn't have idle timers, the speedbar timer keeps going off ;; arbitrarily while you're typing. It's quite pesky. @@ -111,10 +120,6 @@ ;; display after changing directories. Remember, do not interrupt the ;; stealthy updates or your display may not be completely refreshed. ;; -;; See optional file `speedbspec.el' for additional configurations -;; which allow speedbar to create specialized lists for special modes -;; that are not file-related. -;; ;; AUC-TEX users: The imenu tags for AUC-TEX mode don't work very ;; well. Use the imenu keywords from tex-mode.el for better results. ;; @@ -122,211 +127,90 @@ ;; and the package custom (for easy configuration of speedbar) ;; http://www.dina.kvl.dk/~abraham/custom/ ;; -;; If you do not have custom installed, you can still get face colors -;; by modifying the faces directly in your .emacs file, or setting -;; them in your .Xdefaults file. -;; Here is an example .Xdefaults for a dark background: +;;; 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 tradition file/tag data. Rmail, Info, +;; and the debugger are examples. These modes can, however, benefit +;; from a speedbar style display in their own way. ;; -;; emacs*speedbar-button-face.attributeForeground: Aquamarine -;; emacs*speedbar-selected-face.attributeForeground: red -;; emacs*speedbar-selected-face.attributeUnderline: true -;; emacs*speedbar-directory-face.attributeForeground: magenta -;; emacs*speedbar-file-face.attributeForeground: green3 -;; emacs*speedbar-highlight-face.attributeBackground: sea green -;; emacs*speedbar-tag-face.attributeForeground: yellow - -;;; Speedbar updates can be found at: -;; ftp://ftp.ultranet.com/pub/zappo/speedbar*.tar.gz +;; 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 function `speedbar-with-attached-buffer' brings you back to the +;; buffer speedbar is displaying for. ;; - -;;; Change log: -;; 0.1 Initial Revision -;; 0.2 Fixed problem with x-pointer-shape causing future frames not -;; to be created. -;; Fixed annoying habit of `speedbar-update-contents' to make -;; it possible to accidentally kill the speedbar buffer. -;; Clicking directory names now only changes the contents of -;; the speedbar, and does not cause a dired mode to appear. -;; Clicking the <+> next to the directory does cause dired to -;; be run. -;; Added XEmacs support, which means timer support moved to a -;; platform independant call. -;; Added imenu support. Now modes are supported by imenu -;; first, and etags only if the imenu call doesn't work. -;; Imenu is a little faster than etags, and is more emacs -;; friendly. -;; Added more user control variables described in the commentary. -;; Added smart recentering when nodes are opened and closed. -;; 0.3 x-pointer-shape fixed for emacs 19.35, so I put that check in. -;; Added invisible codes to the beginning of each line. -;; Added list aproach to node expansion for easier addition of new -;; types of things to expand by -;; Added multi-level path name support -;; Added multi-level tag name support. -;; Only mouse-2 is now used for node expansion -;; Added keys e + - to edit expand, and contract node lines -;; Added longer legal file regexp for all those modes which support -;; imenu. (pascal, fortran90, ada, pearl) -;; Added pascal support to etags from Dave Penkler -;; Fixed centering algorithm -;; Tried to choose background independent colors. Made more robust. -;; Rearranged code into a more logical order -;; 0.3.1 Fixed doc & broken keybindings -;; Added mode hooks. -;; Improved color selection to be background mode smart -;; `nil' passed to `speedbar-frame-mode' now toggles the frame as -;; advertised in the doc string -;; 0.4a Added modified patch from Dan Schmidt allowing a -;; directory cache to be maintained speeding up revisiting of files. -;; Default raise-lower behavior is now off by default. -;; Added some menu items for edit expand and contract. -;; Pre 19.31 emacsen can run without idle timers. -;; Added some patch information from Farzin Guilak -;; adding xemacs specifics, and some etags upgrades. -;; Added ability to set a faces symbol-value to a string -;; representing the desired foreground color. (idea from -;; Farzin Guilak, but implemented differently) -;; Fixed problem with 1 character buttons. -;; Added support for new Imenu marker technique. -;; Added `speedbar-load-hooks' for things to run only once on -;; load such as updating one of the many lists. -;; Added `speedbar-supported-extension-expressions' which is a -;; list of extensions that speedbar will tag. This variable -;; should only be updated with `speedbar-add-supported-extension' -;; Moved configure dialog support to a separate file so -;; speedbar is not dependant on eieio to run -;; Fixed list-contraction problem when the item was at the end -;; of a sublist. -;; Fixed XEmacs multi-frame timer selecting bug problem. -;; Added `speedbar-ignored-modes' which is a list of major modes -;; speedbar will not follow when it is displayed in the selected frame -;; 0.4 When the file being edited is not in the list, and is a file -;; that should be in the list, the speedbar cache is replaced. -;; Temp buffers are now shown in the attached frame not the -;; speedbar frame -;; New variables `speedbar-vc-*' and `speedbar-stealthy-function-list' -;; added. `speedbar-update-current-file' is now a member of -;; the stealthy list. New function `speedbar-check-vc' will -;; examine each file and mark it if it is checked out. To -;; add new version control types, override the function -;; `speedbar-this-file-in-vc' and `speedbar-vc-check-dir-p'. -;; The stealth list is interruptible so that long operations -;; do not interrupt someones editing flow. Other long -;; speedbar updates will be added to the stealthy list in the -;; future should interesting ones be needed. -;; Added many new functions including: -;; `speedbar-item-byte-compile' `speedbar-item-load' -;; `speedbar-item-copy' `speedbar-item-rename' `speedbar-item-delete' -;; and `speedbar-item-info' -;; If the user kills the speedbar buffer in some way, the frame will -;; be removed. -;; 0.4.1 Bug fixes -;; added `speedbar-update-flag', -;; XEmacs fixes for menus, and tag sorting, and quit key. -;; Modeline now updates itself based on window-width. -;; Frame is cached when closed to make pulling it up again faster. -;; Speedbars window is now marked as dedicated. -;; Added bindings: -;; Long directories are now span multiple lines autmoatically -;; Added `speedbar-directory-button-trim-method' to specify how to -;; sorten the directory button to fit on the screen. -;; 0.4.2 Add one level of full-text cache. -;; Add `speedbar-get-focus' to switchto/raise the speedbar frame. -;; Editing thing-on-line will auto-raise the attached frame. -;; Bound `U' to `speedbar-up-directory' command. -;; Refresh will now maintain all subdirectories that were open -;; when the refresh was requested. (This does not include the -;; tags, only the directories) -;; 0.4.3 Bug fixes -;; 0.4.4 Added `speedbar-ignored-path-expressions' and friends. -;; Configuration menu items not displayed if dialog-mode not present -;; Speedbar buffer now starts with a space, and is not deleted -;; ewhen the speedbar frame is closed. This prevents the invisible -;; frame from preventing buffer switches with other buffers. -;; Fixed very bad bug in the -add-[extension|path] functions. -;; Added `speedbar-find-file-in-frame' which will always pop up a frame -;; that is already display a buffer selected in the speedbar buffer. -;; Added S-mouse2 as "power click" for always poping up a new frame. -;; and always rescanning with imenu (ditching the imenu cache), and -;; always rescanning directories. -;; 0.4.5 XEmacs bugfixes and enhancements. -;; Window Title simplified. -;; 0.4.6 Fixed problems w/ dedicated minibuffer frame. -;; Fixed errors reported by checkdoc. -;; 0.5 Mode-specific contents added. Controlled w/ the variable -;; `speedbar-mode-specific-contents-flag'. See speedbspec -;; for info on enabling this feature. -;; `speedbar-load-hook' name change and pointer check against -;; major-mode. Suggested by Sam Steingold -;; Quit auto-selects the attached frame. -;; Ranamed `speedbar-do-updates' to `speedbar-update-flag' -;; Passes checkdoc. -;; 0.5.1 Advice from ptype@dra.hmg.gb: -;; Use `post-command-idle-hook' in older emacsen -;; `speedbar-sort-tags' now works with imenu. -;; Unknown files (marked w/ ?) can now be operated on w/ -;; file commands. -;; `speedbar-vc-*-hook's for easilly adding new version control systems. -;; Checkin/out w/ vc will reset the scanners and update the * marker. -;; Fixed ange-ftp require compile time problem. -;; Fixed XEmacs menu bar bug. -;; Added `speedbar-activity-change-focus-flag' to control if the -;; focus changes w/ mouse events. -;; Added `speedbar-sort-tags' toggle to the menubar. -;; Added `speedbar-smart-directory-expand-flag' to toggle how -;; new directories might be inserted into the speedbar hierarchy. -;; Added `speedbar-visiting-[tag|file]hook' which is called whenever -;; speedbar pulls up a file or tag in the attached frame. Setting -;; this to `reposition-window' will do nice things to function tags. -;; Fixed text-cache default-directory bug. -;; Emacs 20 char= support. -;; 0.5.2 Customization -;; For older emacsen, you will need to download the new defcustom -;; package to get nice faces for speedbar -;; mouse1 Double-click is now the same as middle click. -;; No mouse pointer shape stuff for XEmacs (is there any?) -;; 0.5.3 Regressive support for non-custom enabled emacsen. -;; Fixed serious problem w/ 0.5.2 and ignored paths. -;; `condition-case' no longer used in timer fcn. -;; `speedbar-edit-line' is now smarter w/ special modes. -;; 0.5.4 Fixed more problems for Emacs 20 so speedbar loads correctly. -;; Updated some documentation strings. -;; Added customization menu item, and customized some more variables. -;; 0.5.5 Fixed so that there can be no ignored paths -;; Added .l & .lsp as lisp, suggested by: sshteingold@cctrading.com -;; You can now adjust height in `speedbar-frame-parameters' -;; XEmacs fix for use of `local-variable-p' -;; 0.5.6 Folded in XEmacs suggestions from Hrvoje Niksic -;; Several custom changes (group definitions, trim-method & others) -;; Keymap changes, and ways to add menu items. -;; Timer use changes for XEmacs 20.4 -;; Regular expression enhancements. -;; 0.6 Fixed up some frame definition stuff, use more convenience fns. -;; Rehashed frame creation code for better compatibility. -;; Fixed setting of kill-buffer hook. -;; Default speedbar has no menubar, mouse-3 is popup menu, -;; XEmacs double-click capability (Hrvoje Niksic ) -;; General documentation fixup. -;; 0.6.1 Fixed button-3 menu for Emacs 20. -;; 0.6.2 Added autoload tag to `speedbar-get-focus' +;; 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 indications 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. ;;; TODO: ;; - More functions to create buttons and options -;; - filtering algorithms to reduce the number of tags/files displayed. ;; - Timeout directories we haven't visited in a while. ;; - Remeber tags when refreshing the display. (Refresh tags too?) ;; - More 'special mode support. -;; - C- Mouse 3 menu too much indirection (require 'assoc) (require 'easymenu) +(defvar speedbar-xemacsp (string-match "XEmacs" emacs-version) + "Non-nil if we are running in the XEmacs environment.") +(defvar speedbar-xemacs20p (and speedbar-xemacsp + (= emacs-major-version 20))) + ;; From custom web page for compatibility between versions of custom: (eval-and-compile (condition-case () (require 'custom) (error nil)) - (if (and (featurep 'custom) (fboundp 'custom-declare-variable)) + (if (and (featurep 'custom) (fboundp 'custom-declare-variable) + ;; Some XEmacsen w/ custom don't have :set keyword. + ;; This protects them against custom. + (fboundp 'custom-initialize-set)) nil ;; We've got what we needed ;; We have the old custom-library, hack around it! (defmacro defgroup (&rest args) @@ -361,23 +245,51 @@ :group 'speedbar) ;;; Code: -(defvar speedbar-xemacsp (string-match "XEmacs" emacs-version) - "Non-nil if we are running in the XEmacs environment.") -(defvar speedbar-xemacs20p (and speedbar-xemacsp (= emacs-major-version 20))) +(defvar speedbar-initial-expansion-mode-alist + '(("buffers" speedbar-buffer-easymenu-definition speedbar-buffers-key-map + speedbar-buffer-buttons) + ("quick buffers" speedbar-buffer-easymenu-definition speedbar-buffers-key-map + speedbar-buffer-buttons-temp) + ;; Files last, means first in the Displays menu + ("files" speedbar-easymenu-definition-special speedbar-file-key-map + speedbar-directory-buttons speedbar-default-directory-list) + ) + "List of named expansion elements for filling the speedbar frame. +These expansion lists are only valid for regular files. Special modes +still get to override this list on a mode-by-mode basis. This list of +lists is of the form (NAME MENU KEYMAP FN1 FN2 ...). NAME is a string +representing the types of things to be displayed. MENU is an easymenu +structure used when in this mode. KEYMAP is a local keymap to install +over the regular speedbar keymap. FN1 ... are functions that will be +called in order. These functions will always get the default +directory to use passed in as the first parameter, and a 0 as the +second parameter. The 0 indicates the uppermost indentation level. +They must assume that the cursor is at the position where they start +inserting buttons.") -(defvar speedbar-initial-expansion-list - '(speedbar-directory-buttons speedbar-default-directory-list) - "List of functions to call to fill in the speedbar buffer. -Whenever a top level update is issued all functions in this list are -run. These functions will always get the default directory to use -passed in as the first parameter, and a 0 as the second parameter. -The 0 indicates the uppermost indentation level. They must assume -that the cursor is at the position where they start inserting -buttons.") +(defcustom speedbar-initial-expansion-list-name "files" + "A symbol name representing the expansion list to use. +The expansion list `speedbar-initial-expansion-mode-alist' contains +the names and associated functions to use for buttons in speedbar." + :group 'speedbar + :type '(radio (const :tag "File Directorys" file) + )) + +(defvar speedbar-previously-used-expansion-list-name "files" + "Save the last expansion list method. +This is used for returning to a previous expansion list method when +the user is done with the current expansion list.") (defvar speedbar-stealthy-function-list - '(speedbar-update-current-file speedbar-check-vc) + '(("files" + speedbar-update-current-file speedbar-check-vc speedbar-check-objects) + ) "List of functions to periodically call stealthily. +This list is of the form: + '( (\"NAME\" FUNCTION ...) + ...) +where NAME is the name of the major display mode these functions are +for, and the remaining elements FUNCTION are functions to call in order. Each function must return nil if interrupted, or t if completed. Stealthy functions which have a single operation should always return t. Functions which take a long time should maintain a state (where @@ -392,16 +304,16 @@ :type 'boolean) (defvar speedbar-special-mode-expansion-list nil - "Mode specific list of functions to call to fill in speedbar. -Some modes, such as Info or RMAIL, do not relate quite as easily into -a simple list of files. When this variable is non-nil and buffer-local, -then these functions are used, creating specialized contents. These -functions are called each time the speedbar timer is called. This -allows a mode to update its contents regularly. + "Default function list for creating specialized button lists. +This list is set by modes that wish to have special speedbar displays. +The list is of function names. Each function is called with one +parameter BUFFER, the originating buffer. The current buffer is the +speedbar buffer.") - Each function is called with the default and frame belonging to -speedbar, and with one parameter; the buffer requesting -the speedbar display.") +(defvar speedbar-special-mode-key-map nil + "Default keymap used when identifying a specialized display mode. +This keymap is local to each buffer that wants to define special keybindings +effective when it's display is shown.") (defcustom speedbar-visiting-file-hook nil "Hooks run when speedbar visits a file in the selected frame." @@ -436,7 +348,10 @@ :group 'speedbar :type 'integer) -(defcustom speedbar-navigating-speed 10 +;; When I moved to a repeating timer, I had the horrible missfortune +;; of loosing the ability for adaptive speed choice. This update +;; speed currently causes long delays when it should have been turned off. +(defcustom speedbar-navigating-speed speedbar-update-speed "*Idle time to wait after navigation commands in speedbar are executed. Navigation commands included expanding/contracting nodes, and moving between different directories." @@ -483,11 +398,51 @@ :group 'speedbar :type 'boolean) +(defcustom speedbar-track-mouse-flag t + "*Non-nil means to display info about the line under the mouse." + :group 'speedbar + :type 'boolean) + (defcustom speedbar-sort-tags nil - "*If Non-nil, sort tags in the speedbar display." + "*If Non-nil, sort tags in the speedbar display. *Obsolete*." :group 'speedbar :type 'boolean) +(defcustom speedbar-tag-hierarchy-method + '(prefix-group trim-words) + "*List of methods which speedbar will use to organize tags into groups. +Groups are defined as expandable meta-tags. Imenu supports such +things in some languages, such as separating variables from functions. +Available methods are: + sort - Sort tags. (sometimes unnecessary) + trim-words - Trim all tags by a common prefix, broken @ word sections. + prefix-group - Try to guess groups by prefix. + simple-group - If imenu already returned some meta groups, stick all + tags that are not in a group into a sub-group." + :group 'speedbar + :type '(repeat + (radio + (const :tag "Sort the tags." sort) + (const :tag "Trim words to common prefix." trim-words) + (const :tag "Create groups from common prefixes." prefix-group) + (const :tag "Group loose tags into their own group." simple-group)) + )) + +(defcustom speedbar-tag-split-minimum-length 20 + "*Minimum length before we stop trying to create sub-lists in tags. +This is used by all tag-hierarchy methods that break large lists into +sub-lists." + :group 'speedbar + :type 'integer) + +(defcustom speedbar-tag-regroup-maximum-length 10 + "*Maximum length of submenus that are regrouped. +If the regrouping option is used, then if two or more short subgroups +are next to each other, then they are combined until this number of +items is reached." + :group 'speedbar + :type 'integer) + (defcustom speedbar-activity-change-focus-flag nil "*Non-nil means the selected frame will change based on activity. Thus, if a file is selected for edit, the buffer will appear in the @@ -518,6 +473,9 @@ :group 'speedbar :type 'boolean) +(defvar speedbar-hide-button-brackets-flag nil + "*Non-nil means speedbar will hide the brackets around the + or -.") + (defcustom speedbar-before-popup-hook nil "*Hooks called before popping up the speedbar frame." :group 'speedbar @@ -545,25 +503,21 @@ :group 'speedbar :type 'integer) +(defvar speedbar-indicator-separator " " + "String separating file text from indicator characters.") + (defcustom speedbar-vc-do-check t "*Non-nil check all files in speedbar to see if they have been checked out. Any file checked out is marked with `speedbar-vc-indicator'" :group 'speedbar-vc :type 'boolean) -(defvar speedbar-vc-indicator " *" +(defvar speedbar-vc-indicator "*" "Text used to mark files which are currently checked out. Currently only RCS is supported. Other version control systems can be added by examining the function `speedbar-this-file-in-vc' and `speedbar-vc-check-dir-p'") -(defcustom speedbar-scanner-reset-hook nil - "*Hook called whenever generic scanners are reset. -Set this to implement your own scanning / rescan safe functions with -state data." - :group 'speedbar - :type 'hook) - (defcustom speedbar-vc-path-enable-hook nil "*Return non-nil if the current path should be checked for Version Control. Functions in this hook must accept one parameter which is the path @@ -581,13 +535,56 @@ (defvar speedbar-vc-to-do-point nil "Local variable maintaining the current version control check position.") +(defcustom speedbar-obj-do-check t + "*Non-nil check all files in speedbar to see if they have an object file. +Any file checked out is marked with `speedbar-obj-indicator', and the +marking is based on `speedbar-obj-alist'" + :group 'speedbar-vc + :type 'boolean) + +(defvar speedbar-obj-to-do-point nil + "Local variable maintaining the current version control check position.") + +(defvar speedbar-obj-indicator '("#" . "!") + "Text used to mark files that have a corresponding hidden object file. +The car is for an up-to-date object. The cdr is for an out of date object. +The expression `speedbar-obj-alist' defines who gets tagged.") + +(defvar speedbar-obj-alist + '(("\\.\\([cpC]\\|cpp\\|cc\\)$" . ".o") + ("\\.el$" . ".elc") + ("\\.java$" . ".class") + ("\\.f\\(or\\|90\\|77\\)?$" . ".o") + ("\\.tex$" . ".dvi") + ("\\.texi$" . ".info")) + "Alist of file extensions, and their corresponding object file type.") + +(defvar speedbar-indicator-regex + (concat (regexp-quote speedbar-indicator-separator) + "\\(" + (regexp-quote speedbar-vc-indicator) + "\\|" + (regexp-quote (car speedbar-obj-indicator)) + "\\|" + (regexp-quote (cdr speedbar-obj-indicator)) + "\\)*") + "Regular expression used when identifying files. +Permits stripping of indicator characters from a line.") + +(defcustom speedbar-scanner-reset-hook nil + "*Hook called whenever generic scanners are reset. +Set this to implement your own scanning / rescan safe functions with +state data." + :group 'speedbar + :type 'hook) + (defvar speedbar-ignored-modes nil "*List of major modes which speedbar will not switch directories for.") (defun speedbar-extension-list-to-regex (extlist) "Takes EXTLIST, a list of extensions and transforms it into regexp. -All the preceding . are stripped for an optimized expression starting -with . followed by extensions, followed by full-filenames." +All the preceding `.' are stripped for an optimized expression starting +with `.' followed by extensions, followed by full-filenames." (let ((regex1 nil) (regex2 nil)) (while extlist (if (= (string-to-char (car extlist)) ?.) @@ -625,6 +622,13 @@ speedbar-ignored-path-regexp (speedbar-extension-list-to-regex val)))) +(defcustom speedbar-directory-unshown-regexp "^\\(CVS\\|RCS\\|SCCS\\)\\'" + "*Regular expression matching directories not to show in speedbar. +They should include commonly existing directories which are not +useful, such as version control." + :group 'speedbar + :type 'string) + (defvar speedbar-file-unshown-regexp (let ((nstr "") (noext completion-ignored-extensions)) (while noext @@ -638,10 +642,13 @@ ;; this is dangerous to customize, because the defaults will probably ;; change in the future. (defcustom speedbar-supported-extension-expressions - (append '(".[CcHh]\\(\\+\\+\\|pp\\|c\\|h\\)?" ".tex\\(i\\(nfo\\)?\\)?" - ".el" ".emacs" ".l" ".lsp" ".p" ".java") + (append '(".[ch]\\(\\+\\+\\|pp\\|c\\|h\\|xx\\)?" ".tex\\(i\\(nfo\\)?\\)?" + ".el" ".emacs" ".l" ".lsp" ".p" ".java" ".f\\(90\\|77\\|or\\)?") (if speedbar-use-imenu-flag - '(".f90" ".ada" ".pl" ".tcl" ".m" + '(".ada" ".pl" ".tcl" ".m" ".scm" ".pm" ".py" + ;; html is not supported by default, but an imenu tags package + ;; is available. Also, html files are nice to be able to see. + ".s?html" "Makefile\\(\\.in\\)?"))) "*List of regular expressions which will match files supported by tagging. Do not prefix the `.' char with a double \\ to quote it, as the period @@ -670,6 +677,7 @@ the dot should NOT be quoted in with \\. Other regular expression matchers are allowed however. EXTENSION may be a single string or a list of strings." + (interactive "sExtionsion: ") (if (not (listp extension)) (setq extension (list extension))) (while extension (if (member (car extension) speedbar-supported-extension-expressions) @@ -684,6 +692,7 @@ "Add PATH-EXPRESSION as a new ignored path for speedbar tracking. This function will modify `speedbar-ignored-path-regexp' and add PATH-EXPRESSION to `speedbar-ignored-path-expressions'." + (interactive "sPath regex: ") (if (not (listp path-expression)) (setq path-expression (list path-expression))) (while path-expression @@ -702,9 +711,11 @@ speedbar-ignored-path-regexp (speedbar-extension-list-to-regex speedbar-ignored-path-expressions))) -(defvar speedbar-update-flag (or (fboundp 'run-with-idle-timer) - (fboundp 'start-itimer) - (boundp 'post-command-idle-hook)) +(defvar speedbar-update-flag (and + (or (fboundp 'run-with-idle-timer) + (fboundp 'start-itimer) + (boundp 'post-command-idle-hook)) + window-system) "*Non-nil means to automatically update the display. When this is nil then speedbar will not follow the attached frame's path. When speedbar is active, use: @@ -727,7 +738,6 @@ (modify-syntax-entry ?[ " " speedbar-syntax-table) (modify-syntax-entry ?] " " speedbar-syntax-table)) - (defvar speedbar-key-map nil "Keymap used in speedbar buffer.") @@ -737,37 +747,49 @@ (suppress-keymap speedbar-key-map t) ;; control - (define-key speedbar-key-map "e" 'speedbar-edit-line) - (define-key speedbar-key-map "\C-m" 'speedbar-edit-line) - (define-key speedbar-key-map "+" 'speedbar-expand-line) - (define-key speedbar-key-map "-" 'speedbar-contract-line) (define-key speedbar-key-map "g" 'speedbar-refresh) (define-key speedbar-key-map "t" 'speedbar-toggle-updates) (define-key speedbar-key-map "q" 'speedbar-close-frame) - (define-key speedbar-key-map "U" 'speedbar-up-directory) ;; navigation (define-key speedbar-key-map "n" 'speedbar-next) (define-key speedbar-key-map "p" 'speedbar-prev) + (define-key speedbar-key-map "\M-n" 'speedbar-restricted-next) + (define-key speedbar-key-map "\M-p" 'speedbar-restricted-prev) + (define-key speedbar-key-map "\C-\M-n" 'speedbar-forward-list) + (define-key speedbar-key-map "\C-\M-p" 'speedbar-backward-list) (define-key speedbar-key-map " " 'speedbar-scroll-up) (define-key speedbar-key-map [delete] 'speedbar-scroll-down) - ;; After much use, I suddenly desired in my heart to perform dired - ;; style operations since the directory was RIGHT THERE! - (define-key speedbar-key-map "I" 'speedbar-item-info) - (define-key speedbar-key-map "B" 'speedbar-item-byte-compile) - (define-key speedbar-key-map "L" 'speedbar-item-load) - (define-key speedbar-key-map "C" 'speedbar-item-copy) - (define-key speedbar-key-map "D" 'speedbar-item-delete) - (define-key speedbar-key-map "R" 'speedbar-item-rename) + ;; Short cuts I happen to find useful + (define-key speedbar-key-map "r" + (lambda () (interactive) + (speedbar-change-initial-expansion-list + speedbar-previously-used-expansion-list-name))) + (define-key speedbar-key-map "b" + (lambda () (interactive) + (speedbar-change-initial-expansion-list "quick buffers"))) + (define-key speedbar-key-map "f" + (lambda () (interactive) + (speedbar-change-initial-expansion-list "files"))) + + ;; Overrides + (substitute-key-definition 'switch-to-buffer + 'speedbar-switch-buffer-attached-frame + speedbar-key-map global-map) (if speedbar-xemacsp (progn ;; mouse bindings so we can manipulate the items on each line (define-key speedbar-key-map 'button2 'speedbar-click) (define-key speedbar-key-map '(shift button2) 'speedbar-power-click) - (define-key speedbar-key-map 'button3 'speedbar-xemacs-popup-kludge) - (define-key speedbar-key-map '(meta button3) 'speedbar-mouse-item-info)) + ;; Info doc fix from Bob Weiner + (if (featurep 'infodoc) + nil + (define-key speedbar-key-map 'button3 'speedbar-xemacs-popup-kludge)) + (define-key speedbar-key-map '(meta button3) 'speedbar-mouse-item-info) + ) + ;; mouse bindings so we can manipulate the items on each line (define-key speedbar-key-map [down-mouse-1] 'speedbar-double-click) (define-key speedbar-key-map [mouse-2] 'speedbar-click) @@ -779,21 +801,47 @@ (define-key speedbar-key-map [down-mouse-3] 'speedbar-emacs-popup-kludge) - ;;***** Disable disabling: Remove menubar completely. - ;; disable all menus - we don't have a lot of space to play with - ;; in such a skinny frame. This will cleverly find and nuke some - ;; user-defined menus as well if they are there. Too bad it - ;; rely's on the structure of a keymap to work. -; (let ((k (lookup-key global-map [menu-bar]))) -; (while k -; (if (and (listp (car k)) (listp (cdr (car k)))) -; (define-key speedbar-key-map (vector 'menu-bar (car (car k))) -; 'undefined)) -; (setq k (cdr k)))) - ;; This lets the user scroll as if we had a scrollbar... well maybe not (define-key speedbar-key-map [mode-line mouse-2] 'speedbar-mouse-hscroll) - )) + ;; another handy place users might click to get our menu. + (define-key speedbar-key-map [mode-line down-mouse-1] + 'speedbar-emacs-popup-kludge) + + ;; Lastly, we want to track the mouse. Play here + (define-key speedbar-key-map [mouse-movement] 'speedbar-track-mouse) + )) + +(defun speedbar-make-specialized-keymap () + "Create a keymap for use w/ a speedbar major or minor display mode. +This basically creates a sparse keymap, and makes it's parent be +`speedbar-key-map'." + (let ((k (make-sparse-keymap))) + (set-keymap-parent k speedbar-key-map) + k)) + +(defvar speedbar-file-key-map nil + "Keymap used in speedbar buffer while files are displayed.") + +(if speedbar-file-key-map + nil + (setq speedbar-file-key-map (speedbar-make-specialized-keymap)) + + ;; Basic tree features + (define-key speedbar-file-key-map "e" 'speedbar-edit-line) + (define-key speedbar-file-key-map "\C-m" 'speedbar-edit-line) + (define-key speedbar-file-key-map "+" 'speedbar-expand-line) + (define-key speedbar-file-key-map "-" 'speedbar-contract-line) + + ;; file based commands + (define-key speedbar-file-key-map "U" 'speedbar-up-directory) + (define-key speedbar-file-key-map "I" 'speedbar-item-info) + (define-key speedbar-file-key-map "B" 'speedbar-item-byte-compile) + (define-key speedbar-file-key-map "L" 'speedbar-item-load) + (define-key speedbar-file-key-map "C" 'speedbar-item-copy) + (define-key speedbar-file-key-map "D" 'speedbar-item-delete) + (define-key speedbar-file-key-map "O" 'speedbar-item-object-delete) + (define-key speedbar-file-key-map "R" 'speedbar-item-rename) + ) (defvar speedbar-easymenu-definition-base '("Speedbar" @@ -807,39 +855,41 @@ '(["Edit Item On Line" speedbar-edit-line t] ["Show All Files" speedbar-toggle-show-all-files :style toggle :selected speedbar-show-unknown-files] - ["Expand Item" speedbar-expand-line + ["Expand File Tags" speedbar-expand-line (save-excursion (beginning-of-line) (looking-at "[0-9]+: *.\\+. "))] - ["Contract Item" speedbar-contract-line + ["Contract File Tags" speedbar-contract-line (save-excursion (beginning-of-line) (looking-at "[0-9]+: *.-. "))] - ["Sort Tags" speedbar-toggle-sorting - :style toggle :selected speedbar-sort-tags] +; ["Sort Tags" speedbar-toggle-sorting +; :style toggle :selected speedbar-sort-tags] "----" - ["Item Information" speedbar-item-info t] + ["File/Tag Information" speedbar-item-info t] ["Load Lisp File" speedbar-item-load (save-excursion (beginning-of-line) - (looking-at "[0-9]+: *\\[[+-]\\] .+\\(\\.el\\)\\( \\*\\)?$"))] + (looking-at "[0-9]+: *\\[[+-]\\] .+\\(\\.el\\)\\( \\|$\\)"))] ["Byte Compile File" speedbar-item-byte-compile (save-excursion (beginning-of-line) - (looking-at "[0-9]+: *\\[[+-]\\] .+\\(\\.el\\)\\( \\*\\)?$"))] - ["Copy Item" speedbar-item-copy + (looking-at "[0-9]+: *\\[[+-]\\] .+\\(\\.el\\)\\( \\|$\\)"))] + ["Copy File" speedbar-item-copy (save-excursion (beginning-of-line) (looking-at "[0-9]+: *\\["))] - ["Rename Item" speedbar-item-rename + ["Rename File" speedbar-item-rename + (save-excursion (beginning-of-line) (looking-at "[0-9]+: *[[<]"))] + ["Delete File" speedbar-item-delete (save-excursion (beginning-of-line) (looking-at "[0-9]+: *[[<]"))] - ["Delete Item" speedbar-item-delete - (save-excursion (beginning-of-line) (looking-at "[0-9]+: *[[<]"))]) + ["Delete Object" speedbar-item-object-delete + (save-excursion (beginning-of-line) + (looking-at "[0-9]+: *\\[[+-]\\] [^ \n]+ \\*?[!#]$"))] + ) "Additional menu items while in file-mode.") (defvar speedbar-easymenu-definition-trailer - (if (and (featurep 'custom) (fboundp 'custom-declare-variable)) - '("----" - ["Customize..." speedbar-customize t] - ["Close" speedbar-close-frame t]) - '("----" - ["Close" speedbar-close-frame t])) + (list + (if (and (featurep 'custom) (fboundp 'custom-declare-variable)) + ["Customize..." speedbar-customize t]) + ["Close" speedbar-close-frame t]) "Menu items appearing at the end of the speedbar menu.") (defvar speedbar-desired-buffer nil @@ -890,21 +940,6 @@ `speedbar-before-popup-hook' is called before popping up the speedbar frame. `speedbar-before-delete-hook' is called before the frame is deleted." (interactive "P") - (if (if (and speedbar-xemacsp (fboundp 'console-on-window-system-p)) - (not (console-on-window-system-p)) - (not (symbol-value 'window-system))) - (error "Speedbar is not useful outside of a windowing environment")) -;;; RMS says this should not modify the menu. -; (if speedbar-xemacsp -; (add-menu-button '("Tools") -; ["Speedbar" speedbar-frame-mode -; :style toggle -; :selected (and (boundp 'speedbar-frame) -; (frame-live-p speedbar-frame) -; (frame-visible-p speedbar-frame))] -; "--") -; (define-key-after (lookup-key global-map [menu-bar tools]) -; [speedbar] '("Speedbar" . speedbar-frame-mode) [calendar])) ;; toggle frame on and off. (if (not arg) (if (and (frame-live-p speedbar-frame) (frame-visible-p speedbar-frame)) @@ -956,7 +991,8 @@ (if speedbar-xemacsp (speedbar-needed-height) (+ mh (frame-height)))))))) - (if (< emacs-major-version 20);;a bug is fixed in v20 & later + (if (or (< emacs-major-version 20);;a bug is fixed in v20 + (not (eq window-system 'x))) (make-frame params) (let ((x-pointer-shape x-pointer-top-left-arrow) (x-sensitive-text-pointer-shape x-pointer-hand2)) @@ -981,10 +1017,15 @@ (if (eq (selected-frame) speedbar-frame) (if (frame-live-p speedbar-attached-frame) (select-frame speedbar-attached-frame)) + ;; If updates are off, then refresh the frame (they want it now...) + (if (not speedbar-update-flag) + (let ((speedbar-update-flag t)) + (speedbar-timer-fn))) ;; make sure we have a frame (if (not (frame-live-p speedbar-frame)) (speedbar-frame-mode 1)) ;; go there - (select-frame speedbar-frame)) + (select-frame speedbar-frame) + ) (other-frame 0)) (defun speedbar-close-frame () @@ -994,6 +1035,18 @@ (select-frame speedbar-attached-frame) (other-frame 0)) +(defun speedbar-switch-buffer-attached-frame (&optional buffer) + "Switch to BUFFER in speedbar's attached frame, and raise that frame. +This overrides the default behavior of `switch-to-buffer' which is +broken because of the dedicated speedbar frame." + (interactive) + ;; Assume we are in the speedbar frame. + (speedbar-get-focus) + ;; Now switch buffers + (if buffer + (switch-to-buffer buffer) + (call-interactively 'switch-to-buffer nil nil))) + (defmacro speedbar-frame-width () "Return the width of the speedbar frame in characters. nil if it doesn't exist." @@ -1032,6 +1085,11 @@ version control systems can be added by examining the documentation for `speedbar-this-file-in-vc' and `speedbar-vc-check-dir-p' +Files with a `#' or `!' character after them are source files that +have an object file associated with them. The `!' indicates that the +files is out of date. You can control what source/object associations +exist through the variable `speedbar-obj-alist'. + Click on the [+] to display a list of tags from that file. Click on the [-] to retract the list. Click on the file name to edit the file in the attached frame. @@ -1048,17 +1106,22 @@ (kill-all-local-variables) (setq major-mode 'speedbar-mode) (setq mode-name "Speedbar") - (use-local-map speedbar-key-map) (set-syntax-table speedbar-syntax-table) (setq font-lock-keywords nil) ;; no font-locking please (setq truncate-lines t) (make-local-variable 'frame-title-format) (setq frame-title-format "Speedbar") ;; Set this up special just for the speedbar buffer - (if (null default-minibuffer-frame) + ;; Terminal minibuffer stuff does not require this. + (if (and window-system (null default-minibuffer-frame)) (progn (make-local-variable 'default-minibuffer-frame) (setq default-minibuffer-frame speedbar-attached-frame))) + ;; Correct use of `temp-buffer-show-function': Bob Weiner + (if (and (boundp 'temp-buffer-show-hook) + (boundp 'temp-buffer-show-function)) + (progn (make-local-variable 'temp-buffer-show-hook) + (setq temp-buffer-show-hook temp-buffer-show-function))) (make-local-variable 'temp-buffer-show-function) (setq temp-buffer-show-function 'speedbar-temp-buffer-show-function) (if speedbar-xemacsp @@ -1088,12 +1151,29 @@ (speedbar-frame-mode -1))))) t t) (speedbar-set-mode-line-format) - (if (not speedbar-xemacsp) - (setq auto-show-mode nil)) ;no auto-show for Emacs + (if speedbar-xemacsp + (progn + (make-local-variable 'mouse-motion-handler) + (setq mouse-motion-handler 'speedbar-track-mouse-xemacs)) + (if speedbar-track-mouse-flag + (progn + (make-local-variable 'track-mouse) + (setq track-mouse t))) ;this could be messy. + (setq auto-show-mode nil)) ;no auto-show for Emacs (run-hooks 'speedbar-mode-hook)) (speedbar-update-contents) speedbar-buffer) +(defun speedbar-show-info-under-mouse (&optional event) + "Call the info function for the line under the mouse. +Optional EVENT is currently not used." + (let ((pos (mouse-position))) ; we ignore event until I use it later. + (if (equal (car pos) speedbar-frame) + (save-excursion + (save-window-excursion + (apply 'set-mouse-position pos) + (speedbar-item-info)))))) + (defun speedbar-set-mode-line-format () "Set the format of the mode line based on the current speedbar environment. This gives visual indications of what is up. It EXPECTS the speedbar @@ -1132,34 +1212,71 @@ (if speedbar-attached-frame (select-frame speedbar-attached-frame)) (pop-to-buffer buffer nil) (other-window -1) - (run-hooks 'temp-buffer-show-hook)) + ;; Fix for using this hook: Bob Weiner + (cond ((fboundp 'run-hook-with-args) + (run-hook-with-args 'temp-buffer-show-hook buffer)) + ((and (boundp 'temp-buffer-show-hook) + (listp temp-buffer-show-hook)) + (mapcar (function (lambda (hook) (funcall hook buffer))) + temp-buffer-show-hook)))) -(defun speedbar-reconfigure-menubar () +(defun speedbar-reconfigure-keymaps () "Reconfigure the menu-bar in a speedbar frame. Different menu items are displayed depending on the current display mode and the existence of packages." - (let ((md (append speedbar-easymenu-definition-base - (if speedbar-shown-directories - ;; file display mode version - speedbar-easymenu-definition-special - (save-excursion - (select-frame speedbar-attached-frame) - (if (local-variable-p - 'speedbar-easymenu-definition-special - (current-buffer)) - ;; If bound locally, we can use it - speedbar-easymenu-definition-special))) - ;; The trailer - speedbar-easymenu-definition-trailer))) - (easy-menu-define speedbar-menu-map speedbar-key-map "Speedbar menu" md) - (if speedbar-xemacsp - (save-excursion - (set-buffer speedbar-buffer) - ;; For the benefit of button3 - (if (and (not (assoc "Speedbar" mode-popup-menu))) - (easy-menu-add md)) - (set-buffer-menubar (list md))) - (easy-menu-add md)))) + (let ((md (append + speedbar-easymenu-definition-base + (if speedbar-shown-directories + ;; file display mode version + (speedbar-initial-menu) + (save-excursion + (select-frame speedbar-attached-frame) + (if (local-variable-p + 'speedbar-easymenu-definition-special + (current-buffer)) + ;; If bound locally, we can use it + speedbar-easymenu-definition-special))) + ;; Dynamic menu stuff + '("-") + (list (cons "Displays" + (let ((displays nil) + (alist speedbar-initial-expansion-mode-alist)) + (while alist + (setq displays + (cons + (vector + (capitalize (car (car alist))) + (list + 'speedbar-change-initial-expansion-list + (car (car alist))) + t) + displays)) + (setq alist (cdr alist))) + displays))) + ;; The trailer + speedbar-easymenu-definition-trailer)) + (localmap (save-excursion + (let ((cf (selected-frame))) + (prog2 + (select-frame speedbar-attached-frame) + (if (local-variable-p + 'speedbar-special-mode-key-map + (current-buffer)) + speedbar-special-mode-key-map) + (select-frame cf)))))) + (save-excursion + (set-buffer speedbar-buffer) + (use-local-map (or localmap + (speedbar-initial-keymap) + ;; This creates a small keymap we can glom the + ;; menu adjustments into. + (speedbar-make-specialized-keymap))) + (if (not speedbar-xemacsp) + (easy-menu-define speedbar-menu-map (current-local-map) + "Speedbar menu" md) + (if (and (not (assoc "Speedbar" mode-popup-menu))) + (easy-menu-add md (current-local-map))) + (set-buffer-menubar (list md)))))) ;;; User Input stuff @@ -1195,6 +1312,34 @@ (select-frame sf)) (speedbar-maybee-jump-to-attached-frame)) +(defun speedbar-track-mouse (event) + "For motion EVENT, display info about the current line." + (interactive "e") + (if (not speedbar-track-mouse-flag) + nil + (save-excursion + (let ((char (nth 1 (car (cdr event))))) + (if (not (numberp char)) + (message nil) + (goto-char char) + ;; (message "%S" event) + (speedbar-item-info) + ))))) + +(defun speedbar-track-mouse-xemacs (event) + "For motion EVENT, display info about the current line." + (if (functionp (default-value 'mouse-motion-handler)) + (funcall (default-value 'mouse-motion-handler) event)) + (if speedbar-track-mouse-flag + (save-excursion + (save-window-excursion + (condition-case () + (progn (mouse-set-point event) + ;; Prevent focus-related bugs. + (if (eq major-mode 'speedbar-mode) + (speedbar-item-info))) + (error nil)))))) + ;; In XEmacs, we make popup menus work on the item over mouse (as ;; opposed to where the point happens to be.) We attain this by ;; temporarily moving the point to that place. @@ -1203,6 +1348,7 @@ "Pop up a menu related to the clicked on item. Must be bound to EVENT." (interactive "e") + (select-frame speedbar-frame) (save-excursion (goto-char (event-closest-point event)) (beginning-of-line) @@ -1241,6 +1387,82 @@ (interactive "p") (speedbar-next (if arg (- arg) -1))) +(defun speedbar-restricted-move (arg) + "Move to the next ARGth line in a speedbar buffer at the same depth. +This means that movement is restricted to a subnode, and that siblings +of intermediate nodes are skipped." + (if (not (numberp arg)) (signal 'wrong-type-argument (list arg 'numberp))) + ;; First find the extent for which we are allowed to move. + (let ((depth (save-excursion (beginning-of-line) + (if (looking-at "[0-9]+:") + (string-to-int (match-string 0)) + 0))) + (crement (if (< arg 0) 1 -1)) ; decrement or increment + (lastmatch (point))) + (while (/= arg 0) + (forward-line (- crement)) + (let ((subdepth (save-excursion (beginning-of-line) + (if (looking-at "[0-9]+:") + (string-to-int (match-string 0)) + 0)))) + (cond ((or (< subdepth depth) + (progn (end-of-line) (eobp)) + (progn (beginning-of-line) (bobp))) + ;; We have reached the end of this block. + (goto-char lastmatch) + (setq arg 0) + (error "End of sub-list")) + ((= subdepth depth) + (setq lastmatch (point) + arg (+ arg crement)))))) + (speedbar-position-cursor-on-line))) + +(defun speedbar-restricted-next (arg) + "Move to the next ARGth line in a speedbar buffer at the same depth. +This means that movement is restricted to a subnode, and that siblings +of intermediate nodes are skipped." + (interactive "p") + (speedbar-restricted-move (or arg 1)) + (speedbar-item-info)) + + +(defun speedbar-restricted-prev (arg) + "Move to the previous ARGth line in a speedbar buffer at the same depth. +This means that movement is restricted to a subnode, and that siblings +of intermediate nodes are skipped." + (interactive "p") + (speedbar-restricted-move (if arg (- arg) -1)) + (speedbar-item-info)) + +(defun speedbar-navigate-list (arg) + "Move across ARG groups of similarly typed items in speedbar. +Stop on the first line of the next type of item, or on the last or first item +if we reach a buffer boundary." + (interactive "p") + (beginning-of-line) + (if (looking-at "[0-9]+: *[[<{][-+?][]>}] ") + (let ((str (regexp-quote (match-string 0)))) + (while (looking-at str) + (speedbar-restricted-move arg) + (beginning-of-line)))) + (speedbar-position-cursor-on-line)) + +(defun speedbar-forward-list () + "Move forward over the current list. +A LIST in speedbar is a group of similarly typed items, such as directories, +files, or the directory button." + (interactive) + (speedbar-navigate-list 1) + (speedbar-item-info)) + +(defun speedbar-backward-list () + "Move backward over the current list. +A LIST in speedbar is a group of similarly typed items, such as directories, +files, or the directory button." + (interactive) + (speedbar-navigate-list -1) + (speedbar-item-info)) + (defun speedbar-scroll-up (&optional arg) "Page down one screen-full of the speedbar, or ARG lines." (interactive "P") @@ -1274,10 +1496,14 @@ (speedbar-stealthy-updates) ;; Reset the timer in case it got really hosed for some reason... (speedbar-set-timer speedbar-update-speed) - (if (<= 1 speedbar-verbosity-level) (message "Refreshing speedbar...done"))) + (if (<= 1 speedbar-verbosity-level) + (progn + (message "Refreshing speedbar...done") + (sit-for 0) + (message nil)))) (defun speedbar-item-load () - "Load the item under the cursor or mouse if it is a lisp file." + "Load the item under the cursor or mouse if it is a Lisp file." (interactive) (let ((f (speedbar-line-file))) (if (and (file-exists-p f) (string-match "\\.el\\'" f)) @@ -1286,10 +1512,10 @@ ;; If the compiled version exists, load that instead... (load-file (concat f "c")) (load-file f)) - (error "Not a loadable file...")))) + (error "Not a loadable file")))) (defun speedbar-item-byte-compile () - "Byte compile the item under the cursor or mouse if it is a lisp file." + "Byte compile the item under the cursor or mouse if it is a Lisp file." (interactive) (let ((f (speedbar-line-file)) (sf (selected-frame))) @@ -1297,7 +1523,8 @@ (progn (select-frame speedbar-attached-frame) (byte-compile-file f nil) - (select-frame sf))) + (select-frame sf) + (speedbar-reset-scanners))) )) (defun speedbar-mouse-item-info (event) @@ -1307,36 +1534,55 @@ (mouse-set-point event) (speedbar-item-info)) +(defun speedbar-generic-item-info () + "Attempt to derive, and then display information about thils line item. +File style information is displayed with `speedbar-item-info'." + (save-excursion + (beginning-of-line) + ;; Skip invisible number info. + (if (looking-at "\\([0-9]+\\):") (goto-char (match-end 0))) + ;; Skip items in "folder" type text characters. + (if (looking-at "\\s-*[[<({].[]>)}] ") (goto-char (match-end 0))) + ;; Get the text + (message "Text: %s" (buffer-substring-no-properties + (point) (progn (end-of-line) (point)))))) + (defun speedbar-item-info () "Display info in the mini-buffer about the button the mouse is over." (interactive) (if (not speedbar-shown-directories) - nil + (speedbar-generic-item-info) (let* ((item (speedbar-line-file)) (attr (if item (file-attributes item) nil))) - (if item (message "%s %d %s" (nth 8 attr) (nth 7 attr) item) + (if (and item attr) (message "%s %-6d %s" (nth 8 attr) (nth 7 attr) item) (save-excursion (beginning-of-line) - (looking-at "\\([0-9]+\\):") - (setq item (speedbar-line-path (string-to-int (match-string 1)))) - (if (re-search-forward "> \\([^ ]+\\)$" - (save-excursion(end-of-line)(point)) t) - (progn - (setq attr (get-text-property (match-beginning 1) - 'speedbar-token)) - (message "Tag %s in %s at position %s" - (match-string 1) item (if attr attr 0))) - (message "No special info for this line."))) - )))) + (if (not (looking-at "\\([0-9]+\\):")) + (speedbar-generic-item-info) + (setq item (speedbar-line-path (string-to-int (match-string 1)))) + (if (re-search-forward "> \\([^ ]+\\)$" + (save-excursion(end-of-line)(point)) t) + (progn + (setq attr (get-text-property (match-beginning 1) + 'speedbar-token)) + (message "Tag: %s in %s @ %s" + (match-string 1) item + (if attr + (if (markerp attr) (marker-position attr) attr) + 0))) + (if (re-search-forward "{[+-]} \\([^\n]+\\)$" + (save-excursion(end-of-line)(point)) t) + (message "Group of tags \"%s\"" (match-string 1)) + (speedbar-generic-item-info))))))))) (defun speedbar-item-copy () "Copy the item under the cursor. Files can be copied to new names or places." (interactive) (let ((f (speedbar-line-file))) - (if (not f) (error "Not a file.")) + (if (not f) (error "Not a file")) (if (file-directory-p f) - (error "Cannot copy directory.") + (error "Cannot copy directory") (let* ((rt (read-file-name (format "Copy %s to: " (file-name-nondirectory f)) (file-name-directory f))) @@ -1387,13 +1633,13 @@ (speedbar-refresh) (speedbar-goto-this-file rt) ))))) - (error "Not a file.")))) + (error "Not a file")))) (defun speedbar-item-delete () "Delete the item under the cursor. Files are removed from disk." (interactive) (let ((f (speedbar-line-file))) - (if (not f) (error "Not a file.")) + (if (not f) (error "Not a file")) (if (y-or-n-p (format "Delete %s? " f)) (progn (if (file-directory-p f) @@ -1406,6 +1652,24 @@ )) )) +(defun speedbar-item-object-delete () + "Delete the object associated from the item under the cursor. +The file is removed from disk. The object is determined from the +variable `speedbar-obj-alist'." + (interactive) + (let* ((f (speedbar-line-file)) + (obj nil) + (oa speedbar-obj-alist)) + (if (not f) (error "Not a file")) + (while (and oa (not (string-match (car (car oa)) f))) + (setq oa (cdr oa))) + (setq obj (concat (file-name-sans-extension f) (cdr (car oa)))) + (if (and oa (file-exists-p obj) + (y-or-n-p (format "Delete %s? " obj))) + (progn + (delete-file obj) + (speedbar-reset-scanners))))) + (defun speedbar-enable-update () "Enable automatic updating in speedbar via timers." (interactive) @@ -1501,12 +1765,12 @@ (put 'speedbar-with-writable 'lisp-indent-function 0) (defun speedbar-select-window (buffer) - "Select a window in which BUFFER is show. + "Select a window in which BUFFER is shown. If it is not shown, force it to appear in the default window." (let ((win (get-buffer-window buffer speedbar-attached-frame))) (if win (select-window win) - (show-buffer (selected-window) buffer)))) + (set-window-buffer (selected-window) buffer)))) (defmacro speedbar-with-attached-buffer (&rest forms) "Execute FORMS in the attached frame's special buffer. @@ -1550,7 +1814,7 @@ (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)" (put-text-property start end 'face face) (put-text-property start end 'mouse-face mouse) (put-text-property start end 'invisible nil) @@ -1558,6 +1822,114 @@ (if token (put-text-property start end 'speedbar-token token)) ) +;;; Initial Expansion list management +;; +(defun speedbar-initial-expansion-list () + "Return the current default expansion list. +This is based on `speedbar-initial-expansion-list-name' referencing +`speedbar-initial-expansion-mode-alist'." + ;; cdr1 - name, cdr2 - menu + (cdr (cdr (cdr (assoc speedbar-initial-expansion-list-name + speedbar-initial-expansion-mode-alist))))) + +(defun speedbar-initial-menu () + "Return the current default menu data. +This is based on `speedbar-initial-expansion-list-name' referencing +`speedbar-initial-expansion-mode-alist'." + (symbol-value + (car (cdr (assoc speedbar-initial-expansion-list-name + speedbar-initial-expansion-mode-alist))))) + +(defun speedbar-initial-keymap () + "Return the current default menu data. +This is based on `speedbar-initial-expansion-list-name' referencing +`speedbar-initial-expansion-mode-alist'." + (symbol-value + (car (cdr (cdr (assoc speedbar-initial-expansion-list-name + speedbar-initial-expansion-mode-alist)))))) + +(defun speedbar-initial-stealthy-functions () + "Return a list of functions to call stealthily. +This is based on `speedbar-initial-expansion-list-name' referencing +`speedbar-stealthy-function-list'." + (cdr (assoc speedbar-initial-expansion-list-name + speedbar-stealthy-function-list))) + +(defun speedbar-add-expansion-list (new-list) + "Add NEW-LIST to the list of expansion lists." + (add-to-list 'speedbar-initial-expansion-mode-alist new-list)) + +(defun speedbar-change-initial-expansion-list (new-default) + "Change speedbar's default expansion list to NEW-DEFAULT." + (interactive + (list + (completing-read (format "Speedbar Mode (default %s): " + speedbar-previously-used-expansion-list-name) + speedbar-initial-expansion-mode-alist + nil t "" nil + speedbar-previously-used-expansion-list-name))) + (setq speedbar-previously-used-expansion-list-name + speedbar-initial-expansion-list-name + speedbar-initial-expansion-list-name new-default) + (speedbar-refresh) + (speedbar-reconfigure-keymaps)) + + +;;; Special speedbar display management +;; +(defun speedbar-maybe-add-localized-support (buffer) + "Quick check function called on BUFFERs by the speedbar timer function. +Maintains the value of local variables which control speedbars use +of the special mode functions." + (or speedbar-special-mode-expansion-list + (speedbar-add-localized-speedbar-support buffer))) + +(defun speedbar-add-localized-speedbar-support (buffer) + "Add localized speedbar support to BUFFER's mode if it is available." + (interactive "bBuffer: ") + (if (stringp buffer) (setq buffer (get-buffer buffer))) + (if (not (buffer-live-p buffer)) + nil + (save-excursion + (set-buffer buffer) + (save-match-data + (let ((ms (symbol-name major-mode)) v) + (if (not (string-match "-mode$" ms)) + nil ;; do nothing to broken mode + (setq ms (substring ms 0 (match-beginning 0))) + (setq v (intern-soft (concat ms "-speedbar-buttons"))) + (make-local-variable 'speedbar-special-mode-expansion-list) + (if (not v) + (setq speedbar-special-mode-expansion-list t) + ;; If it is autoloaded, we need to load it now so that + ;; we have access to the varialbe -speedbar-menu-items. + ;; Is this XEmacs safe? + (let ((sf (symbol-function v))) + (if (and (listp sf) (eq (car sf) 'autoload)) + (load-library (car (cdr sf))))) + (setq speedbar-special-mode-expansion-list (list v)) + (setq v (intern-soft (concat ms "-speedbar-key-map"))) + (if (not v) + nil ;; don't add special keymap + (make-local-variable 'speedbar-special-mode-key-map) + (setq speedbar-special-mode-key-map + (symbol-value v))) + (setq v (intern-soft (concat ms "-speedbar-menu-items"))) + (if (not v) + nil ;; don't add special menus + (make-local-variable 'speedbar-easymenu-definition-special) + (setq speedbar-easymenu-definition-special + (symbol-value v))) + ))))))) + +(defun speedbar-remove-localized-speedbar-support (buffer) + "Remove any traces that BUFFER supports speedbar in a specialized way." + (save-excursion + (set-buffer buffer) + (kill-local-variable 'speedbar-special-mode-expansion-list) + (kill-local-variable 'speedbar-special-mode-key-map) + (kill-local-variable 'speedbar-easymenu-definition-special))) + ;;; File button management ;; (defun speedbar-file-lists (directory) @@ -1578,7 +1950,9 @@ (dirs nil) (files nil)) (while dir - (if (not (string-match speedbar-file-unshown-regexp (car dir))) + (if (not + (or (string-match speedbar-file-unshown-regexp (car dir)) + (string-match speedbar-directory-unshown-regexp (car dir)))) (if (file-directory-p (car dir)) (setq dirs (cons (car dir) dirs)) (setq files (cons (car dir) files)))) @@ -1696,6 +2070,10 @@ (mf (if exp-button-function 'speedbar-highlight-face nil)) ) (speedbar-make-button start end bf mf exp-button-function exp-button-data) + (if speedbar-hide-button-brackets-flag + (progn + (put-text-property start (1+ start) 'invisible t) + (put-text-property end (1- end) 'invisible t))) ) (insert-char ? 1 nil) (put-text-property (1- (point)) (point) 'invisible nil) @@ -1717,7 +2095,8 @@ (speedbar-with-writable (goto-char (match-beginning 1)) (delete-char 1) - (insert-char char 1 t))))) + (insert-char char 1 t) + (put-text-property (point) (1- (point)) 'invisible nil))))) ;;; Build button lists @@ -1726,7 +2105,7 @@ "Insert list of FILES starting at point, and indenting all files to LEVEL. Tag expandable items with a +, otherwise a ?. Don't highlight ? as we don't know how to manage them. The input parameter FILES is a cons -cell of the form ( 'DIRLIST . 'FILELIST )" +cell of the form ( 'DIRLIST . 'FILELIST )" ;; Start inserting all the directories (let ((dirs (car files))) (while dirs @@ -1734,7 +2113,8 @@ (car dirs) 'speedbar-dir-follow nil 'speedbar-directory-face level) (setq dirs (cdr dirs)))) - (let ((lst (car (cdr files)))) + (let ((lst (car (cdr files))) + (case-fold-search t)) (while lst (let* ((known (string-match speedbar-file-regexp (car lst))) (expchar (if known ?+ ??)) @@ -1770,6 +2150,185 @@ (setq sf (cdr sf))))) ))) +(defun speedbar-apply-one-tag-hierarchy-method (lst method) + "Adjust the tag hierarchy LST by METHOD." + (cond + ((eq method 'sort) + (sort (copy-alist lst) + (lambda (a b) (string< (car a) (car b))))) + ((eq method 'prefix-group) + (let ((newlst nil) + (sublst nil) + (work-list nil) + (junk-list nil) + (short-group-list nil) + (short-start-name nil) + (short-end-name nil) + (num-shorts-grouped 0) + (bins (make-vector 256 nil)) + (diff-idx 0)) + ;; Break out sub-lists + (while lst + (if (listp (cdr-safe (car-safe lst))) + (setq newlst (cons (car lst) newlst)) + (setq sublst (cons (car lst) sublst))) + (setq lst (cdr lst))) + ;; Now, first find out how long our list is. Never let a + ;; list get-shorter than our minimum. + (if (<= (length sublst) speedbar-tag-split-minimum-length) + (setq work-list (nreverse sublst)) + (setq diff-idx (length (try-completion "" sublst))) + ;; Sort the whole list into bins. + (while sublst + (let ((e (car sublst)) + (s (car (car sublst)))) + (cond ((<= (length s) diff-idx) + ;; 0 storage bin for shorty. + (aset bins 0 (cons e (aref bins 0)))) + (t + ;; stuff into a bin based on ascii value at diff + (aset bins (aref s diff-idx) + (cons e (aref bins (aref s diff-idx))))))) + (setq sublst (cdr sublst))) + ;; Go through all our bins Stick singles into our + ;; junk-list, everything else as sublsts in work-list. + ;; If two neighboring lists are both small, make a grouped + ;; group combinding those two sub-lists. + (setq diff-idx 0) + (while (> 256 diff-idx) + (let ((l (aref bins diff-idx))) + (if l + (let ((tmp (cons (try-completion "" l) l))) + (if (or (> (length l) speedbar-tag-regroup-maximum-length) + (> (+ (length l) (length short-group-list)) + speedbar-tag-split-minimum-length)) + (progn + ;; We have reached a longer list, so we + ;; must finish off a grouped group. + (cond + ((and short-group-list + (= (length short-group-list) + num-shorts-grouped)) + ;; All singles? Junk list + (setq junk-list (append short-group-list + junk-list))) + ((= num-shorts-grouped 1) + ;; Only one short group? Just stick it in + ;; there by itself. + (setq work-list + (cons (cons (try-completion + "" short-group-list) + (nreverse short-group-list)) + work-list))) + (short-group-list + ;; Multiple groups to be named in a special + ;; way by displaying the range over which we + ;; have grouped them. + (setq work-list + (cons (cons (concat short-start-name + " to " + short-end-name) + (nreverse short-group-list)) + work-list)))) + ;; Reset short group list information every time. + (setq short-group-list nil + short-start-name nil + short-end-name nil + num-shorts-grouped 0))) + ;; Ok, now that we cleaned up the short-group-list, + ;; we can deal with this new list, to decide if it + ;; should go on one of these sub-lists or not. + (if (< (length l) speedbar-tag-regroup-maximum-length) + (setq short-group-list (append short-group-list l) + num-shorts-grouped (1+ num-shorts-grouped) + short-end-name (car tmp) + short-start-name (if short-start-name + short-start-name + (car tmp))) + (setq work-list (cons tmp work-list)))))) + (setq diff-idx (1+ diff-idx)))) + ;; Did we run out of things? Drop our new list onto the end. + (cond + ((and short-group-list (= (length short-group-list) num-shorts-grouped)) + ;; All singles? Junk list + (setq junk-list (append short-group-list junk-list))) + ((= num-shorts-grouped 1) + ;; Only one short group? Just stick it in + ;; there by itself. + (setq work-list + (cons (cons (try-completion "" short-group-list) + (nreverse short-group-list)) + work-list))) + (short-group-list + ;; Multiple groups to be named in a special + ;; way by displaying the range over which we + ;; have grouped them. + (setq work-list + (cons (cons (concat short-start-name " to " short-end-name) + (nreverse short-group-list)) + work-list)))) + ;; Now, stick our new list onto the end of + (if work-list + (if junk-list + (append (nreverse newlst) + (nreverse work-list) + junk-list) + (append (nreverse newlst) + (nreverse work-list))) + (append (nreverse newlst) junk-list)))) + ((eq method 'trim-words) + (let ((newlst nil) + (sublst nil) + (trim-prefix nil) + (trim-chars 0) + (trimlst nil)) + (while lst + (if (listp (cdr-safe (car-safe lst))) + (setq newlst (cons (car lst) newlst)) + (setq sublst (cons (car lst) sublst))) + (setq lst (cdr lst))) + ;; Get the prefix to trim by. Make sure that we don't trim + ;; off silly pieces, only complete understandable words. + (setq trim-prefix (try-completion "" sublst)) + (if (or (= (length sublst) 1) + (not trim-prefix) + (not (string-match "\\(\\w+\\W+\\)+" trim-prefix))) + (append (nreverse newlst) (nreverse sublst)) + (setq trim-prefix (substring trim-prefix (match-beginning 0) + (match-end 0))) + (setq trim-chars (length trim-prefix)) + (while sublst + (setq trimlst (cons + (cons (substring (car (car sublst)) trim-chars) + (cdr (car sublst))) + trimlst) + sublst (cdr sublst))) + ;; Put the lists together + (append (nreverse newlst) trimlst)))) + ((eq method 'simple-group) + (let ((newlst nil) + (sublst nil)) + (while lst + (if (listp (cdr-safe (car-safe lst))) + (setq newlst (cons (car lst) newlst)) + (setq sublst (cons (car lst) sublst))) + (setq lst (cdr lst))) + (if (not newlst) + (nreverse sublst) + (setq newlst (cons (cons "Tags" (nreverse sublst)) newlst)) + (nreverse newlst)))) + (t lst))) + +(defun speedbar-create-tag-hierarchy (lst) + "Adjust the tag hierarchy in LST, and return it. +This uses `speedbar-tag-hierarchy-method' to determine how to adjust +the list. See it's value for details." + (let ((methods speedbar-tag-hierarchy-method)) + (while methods + (setq lst (speedbar-apply-one-tag-hierarchy-method lst (car methods)) + methods (cdr methods))) + lst)) + (defun speedbar-insert-generic-list (level lst expand-fun find-fun) "At LEVEL, insert a generic multi-level alist LST. Associations with lists get {+} tags (to expand into more nodes) and @@ -1779,6 +2338,8 @@ ;; Remove imenu rescan button (if (string= (car (car lst)) "*Rescan*") (setq lst (cdr lst))) + ;; Adjust the list. + (setq lst (speedbar-create-tag-hierarchy lst)) ;; insert the parts (while lst (cond ((null (car-safe lst)) nil) ;this would be a separator @@ -1805,7 +2366,11 @@ (interactive) ;; Set the current special buffer (setq speedbar-desired-buffer nil) + ;; Check for special modes + (speedbar-maybe-add-localized-support (current-buffer)) + ;; Choose the correct method of doodling. (if (and speedbar-mode-specific-contents-flag + (listp speedbar-special-mode-expansion-list) speedbar-special-mode-expansion-list (local-variable-p 'speedbar-special-mode-expansion-list @@ -1818,7 +2383,7 @@ "Update the contents of the speedbar buffer based on the current directory." (let ((cbd (expand-file-name default-directory)) cbd-parent - (funclst speedbar-initial-expansion-list) + (funclst (speedbar-initial-expansion-list)) (cache speedbar-full-text-cache) ;; disable stealth during update (speedbar-stealthy-function-list nil) @@ -1832,7 +2397,12 @@ ;; really a request to update existing contents, so we must be ;; careful with our text cache! (if (member cbd speedbar-shown-directories) - (setq cache nil) + (progn + (setq cache nil) + ;; If the current directory is not the last element in the dir + ;; list, then we ALSO need to zap the list of expanded directories + (if (/= (length (member cbd speedbar-shown-directories)) 1) + (setq speedbar-shown-directories (list cbd)))) ;; Build cbd-parent, and see if THAT is in the current shown ;; directories. First, go through pains to get the parent directory @@ -1840,7 +2410,8 @@ (save-match-data (setq cbd-parent cbd) (if (string-match "/$" cbd-parent) - (setq cbd-parent (substring cbd-parent 0 (match-beginning 0)))) + (setq cbd-parent (substring cbd-parent 0 + (match-beginning 0)))) (setq cbd-parent (file-name-directory cbd-parent))) (member cbd-parent speedbar-shown-directories)) (setq expand-local t) @@ -1883,7 +2454,7 @@ (funcall (car funclst) cbd 0) (setq funclst (cdr funclst)))))) (goto-char (point-min))))) - (speedbar-reconfigure-menubar)) + (speedbar-reconfigure-keymaps)) (defun speedbar-update-special-contents () "Used the mode-specific variable to fill in the speedbar buffer. @@ -1910,10 +2481,10 @@ (funcall (car funclst) specialbuff) (setq funclst (cdr funclst)))) (goto-char (point-min)))) - (speedbar-reconfigure-menubar)) + (speedbar-reconfigure-keymaps)) (defun speedbar-timer-fn () - "Run whenever emacs is idle to update the speedbar item." + "Run whenever Emacs is idle to update the speedbar item." (if (not (and (frame-live-p speedbar-frame) (frame-live-p speedbar-attached-frame))) (speedbar-set-timer nil) @@ -1927,8 +2498,11 @@ ;; get a good directory from (if (string-match "\\*Minibuf-[0-9]+\\*" (buffer-name)) (other-window 1)) + ;; Check for special modes + (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 (local-variable-p 'speedbar-special-mode-expansion-list @@ -1962,28 +2536,36 @@ default-directory)))) (select-frame af)) ;; Now run stealthy updates of time-consuming items - (speedbar-stealthy-updates))))) + (speedbar-stealthy-updates))) + ;; Now run the mouse tracking system + (speedbar-show-info-under-mouse))) (run-hooks 'speedbar-timer-hook)) ;;; Stealthy activities ;; +(defvar speedbar-stealthy-update-recurse nil + "Recursion avoidance variable for stealthy update.") + (defun speedbar-stealthy-updates () "For a given speedbar, run all items in the stealthy function list. Each item returns t if it completes successfully, or nil if interrupted by the user." - (let ((l speedbar-stealthy-function-list)) - (unwind-protect - (while (and l (funcall (car l))) - (sit-for 0) - (setq l (cdr l))) - ;(message "Exit with %S" (car l)) - ))) + (if (not speedbar-stealthy-update-recurse) + (let ((l (speedbar-initial-stealthy-functions)) + (speedbar-stealthy-update-recurse t)) + (unwind-protect + (while (and l (funcall (car l))) + ;(sit-for 0) + (setq l (cdr l))) + ;;(message "Exit with %S" (car l)) + )))) (defun speedbar-reset-scanners () "Reset any variables used by functions in the stealthy list as state. If new functions are added, their state needs to be updated here." - (setq speedbar-vc-to-do-point t) + (setq speedbar-vc-to-do-point t + speedbar-obj-to-do-point t) (run-hooks 'speedbar-scanner-reset-hook) ) @@ -1998,8 +2580,7 @@ speedbar-last-selected-file (re-search-forward (concat " \\(" (regexp-quote speedbar-last-selected-file) - "\\)\\(" (regexp-quote speedbar-vc-indicator) - "\\)?\n") + "\\)\\(" speedbar-indicator-regex "\\)?\n") nil t)) (put-text-property (match-beginning 1) (match-end 1) @@ -2021,7 +2602,8 @@ rf))) (newcf (if newcfd (file-name-nondirectory newcfd))) (lastb (current-buffer)) - (sucf-recursive (boundp 'sucf-recursive))) + (sucf-recursive (boundp 'sucf-recursive)) + (case-fold-search t)) (if (and newcf ;; check here, that way we won't refresh to newcf until ;; its been written, thus saving ourselves some time @@ -2040,8 +2622,7 @@ (goto-char (point-min)) (if (re-search-forward (concat " \\(" (regexp-quote newcf) "\\)\\(" - (regexp-quote speedbar-vc-indicator) - "\\)?\n") nil t) + speedbar-indicator-regex "\\)?$") nil t) ;; put the property on it (put-text-property (match-beginning 1) (match-end 1) @@ -2065,18 +2646,43 @@ )) (setq speedbar-last-selected-file newcf)) (if (not sucf-recursive) - (progn - (forward-line -1) - (speedbar-position-cursor-on-line))) + (speedbar-position-cursor-on-line)) (set-buffer lastb) (select-frame lastf) ))) ;; return that we are done with this activity. t) -;; Load ange-ftp only if compiling to remove errors. +(defun speedbar-add-indicator (indicator-string &optional replace-this) + "Add INDICATOR-STRING to the end of this speedbar line. +If INDICATOR-STRING is space, and REPLACE-THIS is a character, then +an the existing indicator is removed. If there is already an +indicator, then do not add a space." + (beginning-of-line) + ;; The nature of the beast: Assume we are in "the right place" + (end-of-line) + (skip-chars-backward (concat " " speedbar-vc-indicator + (car speedbar-obj-indicator) + (cdr speedbar-obj-indicator))) + (if (and (not (looking-at speedbar-indicator-regex)) + (not (string= indicator-string " "))) + (insert speedbar-indicator-separator)) + (speedbar-with-writable + (save-excursion + (if (and replace-this + (re-search-forward replace-this (save-excursion (end-of-line) + (point)) + t)) + (delete-region (match-beginning 0) (match-end 0)))) + (end-of-line) + (if (not (string= " " indicator-string)) + (insert indicator-string)))) + +;; Load efs/ange-ftp only if compiling to remove byte-compiler warnings. ;; Steven L Baur said this was important: -(eval-when-compile (or (featurep 'xemacs) (require 'ange-ftp))) +(eval-when-compile (or (featurep 'xemacs) + (condition-case () (require 'efs) + (error (require 'ange-ftp))))) (defun speedbar-check-vc () "Scan all files in a directory, and for each see if it's checked out. @@ -2088,12 +2694,17 @@ (set-buffer speedbar-buffer) (if (and speedbar-vc-do-check (eq speedbar-vc-to-do-point t) (speedbar-vc-check-dir-p default-directory) - (not (and (featurep 'ange-ftp) - (string-match (car - (if speedbar-xemacsp - ange-ftp-path-format - ange-ftp-name-format)) - (expand-file-name default-directory))))) + (not (or (and (featurep 'ange-ftp) + (string-match + (car (if speedbar-xemacsp + ange-ftp-path-format + ange-ftp-name-format)) + (expand-file-name default-directory))) + ;; efs support: Bob Weiner + (and (featurep 'efs) + (string-match + (car efs-path-regexp) + (expand-file-name default-directory)))))) (setq speedbar-vc-to-do-point 0)) (if (numberp speedbar-vc-to-do-point) (progn @@ -2103,11 +2714,10 @@ nil t)) (setq speedbar-vc-to-do-point (point)) (if (speedbar-check-vc-this-line (match-string 1)) - (if (not (looking-at (regexp-quote speedbar-vc-indicator))) - (speedbar-with-writable (insert speedbar-vc-indicator))) - (if (looking-at (regexp-quote speedbar-vc-indicator)) - (speedbar-with-writable - (delete-region (match-beginning 0) (match-end 0)))))) + (speedbar-add-indicator speedbar-vc-indicator + (regexp-quote speedbar-vc-indicator)) + (speedbar-add-indicator " " + (regexp-quote speedbar-vc-indicator)))) (if (input-pending-p) ;; return that we are incomplete nil @@ -2171,6 +2781,72 @@ ;; User extension (run-hook-with-args 'speedbar-vc-in-control-hook path name) )) + +;; Objet File scanning +(defun speedbar-check-objects () + "Scan all files in a directory, and for each see if there is an object. +See `speedbar-check-obj-this-line' and `speedbar-obj-alist' for how +to add more object types." + ;; Check for to-do to be reset. If reset but no RCS is available + ;; then set to nil (do nothing) otherwise, start at the beginning + (save-excursion + (set-buffer speedbar-buffer) + (if (and speedbar-obj-do-check (eq speedbar-obj-to-do-point t)) + (setq speedbar-obj-to-do-point 0)) + (if (numberp speedbar-obj-to-do-point) + (progn + (goto-char speedbar-obj-to-do-point) + (while (and (not (input-pending-p)) + (re-search-forward "^\\([0-9]+\\):\\s-*\\[[+-]\\] " + nil t)) + (setq speedbar-obj-to-do-point (point)) + (let ((ind (speedbar-check-obj-this-line (match-string 1)))) + (if (not ind) (setq ind " ")) + (speedbar-add-indicator ind (concat + (car speedbar-obj-indicator) + "\\|" + (cdr speedbar-obj-indicator))))) + (if (input-pending-p) + ;; return that we are incomplete + nil + ;; we are done, set to-do to nil + (setq speedbar-obj-to-do-point nil) + ;; and return t + t)) + t))) + +(defun speedbar-check-obj-this-line (depth) + "Return t if the file on this line has an associated object. +Parameter DEPTH is a string with the current depth of indentation of +the file being checked." + (let* ((d (string-to-int depth)) + (f (speedbar-line-path d)) + (fn (buffer-substring-no-properties + ;; Skip-chars: thanks ptype@dra.hmg.gb + (point) (progn + (skip-chars-forward "^ " + (save-excursion (end-of-line) + (point))) + (point)))) + (fulln (concat f fn))) + (if (<= 2 speedbar-verbosity-level) + (message "Speedbar obj check...%s" fulln)) + (let ((oa speedbar-obj-alist)) + (while (and oa (not (string-match (car (car oa)) fulln))) + (setq oa (cdr oa))) + (if (not (and oa (file-exists-p (concat (file-name-sans-extension fulln) + (cdr (car oa)))))) + nil + ;; Find out if the object is out of date or not. + (let ((date1 (nth 5 (file-attributes fulln))) + (date2 (nth 5 (file-attributes (concat + (file-name-sans-extension fulln) + (cdr (car oa))))))) + (if (or (< (car date1) (car date2)) + (and (= (car date1) (car date2)) + (< (nth 1 date1) (nth 1 date2)))) + (car speedbar-obj-indicator) + (cdr speedbar-obj-indicator))))))) ;;; Clicking Activity ;; @@ -2219,7 +2895,7 @@ ((eq (car e) 'mouse-1) (speedbar-quick-mouse e)) ((or (eq (car e) 'double-down-mouse-1) - (eq (car e) 'tripple-down-mouse-1)) + (eq (car e) 'triple-down-mouse-1)) (mouse-set-point e) (speedbar-do-function-pointer) (speedbar-quick-mouse e)))) @@ -2260,8 +2936,7 @@ (beginning-of-line) (if (looking-at (concat "\\([0-9]+\\): *[[<][-+?][]>] \\([^ \n]+\\)\\(" - (regexp-quote speedbar-vc-indicator) - "\\)?")) + speedbar-indicator-regex "\\)?")) (let* ((depth (string-to-int (match-string 1))) (path (speedbar-line-path depth)) (f (match-string 2))) @@ -2298,7 +2973,7 @@ (let ((nd (file-name-nondirectory file))) (if (re-search-forward (concat "] \\(" (regexp-quote nd) - "\\)\\(" (regexp-quote speedbar-vc-indicator) "\\)?$") + "\\)\\(" speedbar-indicator-regex "\\)$") nil t) (progn (speedbar-position-cursor-on-line) @@ -2310,28 +2985,34 @@ "Retrieve the pathname associated with the current line. This may require traversing backwards from DEPTH and combining the default directory with these items." - (save-excursion - (save-match-data - (let ((path nil)) - (setq depth (1- depth)) - (while (/= depth -1) - (if (not (re-search-backward (format "^%d:" depth) nil t)) - (error "Error building path of tag") - (cond ((looking-at "[0-9]+:\\s-*<->\\s-+\\([^\n]+\\)$") - (setq path (concat (buffer-substring-no-properties - (match-beginning 1) (match-end 1)) - "/" - path))) - ((looking-at "[0-9]+:\\s-*[-]\\s-+\\([^\n]+\\)$") - ;; This is the start of our path. - (setq path (buffer-substring-no-properties - (match-beginning 1) (match-end 1)))))) - (setq depth (1- depth))) - (if (and path - (string-match (concat (regexp-quote speedbar-vc-indicator) "$") - path)) - (setq path (substring path 0 (match-beginning 0)))) - (concat default-directory path))))) + (cond + ((string= speedbar-initial-expansion-list-name "files") + (save-excursion + (save-match-data + (let ((path nil)) + (setq depth (1- depth)) + (while (/= depth -1) + (if (not (re-search-backward (format "^%d:" depth) nil t)) + (error "Error building path of tag") + (cond ((looking-at "[0-9]+:\\s-*<->\\s-+\\([^\n]+\\)$") + (setq path (concat (buffer-substring-no-properties + (match-beginning 1) (match-end 1)) + "/" + path))) + ((looking-at "[0-9]+:\\s-*[-]\\s-+\\([^\n]+\\)$") + ;; This is the start of our path. + (setq path (buffer-substring-no-properties + (match-beginning 1) (match-end 1)))))) + (setq depth (1- depth))) + (if (and path + (string-match (concat speedbar-indicator-regex "$") + path)) + (setq path (substring path 0 (match-beginning 0)))) + (concat default-directory path))))) + (t + ;; If we aren't in file mode, then return an empty string to make + ;; sure that we can still get some stuff done. + ""))) (defun speedbar-path-line (path) "Position the cursor on the line specified by PATH." @@ -2342,12 +3023,12 @@ (fname (file-name-nondirectory path)) (pname (file-name-directory path))) (if (not (member pname speedbar-shown-directories)) - (error "Internal Error: File %s not shown in speedbar." path)) + (error "Internal Error: File %s not shown in speedbar" path)) (goto-char (point-min)) (while (and nomatch (re-search-forward (concat "[]>] \\(" (regexp-quote fname) - "\\)\\(" (regexp-quote speedbar-vc-indicator) "\\)?$") + "\\)\\(" speedbar-indicator-regex "\\)?$") nil t)) (beginning-of-line) (looking-at "\\([0-9]+\\):") @@ -2431,8 +3112,10 @@ "/")) ;; Because we leave speedbar as the current buffer, ;; update contents will change directory without - ;; having to touch the attached frame. - (speedbar-update-contents) + ;; having to touch the attached frame. Turn off smart expand just + ;; in case. + (let ((speedbar-smart-directory-expand-flag nil)) + (speedbar-update-contents)) (speedbar-set-timer speedbar-navigating-speed) (setq speedbar-last-selected-file nil) (speedbar-stealthy-updates)) @@ -2484,7 +3167,7 @@ (speedbar-change-expand-button-char ?+) (speedbar-delete-subblock indent) ) - (t (error "Ooops... not sure what to do."))) + (t (error "Ooops... not sure what to do"))) (speedbar-center-buffer-smartly) (setq speedbar-last-selected-file nil) (save-excursion (speedbar-stealthy-updates))) @@ -2493,7 +3176,9 @@ "Speedbar click handler for default directory buttons. TEXT is the button clicked on. TOKEN is the directory to follow. INDENT is the current indentation level and is unused." - (setq default-directory token) + (if (string-match "^[A-Z]:$" token) + (setq default-directory (concat token "\\")) + (setq default-directory token)) ;; Because we leave speedbar as the current buffer, ;; update contents will change directory without ;; having to touch the attached frame. @@ -2527,7 +3212,7 @@ ((string-match "-" text) ;we have to contract this node (speedbar-change-expand-button-char ?+) (speedbar-delete-subblock indent)) - (t (error "Ooops... not sure what to do."))) + (t (error "Ooops... not sure what to do"))) (speedbar-center-buffer-smartly)) (defun speedbar-tag-find (text token indent) @@ -2556,13 +3241,12 @@ (speedbar-with-writable (save-excursion (end-of-line) (forward-char 1) - (speedbar-insert-generic-list indent - token 'speedbar-tag-expand + (speedbar-insert-generic-list indent token 'speedbar-tag-expand 'speedbar-tag-find)))) ((string-match "-" text) ;we have to contract this node (speedbar-change-expand-button-char ?+) (speedbar-delete-subblock indent)) - (t (error "Ooops... not sure what to do."))) + (t (error "Ooops... not sure what to do"))) (speedbar-center-buffer-smartly)) ;;; Loading files into the attached frame. @@ -2581,7 +3265,7 @@ (let ((pop-up-frames t)) (select-window (display-buffer buff))) (select-frame speedbar-attached-frame) (switch-to-buffer buff)))) - ) + ) ;;; Centering Utility ;; @@ -2678,6 +3362,8 @@ speedbar-parse-c-or-c++tag) ("^\\.emacs$\\|.\\(el\\|l\\|lsp\\)\\'" . "def[^i]+\\s-+\\(\\(\\w\\|[-_]\\)+\\)\\s-*\C-?") +; ("\\.\\([fF]\\|for\\|FOR\\|77\\|90\\)\\'" . +; speedbar-parse-fortran77-tag) ("\\.tex\\'" . speedbar-parse-tex-string) ("\\.p\\'" . "\\(\\(FUNCTION\\|function\\|PROCEDURE\\|procedure\\)\\s-+\\([a-zA-Z0-9_.:]+\\)\\)\\s-*(?^?") @@ -2781,7 +3467,7 @@ ; (delete-region (match-beginning 1) (match-end 1))))) (defun speedbar-extract-one-symbol (expr) - "At point, return nil, or one alist in the form: ( symbol . position ) + "At point, return nil, or one alist in the form: (SYMBOL . POSITION) The line should contain output from etags. Parse the output using the regular expression EXPR" (let* ((sym (if (stringp expr) @@ -2832,6 +3518,143 @@ (t nil))))) +;;; BUFFER DISPLAY mode. +;; +(defvar speedbar-buffers-key-map nil + "Keymap used when in the buffers display mode.") + +(if speedbar-buffers-key-map + nil + (setq speedbar-buffers-key-map (speedbar-make-specialized-keymap)) + + ;; Basic tree features + (define-key speedbar-buffers-key-map "e" 'speedbar-edit-line) + (define-key speedbar-buffers-key-map "\C-m" 'speedbar-edit-line) + (define-key speedbar-buffers-key-map "+" 'speedbar-expand-line) + (define-key speedbar-buffers-key-map "-" 'speedbar-contract-line) + + ;; Buffer specific keybindings + (define-key speedbar-buffers-key-map "k" 'speedbar-buffer-kill-buffer) + (define-key speedbar-buffers-key-map "r" 'speedbar-buffer-revert-buffer) + + ) + +(defvar speedbar-buffer-easymenu-definition + '(["Jump to buffer" speedbar-edit-line t] + ["Expand File Tags" speedbar-expand-line + (save-excursion (beginning-of-line) + (looking-at "[0-9]+: *.\\+. "))] + ["Contract File Tags" speedbar-contract-line + (save-excursion (beginning-of-line) + (looking-at "[0-9]+: *.-. "))] + ) + "Menu item elements shown when displaying a buffer list.") + +(defun speedbar-buffer-buttons (directory zero) + "Create speedbar buttons based on the buffers currently loaded. +DIRECTORY is the path to the currently active buffer, and ZERO is 0." + (speedbar-buffer-buttons-engine nil)) + +(defun speedbar-buffer-buttons-temp (directory zero) + "Create speedbar buttons based on the buffers currently loaded. +DIRECTORY is the path to the currently active buffer, and ZERO is 0." + (speedbar-buffer-buttons-engine t)) + +(defun speedbar-buffer-buttons-engine (temp) + "Create speedbar buffer buttons. +If TEMP is non-nil, then clicking on a buffer restores the previous display." + (insert "Active Buffers:\n") + (let ((bl (buffer-list))) + (while bl + (if (string-match "^[ *]" (buffer-name (car bl))) + nil + (let* ((known (string-match speedbar-file-regexp + (buffer-name (car bl)))) + (expchar (if known ?+ ??)) + (fn (if known 'speedbar-tag-file nil)) + (fname (save-excursion (set-buffer (car bl)) + (buffer-file-name)))) + (speedbar-make-tag-line 'bracket expchar fn fname + (buffer-name (car bl)) + 'speedbar-buffer-click temp + 'speedbar-file-face 0))) + (setq bl (cdr bl))) + (setq bl (buffer-list)) + (insert "Scratch Buffers:\n") + (while bl + (if (not (string-match "^\\*" (buffer-name (car bl)))) + nil + (if (eq (car bl) speedbar-buffer) + nil + (speedbar-make-tag-line 'bracket ?? nil nil + (buffer-name (car bl)) + 'speedbar-buffer-click temp + 'speedbar-file-face 0))) + (setq bl (cdr bl))) + (setq bl (buffer-list)) + (insert "Hidden Buffers:\n") + (while bl + (if (not (string-match "^ " (buffer-name (car bl)))) + nil + (if (eq (car bl) speedbar-buffer) + nil + (speedbar-make-tag-line 'bracket ?? nil nil + (buffer-name (car bl)) + 'speedbar-buffer-click temp + 'speedbar-file-face 0))) + (setq bl (cdr bl))))) + +(defun speedbar-buffer-click (text token indent) + "When the users clicks on a buffer-button in speedbar. +TEXT is the buffer's name, TOKEN and INDENT are unused." + (if speedbar-power-click + (let ((pop-up-frames t)) (select-window (display-buffer text))) + (select-frame speedbar-attached-frame) + (switch-to-buffer text) + (if token (speedbar-change-initial-expansion-list + speedbar-previously-used-expansion-list-name)))) + +(defun speedbar-buffer-kill-buffer () + "Kill the buffer the cursor is on in the speedbar buffer." + (interactive) + (or (save-excursion + (beginning-of-line) + ;; If this fails, then it is a non-standard click, and as such, + ;; perfectly allowed. + (if (re-search-forward "[]>}] [a-zA-Z0-9]" + (save-excursion (end-of-line) (point)) + t) + (let ((text (progn + (forward-char -1) + (buffer-substring (point) (save-excursion + (end-of-line) + (point)))))) + (if (and (get-buffer text) + (y-or-n-p (format "Kill buffer %s? " text))) + (kill-buffer text))))))) + +(defun speedbar-buffer-revert-buffer () + "Revert the buffer the cursor is on in the speedbar buffer." + (interactive) + (save-excursion + (beginning-of-line) + ;; If this fails, then it is a non-standard click, and as such, + ;; perfectly allowed + (if (re-search-forward "[]>}] [a-zA-Z0-9]" + (save-excursion (end-of-line) (point)) + t) + (let ((text (progn + (forward-char -1) + (buffer-substring (point) (save-excursion + (end-of-line) + (point)))))) + (if (get-buffer text) + (progn + (set-buffer text) + (revert-buffer t))))))) + + + ;;; Color loading section This is messy *Blech!* ;; (defface speedbar-button-face '((((class color) (background light))