Matt's Blog

Everything is Lisp if you use Emacs

Sun Dec 10 08:42:07 EST 2006

A simple editor or word processor lets you type in characters on the keyboard and save them to a file so that you can access the file later. A more advanced editor allows formatting markup of the text, eg headings, lists, paragraphs, justification of text. An extremely advanced editor has an embedded scripting language to allow the user to automate common tasks. The type of tasks that can be automated depends on how powerful the scripting language is, and what interfaces there are between the editor and the outside world.

Emacs is an extremely advanced editor. The scripting language is a dialect of common Lisp, so lack of power is not a concern. The editor can be tied into external programs such as news readers, mail agents, web browsers, compilers, contract checker, ... with the scripting language. Programmers love this because it allows automation of common compilation tasks. Non-programmers tend not to use Emacs because the learning curve is a bit steep, however it does offer a number of advantages.

Consider the example of a person working for a large corporation which has a rigidly defined Code of Conduct that must be followed. A particular section of the code specifies what email signature form to use for communication between the employee and other employees, external entities, casual contacts, etc. In a moderately advanced editor a way to do this would be to have a range of separate signature files and include the appropriate one for a given communication. Various email clients have a "roles" setting to do this automatically, ie "I am writing this email as John Smith to my friend" versus "I am writing this email as Mr Smith, Customer Relations, XYZ Corp to Mr. Jones, ABC Corp,..." In emacs it is possible to write a script that keeps track of your contacts, assigns them the roles that you specify and creates the signatures automatically. It is also possible to think of a more general script that takes the code of conduct (written in a formal specification language) and generates the appropriate signature rules automatically. Think of this as treating a business model as a program that needs to be compiled to run on a machine consisting of independent processes connected by email communications channels.

The above is a sketch of the justification of learning to use an extremely advanced editor, what follows is a journal of my experiences learning emacs.

First steps - recon

Emacs has a great deal of documentation available within the editor itself, including a tutorial accessible through the command C-h t (ie hold down ctrl key, press h, release ctrl key, press t). There are also info pages available via info emacs or similar. In FreeBSD locally installed info files are in /usr/local/info, I have installed a few relevant emacs ports such as lang/emacs-lisp-intro.

  • Sidenote: using info. The info program represents documentation as a tree of nodes, similar to hyperlinked webpages.
    • Quick navigation: n, p go to next or previous node at the current level, ], [ take you to the next, previous subnode, , del (or backspace (if keymap is setup correctly)) go forward or back a page, u, d go up or down a level, h brings up the help tutorial. will also take you to the next node if pressed at the end of the current node, similarly del will do the same at the beginning of a mode. Using space, the next node is the first subnode of the current node, rather than the next node at the same level. It is therefore possible to scroll through the info documentation linearly the same as with man pages. m takes you to a menu reference (tab completion to list menu items). f follows a cross reference (as does pressing enter with the cursor on the cross-reference), l gets you back again. C-g undoes a command awaiting input eg m or f.
    • l is important! It always takes you back to the last node visited, think of it as the back button on a web browser. i takes you to the index of menu items for an info manual. d takes you to the directory node listing all installed manuals
    • searching in info: i (string) looks for string in the index of the current manual. ',' takes you to the next match. 's' searches the whole info file as a linear string (so the order may not be the same as node order)
    • advanced usage: go to the directory node, then the Info menu item. 'g' goes to a named node, can be in a separate file. 1-0 go to the first through last menu items on the current screen (0 takes you to the last menu item)
    • in emacs use M-x info (ie press esc, release, press x, type info) to get to the infoviewer.
    • typing info by itself brings you to the top level info directory containing a menu of all info nodes. Have fun browsing all the libraries that have been installed by various applications. These represent good building blocks to use in your own applications.

Second steps - RTFM

Bob Glickstein has written a book "Writing GNU Emacs Extensions" which covers writing emacs lisp code. There is also "An Introduction to Programming in Emacs Lisp" by Robert Chassell, which is available in the ports collection as described above. Some notes:

  • Basics

    • to execute an arbitrary lisp command use M-: (may need to set (put 'eval-expression 'disabled nil) in your .emacs file
    • load an emacs lisp file using M-x load-file RET fname.el RET
    • evaluate the sexp to the left of the cursor with eval-last-sexp, also bound to C-x C-e. Prefix this with C-u to put the result in the current buffer if writeable.
    • bind key sequences to commands with (global-set-key keysequence command) Represent keysequences by quoted strings (backslash escaped). M-x = "\M-x", C-x C-c = "\C-x\C-c" etc, or use \e for \M-, \^ for \C-
    • find bindings with describe-bindings, bound to C-h b. Hmmm... looks like C-x 8 is the command to prefix characters to create special chars, eg C-x 8 Y gives a yen symbol, C-x 8 " e gives an e with umlauts.
    • Pass extra arguments to a command with C-u
    • Get information on commands using M-x apropos RET cmd RET. Prefix this with C-u to get the keybindings as well.
    • M-x describe-key (C-h k) describes the keybinding of a key sequence.
  • Functions

    • M-x describe-function RET <name> RET to describe a function. Short version is C-h f. Particularly interesting is the "interactive" special form that is used to tell how user-defined functions treat parameters.
    • create functions with optional arguments using (defun f (&optional n) (...body...)) for example. Test whether the argument is nil in the function body.
    • or use (interactive "P") (... (prefix-numeric-value n)...) to tell the function to leave the prefix argument (if any) in raw form and assign it to n, then attempt to convert the argument into a numeric value.
    • Multiple argument functions? Doesn't seem possible to do this with the C-u prefix method. C-u only takes numeric arguments or minus signs, any other character just means "Repeat 4 times" (so a string of n C-u commands repeats the following command 4^n times).
    • Solution: different options to the "interactive" special form take different values from the environment. "p" interprets the prefix argument as a number. "r" takes the presently marked range. "B" asks for a buffer name. There are about 20 different options, use describe-function interactive to see more.
    • automatically indents a line of Emacs Lisp code correctly, as does M-C-\ for a region.
    • additional special form to control execution "save-excursion". This saves the current point and mark settings (see below in Point, Mark and Region). Use as the first statement in the body of a function eg (defun f () (save-excursion BODY))

    • Sidenote: The Chassell info document has a footnote about the difference between the mathematical definition of argument ('the information offered') versus the common English usage ('to assert in a manner against which others make counter assertions'). The second definition has connotations of a competition, which makes me think of evolutionary selection amongst proofs. This analogy holds reasonably well, think of a proof as occupying a niche in the logic space of mathematics, and other proofs occupying subsets or supersets of this space. Parasitism of useful proofs by other proofs, symbiosis.

  • Environment

    • The lisp functions perform actions mainly by side effects that modify environment variables.
    • buffer-name: name of the current buffer
    • buffer-file-name: path to the file linked to the current buffer
    • buffer-size: number of characters in the current buffer
    • point: the current position of the cursor in the current buffer (one indexed from start of the buffer)
      • switch-to-buffer makes the editor window go to the named buffer, compare with set-buffer which changes the focus of the lisp interpreter to the named buffer without changing the window
    • current-buffer: returns the buffer itself
    • see section 3.11 of the Chassell info file for more environment variables
  • Point, Mark and Region

    • point is the current position of the cursor in the buffer (actually, the position immediately before the character under the cursor). A mark can be set by C-<SPC>. C-x C-x then swaps the point and mark positions. C-u C-<SPC> jumps to previously saved marks.
    • The section of the buffer between the mark and the point is "the region". This can for example be passed to a function as an argument using the "r" option for interactive.
    • use the save-excursion special form to keep the cursor from moving between buffers as commands are executed.

That is a reasonable start, the next thing to do is actually code something. Start simply with some toy examples eg:

  • reverse all of the characters in a marked region
  • capitalise all of the words in a marked region
  • rotN encryption
  • extract a list of all of the unique words in a buffer and write to another file
  • insert headers or other environments depending on a programming language or library eg put in the boilerplate for using Qt.

For the moment put these on the TO-DO list. There will be some actual code soon, I promise!

[code] [ideas]


code (31)

erlang (6)
ideas (24)
lisp (1)
me (14)
notes (6)
ocaml (4)
physics (46)
qo (7)
unix (6)
vim (3)