(Re)generate: (find-eval-intro) Source code: (find-eev "eev-intro.el" "find-eval-intro") More intros: (find-eev-quick-intro) (find-eepitch-intro) (find-eev-intro) This buffer is _temporary_ and _editable_. It is meant as both a tutorial and a sandbox. Note: this intro needs to be rewritten! Ideally it should _complement_ the material in: (find-eev-quick-intro "2. Evaluating Lisp")
1. The standard way to evaluate Lisp: `C-x C-e'The most important idea in Emacs is that Lisp code can appear anywhere, and you can evaluate a Lisp expression (a "sexp") by placing the cursor (the "point") just after it and typing `C-x C-e'; the result is then displayed in the echo area. Try it in the line below, with the point in the three different indicated positions - you should get different results. (+ (* 2 3) (* 4 5)) ^ ^^ | | \ 6 20 26
2. The end of line and `M-e'A common operation is to move the point to the end of the current line, then run `C-x C-e'. That can be done with `C-e C-x C-e', but eev-mode implements a shorthand for it: `M-e'. Try it here: (+ (* 2 3) (* 4 5) ) `M-e' accepts several different numeric prefixes that alter its behavior. We are only interested in one of them now - `M-0 M-e' highlights the sexp for a fraction of a second insted of executing it. Try it above. In some rare occasions we might want to run something like `M-e' but without moving to the end of the line first. Eev-mode implements a key binding for that: `M-E' (meta-shift-e). As an exercise, try to use `M-0 M-E' at several positions below, to hightlight the subsexps `(* 2 3)', `(* 4 5)', and `4'. (+ (* 2 3) (* 4 5))
3. What to execute, and in what orderNote that the order of evaluation may be important: (setq a 5) (setq a 6) (* a a) By executing `(setq a 5)' and then `(* a a)' above we get 25, by executing `(setq a 6)' and then `(* a a)' we get 36 - the current value of `a' is the one of the last `setq' executed. An exercise: edit the three sexps above to introduce a `(setq a 22)', then use that sexp and the `(* a a)' to calculate the square of 22. Another exercise: just as `setq' sets variables and can override their previous values, `defun' defines, and redefines, functions. Execute the sexps below in different orders to obtain the results 25, 36, 50, and 60. (setq a 5) (setq a 6) (defun f (x) (* x x)) (defun f (x) (* x 10)) (f a) MORAL: Elisp code can appear anywhere in any Emacs buffer, but it is _passive by default_. It only gets executed if we move the point to the right positions and type `C-x C-e', `M-e', or similar keys. Sexps can be executed any number of times, in any order, and can be edited and modified.
4. Elisp hyperlinksSome Emacs functions can be used as hyperlinks. When sexps like (find-file "/tmp/") (info "(emacs)Lisp Eval") (describe-function 'find-file) (find-function 'find-file) (man "cat") are executed they "open a new page" - actually, they create a new buffer, or reuse it if it already exists - and it is usually possible to "go back" by killing the new buffer. However for some functions, like `man', which by default open a manpage in another window, "going back" would mean something different. Eev defines several functions to let us use sexps as hyperlinks. The main conventions on these functions are: 1) their names start with "find-", 2) calls to them can be "refined" with a pos-spec (this will be discussed below), 3) they open the new buffer in the current window (to make it easier to "go back" after following them - see the next section), 4) they don't display much output in the echo area, 5) when they create temporary buffers with lots of sexps then: a) the first sexp in that buffer is one that can regenerate that buffer when executed, b) all the sexps are prefixed with the string stored in the variable `ee-hyperlink-prefix', to let these sexps be pasted into scripts as comments (see below). Note that sometimes the most obvious name for a hyperlink function starting with `find-' is already taken by Emacs - for example, `find-file' and `find-function'. In those cases eev use other names: `find-fline', `find-efunction', etc. Here are the eev versions of the links above: (find-fline "/tmp/") (find-node "(emacs)Lisp Eval") (find-efunctiondescr 'find-file) (find-efunction 'find-file) (find-man "cat")
5. Going backWeb browsers let you follow a hyperlink and then "go back". There are different ways of going back - if you opened the new page on a new window or tab, then going back means deleting the new window or tab (or just switching to the old window/tab); if you opened the new page on the same window/tab, then you need to use the "back" button. Eev-mode defines two keys for "going back": `M-k', that kills the current buffer, and `M-K', that just hides it ("buries" it in the bottom of the list of all buffers). Try following the link below by <M-e>, then deleting its buffer with `M-k' to go back: (find-node "(emacs)Shell") In some cases we know that we may want to go "forward" again after going back, and we may not want to delete the target buffer - for example, because it would take a while to rebuild it again, or because we would lose the position of the point there. Most hyperlink functions in eev are able to reuse a buffer that "looks like" the desired target buffer; the test for lookalikeness is based on the name of the buffer only. Try to follow the links below with `M-e', then come back to this buffer with `M-k', then follow them again. Then try the same thing with `M-K' instead of `M-k', to see the difference - in the `find-sh' example below the "sleep" takes one second to run, so revisiting the existing output buffer after a `M-K' is much quicker than recreating it anew. (find-man "1 bash") (find-sh "sleep 1; echo 'This was run at:'; date")
6. Refining hyperlinksMost hyperlinks functions defined by eev can be "refined" by the addition of extra arguments. These extra arguments are called a "pos-spec" (or a "pos-spec-list") and they specify a position in the target buffer. The first argument means a certain line number, when it is a number, or the first occurrence of a certain string, when it is a string. Try: (find-node "(emacs)Command Index") (find-node "(emacs)Command Index" "eval-last-sexp") Further arguments mean either "move down n lines" or "search for the next occurrence of a string", depending on whether they are numbers or strings. Try: (find-sh "seq 2095 2115") (find-sh "seq 2095 2115" "2100") (find-sh "seq 2095 2115" "2100" "9") (find-sh "seq 2095 2115" "2100" 2)
7. Pos-spec-listsThe optional arguments that refine a hyperlink form what we call a "pos-spec-list". For example, the pos-spec-list here has two elements, (find-sh "seq 2095 2115" "2100" "9") and in most cases an empty pos-spec-list, like this, (find-sh "seq 2095 2115") means: "if the target buffer already exists then just open it" - so that following that hyperlink would jump to the current position of the point in that buffer. Pos-spec-lists are usually interpreted by the function `ee-goto-position'. The first argument is interpreted in a special way, according to its type: string -> jump to the first occurrence of that string in the buffer number -> jump to the n-th line and the other arguments are interpreted (recursively) by `ee-goto-rest': string -> jump to the next occurence of that string number -> move down n lines list -> evaluate the list If you want to add support for more complex pos-spec-lists, just replace `ee-goto-rest' with your own extended version.
8. Anchors and pages[See:] (find-anchors-intro) Some hyperlink functions, like `find-efunction' and `find-evariable', jump to specific positions in buffers - the beginning of the definition of a function or a variable in the source code - even when their pos-spec-lists are empty, so they process all their extra arguments with just `ee-goto-rest'. Other hyperlink functions transform the first argument of a pos-spec-list in a special way it if is a string - for example, in `find-available', which is based on `find-Package', (find-available "bash") (find-available "bash" "bash-doc") the argument "bash" is converted to "\nPackage: bash\n", and the two hyperlinks above jump to the description of the package "bash" in the list of the available packages in a Debian system. The functions based on `find-anchor' transform an initial string argument in the pos-spec-list by running `ee-format-as-anchor' on it [TODO: document this], and the ones based on `ee-goto-position-page' jump to the n-th "page" of a buffer if the first argument of the pos-spec-list is a number, n; for exemple, if n is 234 that will jump to the 233-th formfeed (233 and not 234 because the page 1 is before the first formfeed). For more on "pages", see: (find-pdf-like-intro "PDF-like documents as text")
9. Producing and refining hyperlinksIf you are on an Info page, typing `M-h M-i' will create a temporary buffer containing a header - which we will discuss later - and several (possibly equivalent) links to that info page. Something like this: ________________________________________________________ |;; (find-einfo-links) | | | |;; (info "(emacs)Misc Buffer") | |;; (find-node "(emacs)Misc Buffer") | |;; (find-enode "Misc Buffer") | | | | | |--:**- *Elisp hyperlinks* All L1 (Fundamental)---| |________________________________________________________| These links are meant to be cut & pasted - possibly after refining them to make them more precise. Let's look first at the two key sequences that make refining much easier. Remember that `M-w' (`kill-ring-save') is roughly correspondent to what is called "copy" is most modern interfaces, and `C-y' (`yank') is roughly correspondent to "paste". Both `M-w' and `C-y' operate on Emacs's "kill ring", and to make our examples trivial to follow we will first put a string on the kill ring: (kill-new "C-y") (car kill-ring) Now let's see how to refine hyperlinks quickly. `M-h M-2' duplicates the current line; we will use that to refine a copy of a working hyperlink, instead of working directly on the original, and risking breaking it. And `M-h M-y' refines the hyperlink on the current line by adding a string - the top element in the kill ring - to its sexp. Try this below; you should be able to convert (find-enode "Kill Ring") (find-enode "Yanking") into (find-enode "Kill Ring") (find-enode "Kill Ring" "C-y") (find-enode "Yanking") (find-enode "Yanking" "C-y") with few keystrokes, as you can leave the Meta key pressed. The full key sequence for duplicating and refining is `M-h M-2 M-h M-y', but we can think of it as `M-h2hy'. Now try a more serious exercise: follow the `(find-enode ...)' hyperlink below, copy a word or two from its contents to the kill ring with `M-w', then generate the temporary buffer with hyperlinks to that Info page with `M-h M-i', then duplicate one of its hyperlinks with `M-h M-2', refine it with `M-h M-y', and copy the result to this sandbox with `M-w' (or `C-w') and `C-y'. As this is a long sequence of instructions, it is better to run `C-x 1 C-x 2' or `C-x 1 C-x 3' before following the hyperlink, to keep the instructions visible. (find-enode "Command Index")
10. More on functionsA symbol - for example `f' - can be both a varible and a function; its "value as a variable" and its "value as a function" are stored in different places. Try: (setq f 2) (setq f 5) (defun f (x) (* x x)) (defun f (x) (* 10 x)) (symbol-value 'f) (symbol-function 'f) This is explained here: (find-elnode "Symbol Components") (find-elnode "Symbol Components" "value cell") (find-elnode "Symbol Components" "function cell") The content of a "function cell" is _usually_ a lambda expression. See: (find-elnode "Lambda Expressions") (find-elnode "What Is a Function") (find-elnode "What Is a Function" "lambda expression") (find-elnode "What Is a Function" "byte-code function") Try: (setq f 2) (setq f 5) (set 'f 2) (set 'f 5) (fset 'f (lambda (x) (* x x))) (fset 'f (lambda (x) (* 10 x))) (defun f (x) (* 10 x)) (defun f (x) (* x x)) (symbol-value 'f) (symbol-function 'f) (f 4) (f f) ((lambda (x) (* x x)) 4) ((lambda (x) (* 10 x)) 4)
10.1. Byte-compiled functionsMost functions in Emacs are byte-compiled - which means that their function cells contain a "byte-code" instead of a lambda expression. These byte-codes are very hard for humans to read. See: (find-elnode "What Is a Function" "byte-code function") (find-elnode "Byte-Code Type") (find-elnode "Byte Compilation") (find-elnode "Disassembly") Here is an example: (find-efunctiondescr 'find-file) (find-efunction 'find-file) (symbol-function 'find-file) (find-efunctionpp 'find-file) (find-efunctiond 'find-file) The `find-efunctionpp' link above takes the content of the function cell of `find-file' and "pretty-prints" it, i.e., indents it in a nice way, but the result in this case is unreadable... and the `find-efunctiond' link shows a decompiled version of that byte-code, which is only slightly better. Both the `find-efunctionpp' and the `find-efunctiond' links show internal representations that are very different from the source code. Compare that with a case in which the function is not byte-compiled: (find-efunctiondescr 'find-fline) (find-efunction 'find-fline) (symbol-function 'find-fline) (find-efunctionpp 'find-fline) The `(find-efunctionpp 'find-fline)' shows a lambda expression that is very similar to the defun that defined `find-fline'.
10.2. How `find-efunction' worksEev defines hyperlink functions called `find-efunction', `find-evariable' and `find-eface' that are wrappers around the standard functions `find-function', `find-variable' and `find-face-definition'; the eev variants support pos-spec-lists. Try: (find-efunction 'find-fline) (find-function 'find-fline) (find-evariable 'ee-hyperlink-prefix) (find-variable 'ee-hyperlink-prefix) (find-eface 'eepitch-star-face) (find-face-definition 'eepitch-star-face) The Emacs functions are defined here: (find-efile "emacs-lisp/find-func.el") Their inner workings are quite complex. They use `symbol-file', that works on the variable `load-history'. Here are some links to documentation and tests: (find-efunctiondescr 'symbol-file) (find-elnode "Where Defined") (symbol-file 'find-fline 'defun) (symbol-file 'ee-hyperlink-prefix 'defvar) (symbol-file 'eepitch-star-face 'defface) (find-epp (assoc (locate-library "eepitch") load-history)) The functions in "find-func.el" use `symbol-file' to find the file where a given symbol was defined, and then search a defun, defvar of defface in it that _may be_ the definition that we are looking for. The eev variants use the functions `find-function-noselect', `find-variable-noselect' and `find-definition-noselect' from "find-func.el", that return a pair (BUFFER . POS). Try: (find-efunctiondescr 'find-function-noselect) (find-efunctiondescr 'find-variable-noselect) (find-efunctiondescr 'find-definition-noselect) (find-ebufferandpos (find-function-noselect 'find-fline) ) (find-ebufferandpos (find-variable-noselect 'ee-hyperlink-prefix) ) (find-ebufferandpos (find-definition-noselect 'eepitch-star-face 'defface) ) These `find-*-select' functions work quite well but are not 100% reliable - for example, if an elisp file has several definitions for the same function, variable, or face, the `find-*-select's don't know which ones were executed, neither which one was executed last, overriding the other ones... and it may return the position of a defun, defvar, or defface that is not the "active" one.
10.3. Why eev avoids byte-compilationAll the source files of eev have a "no-byte-compile: t" in them. See: (find-eevgrep "grep --color -nH -e no-byte-compile: *.el") (find-elnode "Byte Compilation" "no-byte-compile: t") This is non-standard, but it is a deliberate design choice. (TODO: explain the three main reasons: it is easier to teach emacs to beginners if they see lots of lambda expressions and few byte-codes; `code-c-d' and friends define functions dynamically and `find-efunction' don't work on them; in a distribution with only the ".elc"s of eev users wouldn't have access to the documentation and examples in the comments of the source files.)
10.4. Quote and backquoteEev uses backquote a lot and avoids macros. (find-elnode "Backquote") (find-elnode "Macros")
11. What else?Eev-mode defines several other key sequences similar to `M-h M-i'. You can get the full list here: (find-efunctiondescr 'eev-mode) (find-efunctiondescr 'eev-mode "M-h f") Try also this: (find-efunction-links 'eev-mode) and for other tutorials like this one, try: (find-wrap-intro) (find-eepitch-intro) [To do: explain M-x ee-hyperlink prefix and how to embed hyperlinks in scripts]