[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9. Entry points for Elisp programmers

This chapter describes how ECB can be used/programmed/driven by an Elisp-program. This contains:

9.1 Variables for Elisp-programs  Which variables an Elisp-program can use
9.2 Available hooks of ECB  All available hooks
9.3 The library tree-buffer.el  Some words to the tree-buffer-library
9.4 How to deal with the adviced window-functions  How to deal with the adviced functions
9.5 How to program new layouts and new special windows  Programming new layouts and special windows

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.1 Variables for Elisp-programs

Variables an Elisp-program can use beyond those ones mentioned in 9.5 How to program new layouts and new special windows:

Look at the documentation of these variables to get a description.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.2 Available hooks of ECB

The following hooks are available:

Look at the documentation of these hooks to get a detailed description.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.3 The library tree-buffer.el

The library tree-buffer.el is ECB independent and can be used for other applications too. But such an application is not allowed to use any of the variables of tree-buffer.el especially not the variable tree-buffers!

tree-buffers: Only for internal use. It contains all tree-buffers of current Emacs-instance, means all tree-buffers of all applications which uses currently tree-buffers. Every application must store its own collection of tree-buffers in an own variable! For example: ECB stores its tree-buffer set in ecb-tree-buffers!

An application may only use the methods tree-buffer.el provides but no internal variables!

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.4 How to deal with the adviced window-functions

ECB offers for packages which work during activated ECB three macros for easy temporally(42) using all original-functions, all adviced functions or only some adviced functions:

For a detailed explanation of each macro read the documentation with describe-function!

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.5 How to program new layouts and new special windows

There are two aspects concerning this topic:

  1. Programming a new layout which contains several special ECB-windows like directories, sources, methods, history or other special windows and arranging them in a new outline.

  2. Creating complete new special windows (e.g. a local-variable window for a graphical debugger like JDEbug of JDEE), adding them to a layout and synchronizing them with the current active edit-window.

The former one covers merely the layout-programming aspect which is explained in the first subsection of this chapter whereas the latter one covers all aspects of creating new special windows and what is necessary to synchronize it with the current active edit-window of ECB. This is explained in the second subsection which will refers to the first subsection.

9.5.1 How to program a new layout  
9.5.2 All aspects of programming special windows  Aspects of programming special windows
9.5.3 The wide range of possible layout-outlines  The wide range of possible layouts
9.5.4 The complete layout-engine API of ECB  The complete layout-engine API

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.5.1 How to program a new layout

If you just want creating a new layout with the standard ECB-windows like directories, sources, methods, history and speedbar it's is strongly recommended to define the new layout interactively with the command ecb-create-new-layout (see section 4.8.5 Interactively creating new layouts).

If you want creating a new layout and if this layout should contain other special windows than the standard ECB-windows then it's still recommended to define this layout interactively with ecb-create-new-layout and using the option to give the created windows user-defined types. For every user defined type you have then just to program the necessary buffer-set function. For all the details see 4.8.5 Interactively creating new layouts.

But if you do not like the interactive way (because you are tough and brave) but you want programming the new layout with Elisp then use the macro ecb-layout-define (the following definition has stripped the prefix "ecb-" for better indexing this manual):

Macro: layout-define name type &rest create-code
Creates a new ECB-layout with name NAME. TYPE is the type of the new layout and is literal, i.e. not evaluated. It can be left, right, top or left-right. DOC is the docstring for the new layout-function "ecb-layout-function-<name>". CREATE-CODE is all the lisp code which is necessary to define the ECB-windows/buffers. This macro adds the layout with NAME and TYPEto the internal variable ecb-available-layouts.

Preconditions for CREATE-CODE:

  1. Current frame is splitted at least in one edit-window and the "column" (for layout types left, right and left-right) rsp. "row" (for a top layout) for the special ECB-windows/buffers. The width of the "column" rsp. the height of the "row" is always defined with the option ecb-windows-width rsp. ecb-windows-height. Depending on the value of the option ecb-compile-window-height there is also a compile window at the bottom of the frame which is stored in ecb-compile-window.

  2. All windows are not dedicated.

  3. Neither the edit-window nor the compile-window (if there is one) are selected for types left, right and top. For type left-right the left column-window is selected

  4. All ECB-advices for the functions in ecb-advice-window-functions are disabled!

Things CREATE-CODE has to do:

  1. Splitting the ECB-tree-windows-column(s)/row (s.a.) in all the ECB-windows the layout should contain (directories, sources, methods and history). The split must not be done with other functions than ecb-split-hor and ecb-split-ver! It is recommended not to to use a "hard" number of split-lines or -rows but using fractions between -0.9 and +0.9! Tip: It is recommended to spilt from right to left and from bottom to top or with other words: First create the right-most and bottom-most special windows!

  2. Making each special ECB-window a dedicated window. This can be done with one of the following functions:
    • ecb-set-directories-buffer
    • ecb-set-sources-buffer
    • ecb-set-methods-buffer
    • ecb-set-history-buffer
    • ecb-set-speedbar-buffer
    Each layout can only contain one of each tree-buffer-type!

    In addition to these functions there is a general macro ecb-with-dedicated-window. This macro performs any arbitrary code in current window and makes the window autom. dedicated at the end. This can be used by third party packages like JDEE to create arbitrary ECB-windows besides the standard tree-windows.

    To make a special ECB-window a dedicated window either one of the five functions above must be used or a function(!) which calls in turn the macro ecb-with-dedicated-window. See the documentation of this macro how to use it!

    Such a function is called a "dedicated setter" and must(!) use ecb-with-dedicated-window to make the window dedicated!

  3. Every(!) special ECB-window must be dedicated as described in 2.

  4. CREATE-CODE must work correctly regardless if there is already a compile-window (stored in ecb-compile-window) or not (ecb-compile-window is nil).

Things CREATE-CODE can do or can use:

  1. The value of ecb-compile-window which contains the compile-window (if there is one). Using the values of ecb-compile-window-height, ecb-windows-width, ecb-windows-height.

Things CREATE-CODE must NOT do:

  1. Splitting the edit-window
  2. Creating a compile-window
  3. Deleting the edit-window, the compile-window (if there is any) or the ECB-windows-column(s)/row (see Precondition 1.)
  4. Referring to the value of ecb-edit-window because this is always nil during CREATE-CODE.

Postconditions for CREATE-CODE:

  1. The edit-window must be the selected window and must not be dedicated and not be splitted.

  2. Every window besides the edit-window \(and the compile-window) must be a dedicated window \(e.g. a ECB-tree-window).

Use this macro to program new layouts within your `.emacs' or any other file which is loaded into your Emacs. After loading the file(s) with all the new layout-definitions you can use it by customizing the option ecb-layout-name to the appropriate name or with the command ecb-change-layout.

With the function ecb-layout-undefine you can remove a layout from the list of available layouts:

Function: layout-undefine name
Unbind ecb-layout-function-<NAME> and ecb-delete-window-ecb-windows-<NAME> and remove NAME from ecb-available-layouts.

Here is an example for a new layout programmed with ecb-layout-define:

(ecb-layout-define "my-own-layout" left nil
  ;; The frame is already splitted side-by-side and point stays in the
  ;; left window (= the ECB-tree-window-column)

  ;; Here is the creation code for the new layout
  ;; 1. Defining the current window/buffer as ECB-methods buffer
  ;; 2. Splitting the ECB-tree-windows-column in two windows
  (ecb-split-ver 0.75 t)
  ;; 3. Go to the second window
  (other-window 1)
  ;; 4. Defining the current window/buffer as ECB-history buffer
  ;; 5. Make the ECB-edit-window current (see Postcondition above)
  (select-window (next-window)))

This layout definition defines a layout with name "my-own-layout" which looks like:

|              |                                      |
|              |                                      |
|              |                                      |
|  Methods     |                                      |
|              |                                      |
|              |                                      |
|              |               Edit                   |
|              |                                      |
|              |                                      |
|--------------|                                      |
|              |                                      |
|  History     |                                      |
|              |                                      |
|                                                     |
|                    Compilation                      |
|                                                     |

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.5.2 All aspects of programming special windows

ECB offers a flexible programmable layout-engine for other packages to display their own contents and informations in special ECB-windows. An example could be a graphical debugger which offers a special window for displaying local variables and another special window for messages from the debugger-process (like JDEbug of JDEE(43)).

This section explains all aspects of programming new special windows, adding them to a new layout and synchronizing them with edit-window of ECB. This can be done best with an easy example which nevertheless covers all necessary aspects to be a good example and skeleton for complex tools (like a graphical debugger) which want to use the layout-engine of ECB do display their own information.

Here comes the example:

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ] The outline of the example layout:

|Bufferinfo for <filename>:            |[prior]       |
|Type: file                            |[next]        |
|Size: 23456                           |              |
|Modes: rw-rw-rw-                      |              |
|                                                     |
|                                                     |
|                                                     |
|                                                     |
|                 edit-window                         |
|                                                     |
|                                                     |
|                                                     |
|                                                     |
|                                                     |
|                 compilation-window                  |
|                                                     |

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ] The description of the layout-contents

The top-left window always displays informations about the current buffer in the selected edit-window. This window demonstrates how autom. synchronizing a special window/buffer of a layout with current edit-window.

The top-right window contains an read-only "action-buffer" and offers two buttons which can be used with the middle mouse-button to scroll the edit-window. This is not very senseful but it demonstrates how to control the edit-window with actions performed in a special window/buffer of a layout.

(If you have not set a compilation-window in ecb-compile-window-height then the layout contains no durable compilation window and the other windows get a little more place).

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ] The example code

Now let have us a look at the several parts of the Elisp-program needed to program this new example layout. ECB contains a library `ecb-examples.el' which contains the full working code of this example. To test this example and to play with it you can load this library into Emacs (with load-library for example) and then calling ecb-change-layout (bound to C-c . lc) and inserting "example-layout1" as layout-name. An alternative is calling ecb-examples-activate and ecb-examples-deactivate. For details see file `ecb-examples.el'.

The following steps only contain code-skeletons to demonstrate the principle. The full working code is available in `ecb-examples.el'.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ] The bufferinfo buffer of the example

The name of the bufferinfo buffer:

(defconst ecb-examples-bufferinfo-buffer-name " *ECB buffer info*")

Two helper functions for displaying infos in a special buffer:

(defun ecb-examples-print-file-attributes (buffer filename)
  (ecb-with-readonly-buffer buffer
    (insert (format "Bufferinfo for %s:\n\n" filename))
    ;; insert with the function `file-attributes' some 
    ;; informations about FILENAME.

(defun ecb-examples-print-non-filebuffer (buffer buffer-name)
  (ecb-with-readonly-buffer buffer
    ;; analogous to `ecb-examples-print-file-attributes'

The main synchronizing function added to ecb-current-buffer-sync-hook for autom. evaluation by ecb-current-buffer-sync which runs dependent on the values of ecb-window-sync and ecb-window-sync-delay. This function synchronizes the bufferinfo buffer with the current buffer of the edit-window if that buffer has changed.

(defun ecb-examples-bufferinfo-sync ()

    ;; here we can be sure that the buffer with name
    ;; `ecb-examples-bufferinfo-buffer-name' is displayed in a 
    ;; window of `ecb-frame'

    ;; The macro `ecb-do-if-buffer-visible-in-ecb-frame' locally 
    ;; binds the variables visible-buffer and visible-window!! See
    ;; documentation of this macro!

    (let ((filename (buffer-file-name (current-buffer))))
      (if (and filename (file-readable-p filename))
          ;; real filebuffers
          ;; here we could add a smarter mechanism;
          ;; see ecb-examples.el
          (ecb-examples-print-file-attributes visible-buffer
        ;; non file buffers like help-buffers etc...
        (setq ecb-examples-bufferinfo-last-file nil)
        (ecb-examples-print-non-filebuffer visible-buffer

The function which makes the bufferinfo-buffer dedicated to a window.

(defun ecb-examples-set-bufferinfo-buffer ()
    (switch-to-buffer (get-buffer-create
    (setq buffer-read-only t)))

This is all what we need for the special bufferinfo buffer. We have demonstrated already three of the important functions/macros of the layout-engine API of ECB: ecb-with-readonly-buffer, ecb-do-if-buffer-visible-in-ecb-frame and ecb-with-dedicated-window (see section 9.5.4 The complete layout-engine API of ECB. Especially the second macro is strongly recommended for programming good synchronizing functions which do not waste CPU!

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ] The action buffer of the example

The name of the action-buffer:

(defconst ecb-examples-action-buffer-name " *ECB action buffer*")

Two helper functions for creating a readonly action-buffer with a special local key-map for the middle-mouse-button and two buttons [prior] and [next]:

(defun ecb-examples-insert-text-in-action-buffer (text)
  (let ((p (point)))
    (insert text)
    (put-text-property p (+ p (length text)) 'mouse-face

(defun ecb-examples-action-buffer-create ()
    (if (get-buffer ecb-examples-action-buffer-name)
        (get-buffer ecb-examples-action-buffer-name)

      (set-buffer (get-buffer-create

      ;; we setup a local key-map and bind middle-mouse-button
      ;; see ecb-examples.el for the full code        

      ;; insert the action buttons [prior] and [next] and
      ;; make it read-only
      (ecb-with-readonly-buffer (current-buffer)
        (ecb-examples-insert-text-in-action-buffer "[prior]")
        ;; analogous for the [next] button

The function which performs the actions in the action-buffer if clicked with the middle-mouse button onto a button [next] or [prior].

(defun ecb-examples-action-buffer-clicked (e)
  (interactive "e")
  (mouse-set-point e)
  (let ((line (buffer-substring (ecb-line-beginning-pos)
    (cond ((string-match "prior" line)
           (call-interactively 'scroll-down))
          ((string-match "next" line)
           ;; analogous for [next]

The function which makes the action-buffer dedicated to a window.

(defun ecb-examples-set-action-buffer ()
  (let ((buf-name (buffer-name (ecb-examples-action-buffer-create))))
    (ecb-with-dedicated-window buf-name 'ecb-examples-set-action-buffer
      (switch-to-buffer (buffer-name

We do not need more code for the action buffer. All of the code is standard emacs-lisp which would also needed if used without ECB.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ] Adding the bufferinfo- and action-buffer to a new layout

Now we add the bufferinfo- and the action-buffer to a new layout of type top with name "example-layout1":

(ecb-layout-define "example-layout1" top
  ;; dedicating the bufferinfo window to the bufferinfo-buffer

  ;; creating the action-window
  (ecb-split-hor 0.75)
  ;; dedicate the action window to the action-buffer

  ;; select the edit-window
  (select-window (next-window)))

This all what we need to define the new layout. See 9.5.1 How to program a new layout for more details of the pure layout-programming task.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ] Synchronizing the bufferinfo-buffer automatically

The last thing we have to do is to synchronize the bufferinfo-buffer with current edit-window. We do this by adding ecb-examples-bufferinfo-sync to the hook ecb-current-buffer-sync-hook' (The file `ecb-examples.el' shows a smarter mechanism for (de)activating the new layout and the synchronization but this works also very well).

(add-hook 'ecb-current-buffer-sync-hook 'ecb-examples-bufferinfo-sync)

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ] Activating and deactivating new layouts

Because a set of new special windows integrated in a new layout is often just the GUI of a complete tool (like a graphical debugger) we demonstrate here the complete activation and deactivation of such a tool or at least of the tool-GUI. We decide that the GUI of our example "tool" needs a compile-window with height 5 lines and the height of the special windows "row" on top should be exactly 6 lines (normally width and height of the special windows should be a fraction of the frame, but here we use 6 lines(44)

Here comes the (de)activation code.

The code for saving and restoring the state before activation (the full code is available in `ecb-examples.el':

(defun ecb-examples-preactivation-state(action)
  (cond ((equal action 'save)
         ;; code for saving the state
        ((equal action 'restore)
        ;; code for restoring the state

The following function activates the GUI of our example tool:

(defun ecb-examples-activate ()
  ;; activating the synchronization of the bufferinfo-window
  (add-hook 'ecb-current-buffer-sync-hook
  ;; saving the state
  (ecb-examples-preactivation-state 'save)

  ;; switch to our preferred layout
  (setq ecb-windows-height 6)
  (setq ecb-compile-window-height 5)
  (ecb-layout-switch "example-layout1"))

This function deactivates the GUI of our example-tool and restores the state as before activation:

(defun ecb-examples-deactivate ()
  (remove-hook 'ecb-current-buffer-sync-hook
  (ecb-examples-preactivation-state 'restore)
  (ecb-layout-switch ecb-layout-name))

Now we have all code for the new layout and the new layout-buffers. The example is ready for use; just load `ecb-examples.el' (s.a.).

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.5.3 The wide range of possible layout-outlines

In the two previous sections 9.5.1 How to program a new layout and 9.5.2 All aspects of programming special windows we have explained in detail how to program new layouts and how to program new special windows/buffers and adding them to a new layout.

The intention of this section is to be a summary what are the real restrictions for a new layout-outline programmed with ecb-layout-define. This is necessary because until now we just programmed "obvious" layouts, means layout which are in principle very similar to the standard ones which means one big edit-window and some special windows "around" this edit-window. This section will show you that a layout can have also very different outlines.

OK, here are the real restrictions and conditions for a layout programmed with ecb-layout-define:

  1. It must have exactly one edit-window regardless of its size. The user of this layout can later split this edit-window in as many edit-windows as he like.

  2. All other windows created within the CREATE-CODE body of ecb-layout-define (see section 9.5.1 How to program a new layout) must be dedicated to their buffers.

  3. All the dedicated windows must (exclusive!) either reside on the left, right, top or left-and-right side of the edit-window. This will be defined with the TYPE-argument of ecb-layout-define (see section 9.5.1 How to program a new layout).

You see, there are only three restrictions/conditions. These and only these must be fulfilled at layout-programming.

Demonstrating what this really means and how flexible the layout-engine of ECB really is, can be done best with some "pathological" layout-outlines. All the following are correct layouts (working code is added below each layout):

The following is a top layout with three vertical layered special windows.

|                                                                |
|                 Upper special window                           |
|                                                                |
|                                                                |
|                 Middle special window                          |
|                                                                |
|                                                                |
|                 Lower special window                           |
|                                                                |
|                                                                |
|                         Edit-area                              |
|      (can be splitted by the user in several edit-windows)     |
|                                                                |
|                 Compilation-window (optional)                  |
|                                                                |

Here is the code for that top layout (all buffers are dummy-buffers):

;; The "dedicated setter" functions:

(defun ecb-set-usw-buffer ()
    "Upper special window"
      (switch-to-buffer (get-buffer-create "Upper special window"))))

(defun ecb-set-msw-buffer ()
    "Middle special window"
      (switch-to-buffer (get-buffer-create "Middle special window"))))

(defun ecb-set-lsw-buffer ()
    "Lower special window"
      (switch-to-buffer (get-buffer-create "Lower special window"))))

;; The layout itself:

(ecb-layout-define "example-layout3" top

  ;; here we have an edit-window and above one top window which we can
  ;; now split in several other windows. Dependent on the value of
  ;; `ecb-compile-window-height' we have also a compile-window at the
  ;; bottom.

  (ecb-split-ver 0.33)
  (ecb-split-ver 0.5)

  ;; select the edit-window.
  (select-window (next-window)))

The following is a left-right layout which has six special windows in the left-"column" and one big special window in the right-"column". For left-right layouts the left-"column" and the right-"column" have always the same width.

|             |       |                   |                      |
| Left1       | Left5 |                   |                      |
|             |       |                   |                      |
|-------------|       |                   |                      |
|      |      |       |                   |                      |
|      |      |       |                   |                      |
|      |      |       |                   |                      |
| Left2| Left3|-------|     Edit-area     |   Right1             |
|      |      |       | (can be splitted  |                      |
|      |      |       |  in several edit- |                      |
|      |      |       |      windows)     |                      |
|-------------|       |                   |                      |
|             |       |                   |                      |
| Left4       | Left6 |                   |                      |
|             |       |                   |                      |
|                                                                |
|                 Compilation-window (optional)                  |
|                                                                |

Here is the code for that left-right layout, again with dummy-buffers (depending to your screen-resolution you will need a quite big value for ecb-windows-width, e.g. 0.4):

Here is one of the "dedicated setter" functions(45):

(defun ecb-set-left1-buffer ()
      (switch-to-buffer (get-buffer-create "Left1"))))

Here is the layout-definition itself:

(ecb-layout-define "example-layout2" left-right

  ;; here we have an edit-window and left and right two windows each
  ;; with width `ecb-windows-width'. Dependent to the value of
  ;; `ecb-compile-window-height' we have also a compile-window at the
  ;; bottom.

  (ecb-split-hor 0.66 t)
  (ecb-split-ver 0.75)
  (select-window (previous-window (selected-window) 0))
  (ecb-split-ver 0.25 nil t)
  (ecb-split-hor 0.5)
  (select-window (next-window (next-window)))
  (ecb-split-ver 0.5)
  (select-window (next-window (next-window)))

  ;; select the edit-window
  (select-window (previous-window (selected-window) 0)))

Especially the last example should demonstrate that even very complicated layouts are easy to program with ecb-layout-define. If such layouts are senseful is another topic ;-)

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.5.4 The complete layout-engine API of ECB

This section lists all functions, macros, variables and user-options the layout-engine API of ECB offers foreign packages. Call describe-function rsp. describe-variable to get a detailed description.

Functions for programming with layouts and special ecb-windows:

Utility functions/macros:

Some other maybe useful functions/macros:

Some useful READONLY variables:


User-options and hooks related to the layout-engine API:

[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by XEmacs Webmaster on October, 2 2007 using texi2html