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.
IMPORTANT: See tree-buffer for a full documentation of the library tree-buffer.el which can be used for programming a new special window as a tree!
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 persistent
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)))
))))
Two conveniance commands for the user:
(defun ecb-maximize-bufferinfo-window () "Maximize the bufferinfo-window. I.e. delete all other ECB-windows, so only one ECB-window and the edit-window\(s) are visible \(and maybe a compile-window). Works also if the ECB-analyse-window is not visible in current layout." (interactive) (ecb-display-one-ecb-buffer ecb-examples-bufferinfo-buffer-name)) (defun ecb-goto-bufferinfo-window () "Make the bufferinfo-window the current window." (interactive) (ecb-goto-ecb-window ecb-examples-bufferinfo-buffer-name))
The function which makes the bufferinfo-buffer dedicated to a window
and registers the new special window/buffer at ECB.
(defecb-window-dedicator ecb-examples-set-bufferinfo-buffer
ecb-examples-bufferinfo-buffer-name
"Set the buffer in the current window to the bufferinfo-buffer
and make this window dedicated for this 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
defecb-window-dedicator (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]
))))
Two conveniance-commands for the user:
(defun ecb-maximize-action-window () "Maximize the action-window. I.e. delete all other ECB-windows, so only one ECB-window and the edit-window\(s) are visible \(and maybe a compile-window). Works also if the ECB-analyse-window is not visible in current layout." (interactive) (ecb-display-one-ecb-buffer ecb-examples-action-buffer-name)) (defun ecb-goto-action-window () "Make the action-window the current window." (interactive) (ecb-goto-ecb-window ecb-examples-action-buffer-name))
The function which makes the action-buffer dedicated to a window and
registers it at ECB.
(defecb-window-dedicator ecb-examples-set-action-buffer
(buffer-name (ecb-examples-action-buffer-create))
"Set the buffer in the current window to the action-buffer
and make this window dedicated for this 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. You
see that you can use any arbitrary code as second argument for
defecb-window-dedicator as long it returns a buffer-name.
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!