[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Speedbar can run different types of Major display modes such as Files (see section 3. File Mode), and Buffers (see section 4. Buffer Mode). It can also manage different minor display modes for use with buffers handling specialized data.
These major and minor display modes are handled through an extension
system which permits specialized keymaps and menu extensions, in
addition to a unique rendering function. You can also specify a wide
range of tagging functions. The default uses imenu
, but new
tagging methods can be easily added. In this chapter, you will
learn how to write your own major or minor display modes, and how to
create specialized tagging functions.
7.1 Minor Display Modes | How to create a minor display mode. | |
7.2 Major Display Modes | How to create a major display mode. | |
7.3 Tagging Extensions | How to create your own tagging methods. | |
7.4 Creating a display | How to insert buttons and hierarchies. |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A minor display mode is a mode useful when using a specific type of buffer. This mode might not be useful for any other kind of data or mode, or may just be more useful that a files or buffers based mode when working with a specialized mode.
Examples that already exist for speedbar include RMAIL, Info, and gdb. These modes display information specific to the major mode shown in the attached frame.
To enable a minor display mode in your favorite Major mode, follow these steps. The string `name' is the name of the major mode being augmented with speedbar.
name-speedbar-key-map
.
(setq name-speedbar-key-map (speedbar-make-specialized-keymap)) |
This function creates a special keymap for use in speedbar.
(if (featurep 'speedbar) (name-install-speedbar-variables) (add-hook 'speedbar-load-hook 'name-install-speedbar-variables)) |
name-speedbar-menu-items
. This will be spliced into
speedbar's control menu.
name-speedbar-buttons
. This function
should take one variable, which is the buffer for which it will create
buttons. At this time (current-buffer)
will point to the
uncleared speedbar buffer.
When writing name-speedbar-buttons
, the first thing you will
want to do is execute a check to see if you need to re-create your
display. If it needs to be cleared, you need to erase the speedbar
buffer yourself, and start drawing buttons. See section 7.4 Creating a display.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Creating a Major Display Mode for speedbar requires authoring a keymap, an easy-menu segment, and writing several functions. These items can be given any name, and are made the same way as in a minor display mode (see section 7.1 Minor Display Modes). Once this is done, these items need to be registered.
Because this setup activity may or may not have speedbar available when it is being loaded, it is necessary to create an install function. This function should create and initialize the keymap, and add your expansions into the customization tables.
When creating the keymap, use the function
speedbar-make-specialized-keymap
instead of other keymap making
functions. This will provide you with the initial bindings needed.
Some common speedbar functions you might want to bind are:
speedbar-edit-line
speedbar-expand-line
speedbar-contract-line
These function require that function speedbar-line-directory
be
correctly overloaded to work.
Next, register your extension like this;
(speedbar-add-expansion-list '("MyExtension" MyExtension-speedbar-menu-items MyExtension-speedbar-key-map MyExtension-speedbar-buttons)) |
There are no limitations to the names you use.
The first parameter is the string representing your display mode. The second parameter is a variable name containing an easymenu compatible menu definition. This will be stuck in the middle of speedbar's menu. The third parameter is the variable name containing the keymap we discussed earlier. The last parameter is a function which draws buttons for your mode. This function must take two parameters. The directory currently being displayed, and the depth at which you should start rendering buttons. The function will then draw (starting at the current cursor position) any buttons deemed necessary based on the input parameters. See section 7.4 Creating a display.
Next, you need to register function overrides. This may look something like this:
(speedbar-add-mode-functions-list '("MYEXTENSION" (speedbar-item-info . MyExtension-speedbar-item-info) (speedbar-line-directory . MyExtension-speedbar-line-directory))) |
The first element in the list is the name of you extension. The second is an alist of functions to overload. The function to overload is first, followed by what you want called instead.
For speedbar-line-directory
your function should take an optional DEPTH
parameter. This is the starting depth for heavily indented lines. If
it is not provided, you can derive it like this:
(save-match-data (if (not depth) (progn (beginning-of-line) (looking-at "^\\([0-9]+\\):") (setq depth (string-to-int (match-string 1))))) |
where the depth is stored as invisible text at the beginning of each line.
The path returned should be the full path name of the file associated with that line. If the cursor is on a tag, then the file containing that tag should be returned. This is critical for built in file based functions to work (meaning less code for you to write). If your display does not deal in files, you do not need to overload this function.
The function speedbar-item-info
, however, is very likely to need
overloading. This function takes no parameters and must derive a text
summary to display in the minibuffer.
There are several helper functions you can use if you are going to use
built in tagging. These functions can be or
ed since each one
returns non-nil
if it displays a message. They are:
speedbar-item-info-file-helper
speedbar-line-file
. It shows details about a file.
speedbar-item-info-tag-helper
Your custom function might look like this:
(defun MyExtension-item-info () "Display information about the current line." (or (speedbar-item-info-tag-helper) (message "Interesting detail."))) |
Once you have done all this, speedbar will show an entry in the `Displays' menu declaring that your extension is available.
If your major mode is running slowly, you may need to add a set of stealthy update functions.
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
they are in their speedbar related calculations) and permit
interruption. See speedbar-check-vc as a good example.
Stealthy functions are currently used in files mode. The first activity is to display the main list with minimal decorations though the buttons function. Once that is done, additional work can be done decorating different lines after the fact.
For files mode, VC status and read-only markers can calculated after the first display is up. Because the process of calculating that information can be slow, these functions are interruptable, and will continue processing at a later time out.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
It is possible to create new methods for tagging files in speedbar. To do this, you need two basic functions, one function to fetch the tags from a buffer, the other to insert them below the filename.
t
if
there was an error. file is not necessarily available as an
buffer when your function is called. Be sure to load it if it is needed
with code like this:
(save-excursion (set-buffer (find-file-noselect file)) ... ) |
The non-error return value can be anything, as long as it can be inserted by its paired function:
It is often useful to use speedbar-create-tag-hierarchy
on your
tag list 7.4 Creating a display.
Once these two functions are written, modify the variable
speedbar-dynamic-tags-function-list
to include your parser at the
beginning, like this:
(add-to-list 'speedbar-dynamic-tags-function-list '(my-fetch-dynamic-tags . my-insert-tag-list)) |
t
, then an
error occurred, and the next fetch routine is tried.
insert is a function which takes an INDENTation level, and a list of
tags to insert. It will then create the speedbar buttons.
If your parser is only good for a few types of files (ie, just texinfo
files), make sure that it is either a buffer local modification (set
only in texi files), or that the tag generator returns t
for
unsupported buffers.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Rendering a display in speedbar is completely flexible. When your
button function is called, see 7.1 Minor Display Modes, and 7.2 Major Display Modes, you have control to insert
anything you want.
The conventions allow almost anything to be inserted, but several helper functions are provided to make it easy to create the standardized buttons.
To understand the built in functions, each `button' in speedbar consists of four important pieces of data. The text to be displayed, token data to be associated with the text, a function to call, and some face to display it in.
When a function is provided, then that text becomes mouse activated, meaning the mouse will highlight the text.
Additionally, for data which can form deep trees, each line is given a depth which indicates how far down the tree it is. This information is stored in invisible text at the beginning of each line, and is used by the navigation commands.
7.4.1 Creating Speedbar Buttons | ||
7.4.2 Generic Tag Lists | ||
7.4.3 Expand Buttons |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
While it is certainly possible to insert your own text and add decorations to it, it is preferable to use the speedbar button creation API instead.
The optional argument token is extra data to associated with the
text. Lastly prevline should be non-nil
if you want this line to
appear directly after the last button which was created instead of on
the next line.
This routine creates a single button in the display, such as a [+] button, or the text that goes after it. It is designed to be called iteratively with indicators on when to add carriage returns between buttons.
To insert a more traditional speedbar line that includes an expansion button followed by clickable text, it is preferable to create a tag-line. Tag lines should be used to represent typical data a user will interact with.
Create a tag line with exp-button-type for the small expansion
button. This is the button that expands or contracts a node (if
applicable), and exp-button-char the character in it (`+',
`-', `?',
etc). exp-button-function is the function to call if it's clicked
on. Button types are 'bracket
, 'angle
, 'curly
,
'expandtag
, 'statictag
, or nil. exp-button-data is
extra data attached to the text forming the expansion button.
Next, tag-button is the text of the tag. tag-button-function is the function to call if clicked on, and tag-button-data is the data to attach to the text field (such a tag positioning, etc). tag-button-face is a face used for this type of tag.
Lastly, depth shows the depth of expansion.
This function assumes that the cursor is in the speedbar window at the position to insert a new item, and that the new item will end with a CR.
Major display modes that use this function will have a consistant look and feel and reliable image use.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
For data stored in a hierarchical list, it is likely possible to have the entire data structure inserted with the speedbar generic list methods.
These insertion functions assume that the data represents 'tags', or data extracted from inside a file, and they are marked with tag markers.
Tags stored in this format can then be manipulated by the tag hierarchy methods described earlier in this manual.
At level, (the current indentation level desired) insert a generic
multi-level alist list. Associations with lists get `{+}'
tags (to expand into more nodes) and those with positions or other data
just get a `>' as the indicator. `{+}' buttons will have the
function expand-fun and the token is the cdr
list. The
token name will have the function find-fun and not token.
Each element of the list can have one of these forms:
(name . marker-or-number)
(name (name . marker-or-number) (name . marker-or-number) ... )
(name marker-or-number (name . marker-or-number) ... )
When you use speedbar-insert-generic-list
, there are some
variables you can set buffer-locally to change the behavior. The most
obvious is speedbar-tag-hierarchy-method
.
See section 6.2 Tag Hierarchy Methods.
'curly
and 'expandtag
. Curly is the default button, and
'expandtag
is useful if the groups also has a position.
nil
and 'statictag
.
nil
is the default, and 'statictag
has the same width as
'expandtag
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Once you have made some buttons, you need to hitch them up to
do something once clicked on. This is set up with
speedbar-make-tag-line
which takes two functions. One is for
the expand button, and the other for the tag.
The function for the tag can be anything, but the expand button has
certain expectations. When that button is has a +
in it, that
indicates that there is "more" inside. A -
indicates that a
section can be closed.
The expand function takes the same signature as all speedbar button functions, such as:
(defun MY-expand-function (text token indent) "Display more information about MY thing. ..." |
This function should then use the text parameter to determine what to do. For example:
(cond ((string-match "+" text) ;we have to expand this file ;; Expand stuff here ) ((string-match "-" text) ;we have to contract this node ;; Contract stuff here )) |
When expanding or contracting, you will need to change the
+
or -
into the opposite symbol. You can do that with
Our sample would then look like this:
(cond ((string-match "+" text) ;we have to expand this file ;; Expand stuff here (speedbar-change-expand-button-char ?-) ) ((string-match "-" text) ;we have to contract this node ;; Contract stuff here (speedbar-change-expand-button-char ?+) )) |
To expand text, the speedbar buffer needs to be writable. The initial
button insertion function runs while the buffer is writable, but an
expand function will need to change that. The best way is to use
speedbar-with-writable
.
Once the buffer is writable, then you can insert more information using any mechanism you like. Remember that the cursor will be on the expand button just clicked though. As such, the code might look like this:
(cond ((string-match "+" text) ;we have to expand this file ;; Expand stuff here (speedbar-change-expand-button-char ?-) (speedbar-with-writable (save-excursion (end-of-line) (forward-char 1) ;; Insert goodies here. )) ) |
Contracting a node is a bit easier. You can just use this built in function to do the work:
Remember that indent is also available as passed into
MY-expand-function
.
The end result would then look like this:
(cond ((string-match "+" text) ;we have to expand this file ;; Expand stuff here (speedbar-change-expand-button-char ?-) (speedbar-with-writable (save-excursion (end-of-line) (forward-char 1) ;; Insert goodies here. )) ) ((string-match "-" text) ;we have to contract this node ;; Contract stuff here (speedbar-change-expand-button-char ?+) (speedbar-delete-subblock indent)) )) |
Expand buttons, unlike other speedbar operations can cause new data to appear in speedbar which would be useful to force onto the screen. You can then recenter using this function:
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by XEmacs shared group account on December, 19 2009
using texi2html 1.65.