Node:Programming special windows, Next:Possible layout-outlines, Previous:Programming a new layout, Up:The layout-engine
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 JDEE1).
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:
------------------------------------------------------- |Bufferinfo for <filename>: |[prior] | |Type: file |[next] | |Size: 23456 | | |Modes: rw-rw-rw- | | |-----------------------------------------------------| | | | | | | | | | edit-window | | | | | | | | | ------------------------------------------------------- | | | compilation-window | | | -------------------------------------------------------
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).
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
.
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 (erase-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 (erase-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 () (ecb-do-if-buffer-visible-in-ecb-frame 'ecb-examples-bufferinfo-buffer-name ;; 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 filename) ;; non file buffers like help-buffers etc... (setq ecb-examples-bufferinfo-last-file nil) (ecb-examples-print-non-filebuffer visible-buffer (buffer-name (current-buffer))) ))))
The function which makes the bufferinfo-buffer dedicated to a window.
(defun ecb-examples-set-bufferinfo-buffer () (ecb-with-dedicated-window ecb-examples-bufferinfo-buffer-name 'ecb-examples-set-bufferinfo-buffer (switch-to-buffer (get-buffer-create ecb-examples-bufferinfo-buffer-name)) (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 The layout-engine API. Especially the second macro is strongly recommended for
programming good synchronizing functions which do not waste CPU!
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 'highlight))) (defun ecb-examples-action-buffer-create () (save-excursion (if (get-buffer ecb-examples-action-buffer-name) (get-buffer ecb-examples-action-buffer-name) (set-buffer (get-buffer-create ecb-examples-action-buffer-name)) ;; 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) (erase-buffer) (ecb-examples-insert-text-in-action-buffer "[prior]") ;; analogous for the [next] button ) (current-buffer))))
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) (ecb-line-end-pos)))) (cond ((string-match "prior" line) (ecb-select-edit-window) (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 (ecb-examples-action-buffer-create))))))
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.
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 (ecb-examples-set-bufferinfo-buffer) ;; creating the action-window (ecb-split-hor 0.75) ;; dedicate the action window to the action-buffer (ecb-examples-set-action-buffer) ;; select the edit-window (select-window (next-window)))
This all what we need to define the new layout. See Programming a new layout for more details of the pure layout-programming task.
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)
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 lines2
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 () (interactive) ;; activating the synchronization of the bufferinfo-window (add-hook 'ecb-current-buffer-sync-hook 'ecb-examples-bufferinfo-sync) ;; 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 () (interactive) (remove-hook 'ecb-current-buffer-sync-hook 'ecb-examples-bufferinfo-sync) (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.).
JDEE is available at http://jdee.sunsite.dk/
You can change the code
in the file ecb-examples.el
to use a frame-fraction of 0.2
instead of 6 hard lines, just try it!