Atlas · Details
Emergency Elisp
Author’s note
This is something you'd only read if you were serious about learning Emacs. It is almost pure technical writing, designed as a primer, with little interest beyond exactly that.
AI Notes
Emacs Lisp primer for the working programmer who needs to bolt custom behaviour onto Emacs and does not want to read a Lisp evangelism tract to do it. The conceit is in the title: a field guide you grab on the way to the patient. Most Lisp introductions, Steve notes, try to deliver the Tao of Lisp with incense and chanting; what he wanted as a beginner was a cookbook for his normal stuff, so this is that cookbook. It walks lexical tokens, comments, operators, the forms-and-atoms distinction, variables, control flow, function definitions, lambda and closures, lists and vectors, error handling — each construct gets the "here is how you would do this in C or Java; here is how you do it in Elisp" treatment. Avoids good-vs-bad arguments and just shows the moves.
The language-primer panel of Steve's 2008 Emacs triptych alongside js2-mode and XEmacs is Dead, and one of the clearest examples of his preferred teaching mode — the cookbook, not the manifesto. Still circulates as a starting point for programmers who want to write Elisp without stomaching the standard Lisp introductions.
Related listings
-
2008
js2-mode: a new JavaScript mode for Emacs
Two months later — the kind of project the Elisp primer is preparation for. js2-mode is roughly ten thousand lines of the exact constructs Emergency Elisp teaches you to read.
-
2008
XEmacs is Dead. Long Live XEmacs!
Three months later — the year's Emacs eulogy. Together with Emergency Elisp and js2-mode it forms Steve's 2008 Emacs triptych: how the language works, what to write in it, and which fork to use.
-
2008
Ejacs: a JavaScript interpreter for Emacs
The end of the same year — the runtime side of Steve's JavaScript-in-Emacs project, written in the language Emergency Elisp teaches.
From the peanut gallery
Read the rest of the thread · 44 more
-
Just what the doctor ordered, and far more useful than the FSF book. Thanks!
-
Brilliant ! Look forward to studying it in detail. Thank you. I'd love to see you go through an existing elisp package and show how it works ... M-x occur, for example.
-
(quote 1 2 3)
doesn't work; you meant
(quote (1 2 3)) -
Just what I needed as I attempt to walk down the Emacs path once again. Thanks a lot!
-
Wow! I've been customizing emacs for 2 years and hadn't heard about: hex and binary notation, try/catch, catch/throw, do/while, case, defstruct and makunbound!
-
#xdeadbeef => -22167825
when you only have 29 bits... -
Now if elisp would just get decent file stream support! Everything-is-a-buffer isn't nearly so elegant and useful as everything-is-a-byte-stream. Or maybe I've just been using Unix too long and it has poisoned my soul.
-
Ben: FSF book will seem more useful after you absorb this, I think.
Mitchell: we have to live with (and work with) what we've got.
Offby1: thanks, fixed.
Hugo: no kidding. There's a lot under the covers.
Jonas: thanks, changed to #xdeadbee :-) -
Lisp is great fun once you get into it.
There's an open source JVM based Lisp called Clojure, with an emphasis on functional programming, but also STM and great concurrency support from the JVM.
Check it out at clojure.sourceforge.net
I honestly haven't had as much fun programming since BBC-Basic when I was a nipper. ;-) -
The programming tips are fine, but how about a follow-up article on things like creating new editing modes, adding menus, making hot-keys do useful things, etc. In other words driving Emacs to do useful stuff.
-
... writing a javascript byte-compiler, etc. (js2? no name yet i guess)
But if you are going to talk more about elisp, don't forget to mention how you can easily tweak other people code with hooks and advices.
And btw, why are you reading the comments? -
And I quote -
(if (today-is-friday)
(message "yay, friday")
(message "not friday!")
(non-friday-stuff)
(more-non-friday-stuff)
Someone forgot a paren. Not using emacs to edit this post I see :p -
Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you!
I've been using emacs for 12+ years and must admit lisp has always been intimidating to me. This post really clears up the basic syntax. -
Quite handy. Thanks, Steve.
-
Thanks for the post! I was just reading the official emacs Lisp manual (http://www.gnu.org/software/emacs/manual/html_mono/elisp.html) but this is much more practical and concise.
-
Thank you for this post. It's a useful summary and reminder.
About dynamic scope, you should at least mention its good for mocking and overriding.
> (require 'cl)
Yes! Too bad ""(require 'cl) considered harmful" considered harmful" is down. :-)
I suspect you are trying to build the crowd to the point when you switch over to your JavaScript emitter to elisp bytecode. "Now this is how you do it right." :) -
Excellent elisp reference for beginners. Thanks!
You missed a closing code tag near: "(let var-decl var-decl".
I think the most popular topic is how to build a major mode for emacs, or to fix/contribute to an existing mode. There are some useful resources on this topic, but I believe you can present it much better. -
Steve, I love your posts - they always brighten my day. I would love to see more emergency elisp! Other than the built in manuals, is there a resource that you have found particularly helpful?
btw (incf 13 6) won't work - it has to be something like (let ((x 13)) (incf x 6)) just in case you get around to creating a book out of this (hint hint) -
Great article. Just wanted to let you know that the second half of the article is hard to read from IE but looks fine in FireFox. Near the top of your section on local variables, there's an opening code tag in the HTML that isn't closed. As a result, the bottom half of the article is in green Courier font under IE.
-
+1 on what David Plumpton said.
This was a nice intro to lisp, but I have done a bit of lisp in the past.
What would be useful for me is an intro to the emacs specific stuff, such as commonly used functions used on regions, "save-excursion", option to (interactive), what emacs modes do (from a code point of view).
What are the elisp constructs you find in your own code most often? -
Nice! I've been using Emacs for 15 years and have read the O'Reilly Emacs Extensions book, but at least half of this was new to me. I'd love to see more elisp tutorials!
BTW, The missed closing code tag after the let example also breaks (half of) the article in Konqueror. -
following on from John a few posts above: the missing code tag also breaks the rendering in Opera, "the standards compliant browser"
;)
mind you the mono-spaced font is a nice change from the usual -
Thanks for all the corrections - I've incorporated them into the post, plus a few that nobody caught.
-
Keep going. Very very helpful.
And change the blog_check to something like 10000 instead of 5000.
Whenever I finish reading your essays , I feel like I need to read more. -
+1 on what John said, I get green mono spaced font in Safari too.
Otherwise excellent post. Thank You. -
Hi Steve,
Nice tutorial.
I have also wrote one similar:
http://xahlee.org/emacs/elisp_basics.html
There are few differences than yours. Here's the major ones:
• i wouldn't go into octal, hex, binary literal notations. In my 20 years of computing in various lang, i don't think i've used them once. (my area is web app dev, unix sys admin, geometry programing; using mostly high level or scripting langs)
• Your mention of bit operator “<<” seems especially odd to me.
In your example:
“To compute the arithmetic expression (0x15 * (8.2 + (7 << 3))) % 2:
(% (* #x15 (+ 8.2 (lsh 7 3))) 2)”
I scratched my head. I had to look up what is “<<” or “lsh”. Again, personally, i've never needed to tweak bits.
• i wouldn't tell my readers to use the “*scratch*” buffer, because i consider it quaint and a obsticle to spreading emacs. Anyway, the C-j in scratch buffer is new to me. I would just tell reader to open a new file and do “Alt+x emacs-lisp-mode”.
• the use of comma here is new to me:
“`(1 ,(+ 1 1) 3)”
However, in that sentence, you said “.. via a template system called "backq”
Just realized that in Opera, much of your code is cut off and invisible.
Only when pasted, i see the word “backquote”. But in Opera browser, i see just “"back” with no indication whatsoever that it has been cut off or needs to scroll. Now i realized other parts of your lisp code also got cut. This is latest Opera on OSX 10.4.11.
• The equality treatment is a bit complex too for a primer. I'd just mention “equal” and “eq”.
• The “apropos” is new to me! (i use emacs daily since 1998) I've already used “C-h a” (apropos-command) or “C-u C-h a”. But i think “apropos” is more versatile since it searching lisp symbols (as opposed to just functions, commands, or variables). Did you mention “C-h f” (describe-function) somewhere? Also i think “Alt+x elisp-index-search” is very useful to me.
• for a simple primer, why mention the so many variation of switch and cond? Just if, if else, cond, will be good for 99% of coding needs i'm sure. The minor variations are fluffy.
• for a simple primer, why load the controversial cl? and cover all the loop forms? To me, “while” and “mapcar” basically does cover 99% needs. If not, then there's “dolist”, “dotimes”, all are cannonical elisp.
• Thanks for covering break/continue. I haven't used it before. It is good learning for me personally.
• you wrote:
«You can use the full Common Lisp specification for argument lists, including support for keyword arguments (see the defstruct section below), if you use the defun* macro instead of defun. The defun* version also lets you (return "foo") without having to set up your own catch/throw.»
I didn't understand this paragraph. (am not familiar with CL) Egads, why are you keep mentioning Common Lisp's concepts in this _introductory_ tutorial? I think emacs lisp is novel enough to keep lisp newbies busy.
When i learn a new system, i tend to want to only learn the pure form, without any add on or modifications. Once i'm well familiar with the raw form, then i study the add ons and variations etc.
• Your section on “reference parameters” is confusing to me. For someone who does not have compiler knowledge, any mentioning of “stack” is confusing. I understand full well of dynamic scope, as well much advanced mathematics in logic. I don't understand what behavior in that section you are trying to say, other than giving a example of dynamic scope of elisp.
What computational effect/behavior is it trying to illustrate? What concrete problem is this “reference parameter” or “modify caller's stack” is supposed to solve? I'd frame this section in these respects. (as opposed to, using the term stack, call-back, reference... which i honestly can't interpret sensibly.)
• in elisp, when would i want to use a class such as defstruct? (as opposed to the built-in alist or hash table)
Personally, i never find OOP paradigm useful, so this is a geniun question.
• treating buffers in a primer is probably complex. Especially treating it as a data structure of “class”, with quite a lot complexities of the local var.
I'd include some real useful examples of little elisp functions you actually use to help you code or use emacs.
(my version is here: http://xahlee.org/emacs/elisp_examples.html ), or start a introduction that covers on how to actually do text processing in emacs, covering functions and concepts such as point, region-max, region-beginning, goto-char, search-forward, delete-char, insert ...
(my version here: http://xahlee.org/emacs/elisp_editing_basics.html )
All the above is just personal rambling. Mostly written just for my own pleasure. :D
Xah
[email protected]
∑ http://xahlee.org/
☄ -
Great elisp summary. Next one about pymacs ?
-
Are elisp macros broken, or did you think an introduction to macros would be out of place here? If the second, please consider a follow-up post focused on macros.
-
Chris: elisp macros are fine, and he did mention the backquote operator (usually used to build macros). It is a rather complicated topic, though, so it makes sense to omit it. M-: (info "elisp") and enjoy learning the rest.
-
There's a with-slots for structs in SLIME's slime.el:
(defmacro* with-struct ((conc-name &rest slots) struct &body body)
"Like with-slots but works only for structs.
\(fn (CONC-NAME &rest SLOTS) STRUCT &body BODY)" ... ) -
I wouldn't normally ask, but if you're looking for things beginners find hard:
I'm writing a major mode for some language and keep fiddling around with the font-lock settings. I want to "unload" the current definition of my mode, hack the regexps, load the new definition and re-fontify a buffer full of the language I'm trying to write the mode for. I've tried using load-library, unload-feature, and font-lock-fontify-buffer, making sure to switch into fundamental mode before I unload-feature, but no joy - the font-lock defs don't seem to change till I restart emacs.
Great tutorial BTW - and I'm off to read up about CL loops now. -
I would also appreciate more emacs related stuff (For example,I often have different file formats that I would love to know how to make a quick mode for font-locking them.) This post is definitely a bookmark though!
-
Steve,
Thanks for this post - I feverishly devour all of your emacs/LISP/eLISP posts as I strive to increase my productivity with emacs.
I only wish LISP enjoyed wider adoption as a programming language. -
A really helpful starting point, thanks.
Now I just need to know whic emacs-lisp function will tell me that the code I'm writing is totally duplicating something that it does already but I didn't know about. -
I'm probably the 37th person to try to give you this link today:
http://xkcd.com/378/
Funny web comic addresses Emacs. -
Cheers this was a handy post. I think macros would be a good topic if you do another one.
-
One thing that people may like is M-x ielm, it's a REPL for elisp. lisp-interaction-mode does the same thing, but ielm feels more like the perl/python/ruby REPLs that everyone is probably used to.
-
Somewhere in one of your excellent blogs I recall something about the annoyance of how the escaping of paren's and or's in Emacs Lisp work backwards from other programming languages. Below is some code I've been using for a little while to reverse this. It seems to work well enough for my purposes.
There's a little duplication in this code, but I haven't decided to take the plunge and go to the next step which would be to change the inner function of query-replace-regexp and friends and and this to perform-string. After this code is a little unit test I use to check things.
P.S. Sorry about the funny formatting. I can't figure out how to tag this as program code or verbatim, monospace text.
;; Call this file say rubyre.el
(defun gsub (search-string replace string &optional regexp-flag)
"Like Ruby gsub."
(with-temp-buffer
(insert string)
(goto-char (point-min))
(let ((search-function (if regexp-flag 're-search-forward 'search-forward)))
(while (funcall search-function search-string nil t)
(replace-match replace))
(buffer-string))))
(defun re-flip (search-string string)
"Flip backslashed character and nonbackslashed version. E.g \(ab\)-> (ab)
while (a|b) -> (ab) -> \(ab\)"
(with-temp-buffer
(let ((pair-string (concat "\\(.\\)\\(" search-string "\\)")))
(insert (concat "X" string)) ;; to allow matching the initial character
(goto-char (point-min))
(while (re-search-forward pair-string nil t)
(if (string= "\\" (match-string 1))
(replace-match (match-string 2))
(replace-match (concat (match-string 1) "\\\\" (match-string 2)))))
(substring (buffer-string) 1))))
(defun ruby2elisp (regexp)
"Convert a Ruby style regexp to an elisp regexp."
(setq regexp (gsub "\\\\d" "[0-9]" regexp t))
(setq regexp (gsub "\\\\D" "[^0-9]" regexp t))
(setq regexp (gsub "\\\\s" "[ \n\t]" regexp t))
(setq regexp (gsub "\\\\S" "[^ \n\t]" regexp t))
(setq regexp (re-flip "[(){}|]" regexp)))
(defun rreplace-regexp (regexp to-string &optional delimited start end)
(interactive
(let ((common
(query-replace-read-args
(if (and transient-mark-mode mark-active)
"Replace regexp in region"
"Replace regexp")
t)))
(list (nth 0 common) (nth 1 common) (nth 2 common)
(if (and transient-mark-mode mark-active)
(region-beginning))
(if (and transient-mark-mode mark-active)
(region-end)))))
(perform-replace (ruby2elisp regexp) to-string nil t delimited nil nil
start end))
(defun rre-search-forward (regexp &optional bound noerror count)
(interactive "sRuby RE search: ")
(re-search-forward (ruby2elisp regexp) bound noerror count))
(defun rre-search-backward (regexp &optional bound noerror count)
(interactive "sRuby RE search: ")
(re-search-backward (ruby2elisp regexp) bound noerror count))
;;; New file
;; -*- emacs-lisp -*-
;; This program has to be run from the directory it is currently in and
;; the rdebug code has to be in the parent directory
(load-file "./elk-test.el")
(load-file "./rubyre.el")
(deftest "gsub-test"
(assert-equal "BBBCD" (gsub "A" "B" "ABACD"))
(assert-equal "BBD" (gsub "A." "B" "ABACD" t))
(assert-equal "FFFCD" (gsub "[AB]" "F" "ABACD" t))
(assert-equal "ABAFF" (gsub "[^AB]" "F" "ABACD" t))
(assert-equal "A\\|B" (gsub "\\([^\\]\\)|" "\\1\\\\|" "A|B" t)))
(deftest "flip-test"
(assert-equal "\\(ab)" (re-flip "(" "(ab)"))
(assert-equal "(ab\\)" (re-flip ")" "(ab)"))
(assert-equal "\\(ab)" (re-flip "(" "\(ab)"))
(assert-equal "(ab\\)" (re-flip ")" "(ab\)"))
(assert-equal "\\(ab\\)" (re-flip "[(){}]" "(ab)")))
(assert-equal "(ab)" (re-flip "[(){}]" "\\(ab\\)"))
;; -------------------------------------------------------------------
;; Build and run the test suite.
;;
(build-suite "rubyre-suite" "gsub-test" "flip-test")
(run-elk-test "rubyre-suite"
"test things in rubyre.el") -
Steve,
What emacs mode/tools do you use for editing html and managing this blog? -
This is incredibly useful. Thank you very much!
-
After a year+ of Emacs, I'm still very much an elisp beginner. I've referred to this page several times.
Keep up the emacs work (wether it's ECMA- or EMACs- -script! -
> The defun* version also lets you (return "foo") without having to set up your own catch/throw.»
I think what you really want to say here is the function body of defun* is implicitly surrounded by (block function-name ...).
In fact, you can not (return "foo"), but can (return-from function-name "foo"). -
This is VERY useful. Thank you so much!
-
Great post man, just got heavily into emacs and this helped fill in a number of blanks for me.
single-line comments only?!
#|
Lisp
has
read
macros
Steve!
|#
— Liron Greenstein · 8:00 PM, January 25, 2008
#|
Liron
Can't
Fugging
Read
|#
This article was about Emacs Lisp, which does not have read macros (although I wish it did.)
Thanks for playing.
— Steve Yegge · 11:30 PM, January 25, 2008
With regard to defvar, you don't have to makunbound to re-evaluate them, you can use C-M-x (which maps to eval-defun).
Tombo: This applies to your problem with font-locking (probably). You need to C-M-x your defvar'd font-lock variables after you change the regexps. Since they are buffer-local, you will need to close the file and then reopen it to see the results, but you certainly don't need to restart Emacs.
— Scott Frazer · 5:43 AM, January 28, 2008
So are you refuting your own "Lisp is not an acceptable Lisp" argument here by trying to steer new people into getting some of it on themselves?
— Mitchell · 3:06 PM, January 24, 2008