(Re)generate: (find-multiwindow-intro)
Source code:  (find-efunction 'find-multiwindow-intro)
More intros:  (find-eev-quick-intro)
              (find-eev-intro)
              (find-eval-intro)
              (find-eepitch-intro)
This buffer is _temporary_ and _editable_.
It is meant as both a tutorial and a sandbox.




1. Introduction

In many situations - for example, when we want to script a debugger, or to test programs that have to talk to one another, or to control several external machines simultaneously - the default window setup for eepitch, which is this, ____________________ | | | | | | | script | shell | | | | | | | |__________|_________| is not enough; other setups, like these, ______________________ | | | _________________________ | | shell A | | | | | |___________| | script | GDB | | script | | | | | | | shell B | |____________|____________| | |___________| | | | | | | | program | program | | | shell C | | I/O | source | |__________|___________| |____________|____________| may be necessary. Eev comes with a few _low-level_ tools for creating these setups; they are not very smart, but they should be easy to understand and to tweak - and I have the impression that ideas for good high-level tools will only come from practical experimentation.

2. `find-wset'

Suppose that we are in a buffer A, and we want to create a window configuration with A at the left, and with the buffers B and C stacked on one another at the right. That is: ___________ ___________ | | | | | | | | | B | | A | --> | A |_____| | | | | | | | | | C | |___________| |_____|_____| To do that from the keyboard we could type this: C-x 3 C-x o C-x b B RET C-x 2 C-x o C-x b C RET You can try that here (the initial `C-x 1' is an extra, for convenience): (eek "C-x 1 ;; delete-other-windows C-x 3 ;; split-window-horizontally (left/right) C-x o ;; other-window (-> right) C-x b B RET ;; switch to the buffer `B' C-x 2 ;; split-window-vertically (upper/lower) C-x o ;; other-window (-> lower right) C-x b C RET ;; switch to the buffer `C' ") We can write something equivalent to that as a `progn', in a way that makes it easy to replace later the `C-x b B RET' and the `C-x b C RET' by arbitrary sexp hyperlinks. We get: (progn (eek "C-x 1 C-x 3 C-x o") (find-ebuffer "B") (eek "C-x 2 C-x o") (find-ebuffer "C") (eek "C-x o") ) When I started to rewrite my window configurations into that form I realized that the `eek's were being used in a very limited way - they only invoked a very small repertoire of window commands, all of them starting with `C-x'. So maybe I should have an interpreter for a simple language of window commands and sexp hyperlinks, in the which window setup above could be expressed like this: `("13o" (find-ebuffer "B") "2o" (find-ebuffer "C") "o" ) `find-wset' supports something like that, but with all the window command strings collapsed into a single one, with "_"s meaning "execute the next sexp from the sexp list". The corresponding call to `find-wset' is: (find-wset "13o_2o_o" '(find-ebuffer "B") '(find-ebuffer "C")) For the full list of supported window command characters - and how to extend it - see the source: (find-eev "eev-multiwindow.el")

3. High-level words

Very often we want to create window setups like _______________ _______________ | | | | | | | | | | | B | | A | B | or | A |_______| ; | | | | | | | | | | | C | |_______|_______| |_______|_______| there are shorthands for that. If you run (find-2a sexpA sexpB) that will create a window setting like the one at the left above, initially with two copies of the current buffer, then will run sexpA at the window "A" and sexpB at the window "B", and finally will select the window "A", i.e., leave the cursor at the window at the left; this (find-2b sexpA sexpB) will do exactly the same as the `(find-2a ...)' above, but will select the window "B" - the one at the right - at the end of the process. For three-window settings we have these: (find-3a sexpA sexpB sexpC) (find-3b sexpA sexpB sexpC) (find-3c sexpA sexpB sexpC) all three create the three-window setting at the right above, initially with all three windows displaying the current buffer, then run sexpA at the window "A", sexpB at the window "B", and sexpC at the window "C"; the difference is that find-3a selects the window "A", find-3b the window "B", find-3c the window "C".

4. Several eepitch targets

If we try to build a window setup like this one, with two eepitch targets, with just `find-wset', we will run into problems - ________________________ | | | | | *shell* | | script |_____________| | | | | | *shell 2* | |__________|_____________| because `(eepitch-shell)' and `(eepitch-shell2)' try to create a shell buffer and put it in an _another_ window, not the one we are in... one solution is to call the `(eepitch-*)' sexps inside an `ee-here', like this: (ee-here '(eepitch-shell)) (ee-here '(eepitch-shell2)) where `ee-here' is a hack that runs a sexp in a way that preserves the current window configuration, then switches the buffer in the current selected window to the current eepitch target. We can use this to create the window setting above, (find-wset "13o2_o_o" ' (ee-here '(eepitch-shell)) ' (ee-here '(eepitch-shell2)) ) This is too long - and would make a very bad one-liner - but there are two shorthands. First, "e" is a variant of "_" that runs its sexp inside an `(ee-here ...) - so this is equivalent the thing above, (find-wset "13o2eoeo" '(eepitch-shell) '(eepitch-shell2) ) Second, these things are useful enough to deserve a high-level word, so this is equivalent to: (find-3ee '(eepitch-shell) '(eepitch-shell2))

5. Restarting eepitch targets

Sometimes we want to do the same as above, but restarting both eepitch targets, i.e., something like this: (find-3ee '(progn (eepitch-shell) (eepitch-kill) (eepitch-shell)) '(progn (eepitch-shell2) (eepitch-kill) (eepitch-shell2)) ) There's a variant of `ee-here' that does that: `ee-here-reset'. For example, (ee-here-reset '(eepitch-shell2)) is equivalent to: (ee-here '(progn (eepitch-shell2) (eepitch-kill) (eepitch-shell2))) and the letter "E" is a variant of "e" that uses `ee-here-reset' instead of `ee-here'; also, `find-3EE' is a variant of `find-3ee' that restarts both targets. Let's adapt this example, (find-eepitch-intro "Other targets") to make it show the two eepitch targets at once in a three-window settings. It becomes: * (find-3EE '(eepitch-shell) '(eepitch-python)) * (eepitch-shell) echo Hello... > /tmp/o * (eepitch-python) print(open("/tmp/o").read()) * (eepitch-shell) echo ...and bye >> /tmp/o * (eepitch-python) print(open("/tmp/o").read()) ** Now compare: * (eek "C-x 1") * (find-3ee '(eepitch-shell) '(eepitch-python)) * (find-3EE '(eepitch-shell) '(eepitch-python))

6. Non-trivial examples

See: (find-prepared-intro "An `ee' for Python") (find-rcirc-intro "The server buffer and the channel buffers")

7. Eepitch blocks for two targets

An eepitch script with two targets uses several different kinds of red star lines - `(eepitch-target1)', `(eepitch-target2)', `(find-3EE ...)', `(find-3ee ...)', etc. We don't want to have to type all those by hand, so there is a hack similar to `M-T' that generates all those kinds from just "target1" and "target2" to let us just copy around the sexps we need. It is bound to `meta-shift-3', which Emacs sees as `M-#'. Compare the result of typing `M-T' here, python with the result of typing `M-#' on this line, shell python which yield this: * (find-3EE '(eepitch-shell) '(eepitch-python)) * (find-3ee '(eepitch-shell) '(eepitch-python)) * (eepitch-shell) * (eepitch-python) Note that we use to `find-3EE' to restart targets instead of `eepitch-kill' (this is non-trivial - think about it =/)...

8. Adding support for new characters in `find-wset'

The standard characters supported by `find-wset' are these: char action key ---- ---------------------------- --------- `1' `delete-other-windows' (C-x C-1) `2' `split-window-vertically' (C-x C-2) `3' `split-window-horizontally' (C-x C-3) `s' `split-window-sensibly' `o' `other-window' (C-x o) `+' `balance-windows' (C-x +) `_' execute the next sexp but the action of each one is defined in a different function, and to add support for a new character, say, `=', we just need to define a function with the right name - in this case, `find-wset-='. The source code is simple enough, so take a look: (find-eev "eev-multiwindow.el" "find-wset-_") (find-eev "eev-multiwindow.el" "find-wset-=") (find-eev "eev-multiwindow.el" "find-wset-!") Note that `find-wset-!' restarts an eepitch target, while `find-wset-=' will reuse an eepitch target if its buffer already exists. [Obs: "=" and "!" have been mostly superseded by "e" and "E"... to do: explain this] See: (find-prepared-intro) [Example at find-prepared-intro]

9. Executing key sequences at other windows

It is possible to use multi-window settings, together with the trick that `<f8>' on a red star line executes it as Lisp and moves down, to create tutorials for Emacs modes. An example: (...)

10. A tutorial for Info mode

Here's a mini-tutorial for Info mode, demonstrating how to navigate in Info using the usual movement keys, plus TAB, <backtab>, RET, l (last), u (up), n (next), p (prev), q (quit), C-h i, and the digits 1-9. Note that the display in Info mode is like this: ____________________________________________ |Next: Nonincremental Search, Up: Search | <- next/prev/up | (emacs)Top > Search > Incremental Search | <- breadcrumbs | | | 19.1 Incremental Search | <- section number / | | node name (long) | (...) | | | |--:%%- *info* (emacs) Incremental Search | |____________________________________________| Here: ** Define some hacks * (defun ow (n) (other-window n)) * (defun eeoe (code) (ow 1) (prog1 (eval code) (ow -1))) * (defun eeok (keystr) (eeoe `(eek ,keystr))) * ** Prepare the windows * (ee-kill-buffer "*info*") * (find-wset "1so_o" '(find-enode "Search")) * ** The arrows (and other movent keys) work as expected. ** Watch the cursor in the Info window... * (eeok "3*<down>") * (eeok "10*<right>") * ** TAB and <backtab> move to the next and to the previous link. ** Note that they consider all the links in a page, not only ** the ones in menus - including the breadcrumb links at the top. * (eeok "TAB ;; Info-next-reference") * (eeok "TAB ;; Info-next-reference") * (eeok "TAB ;; Info-next-reference") * (eeok "TAB ;; Info-next-reference") * (eeok "TAB ;; Info-next-reference") * (eeok "<backtab> ;; Info-prev-reference") * (eeok "<backtab> ;; Info-prev-reference") * (eeok "<backtab> ;; Info-prev-reference") * (eeok "<backtab> ;; Info-prev-reference") * ** RET follows a link, l (last) goes back. ** Watch the section number: 19 -> 32.3.6 -> 19. * (eeok "RET ;; Info-follow-nearest-node") * (eeok "l ;; Info-history-back") * ** The digits 1-9 can be used to go straight to subsections. ** For example, a `4' would follow the 4th _menu_ link - ** ignoring the non-menu links. ** Watch the section number: 19 -> 19.1 -> 19.1.1. * (eeok "1 ;; Info-nth-menu-item") * (eeok "1 ;; Info-nth-menu-item") * ** The keys `u', `n', `p' (up, next, and prev) move through the ** tree structure. Watch the section number: ** 19.1.1 -u-> 19.1 -u-> 19 -n-> 20 -n-> 21 -p-> 20 -p-> 19 * (eeok "u ;; Info-up") * (eeok "u ;; Info-up") * (eeok "n ;; Info-next") * (eeok "n ;; Info-next") * (eeok "p ;; Info-prev") * (eeok "p ;; Info-prev") * ** `q' leaves Info mode - more precisely, it buries the info buffer. ** `C-h i' goes back to the Info buffer (or restarts info). * (eeok "q ;; Info-exit") * (eeok "C-h i ;; info")