Emacs Lisp

Table of Contents

Dialect of Lisp used specifically to configure, extend, and program the GNU Emacs text editor

They are byte complied into .elc file, and native compiled into .eln file.

"TAB" is ^I and "<tab>" is tab key.

1. Syntax

Symbol Symbol is an object that represent a variable or function. quote or ' wraps the variable as a symbol. It consists of four parts: name, value, function value, property list. They can be accessed with symbol-name, symbol-value, symbol-function, symbol-plist respectively.

  • fset sets the function value of the variable. It can be set to a raw function or a symbol as a indirection.
  • Keywords, of the form :keyword, are special symbols whose symbol-value is itself.

Dynamically bound functions expands the scope when it is not bound locally, but lexically bound variable does not.

  • defvar makes the variable dynamically bound.
  • Lexical binding is preferred these days.
  • boundp checks if a symbol is bound to a value or void.
  • setf is like setq but operates on any cell and variables.
  • (let ((var val), ...) (statement)) it binds local variable, dynamically on dynamic variable, lexically on free variable.
    • let* defines them sequencially
  • (setq var val var val ...)
    • The variable is bound to the value.
    • The q is for quoted, which means the var does not need to be quoted
  • (defvar var val "optional documentation")
    • It marks the variable as special, so that it is always dynamically bound.
    • The variable is not overrode, and setq can change the value, it is seen globally
    • It allows doc string.
  • There are various types of primitive data, printed as #<buffer>, #<marker>, #<frame>.
  • value can be a closure and it can be called with funcall
  • #' can be used to explicitly tell it to use the function value.
  • #1= and #1# can be used to create a reference and refer back to it.

List The basic unit of a list is cons cell.

  • It consists of two parts car and cdr, that can contain value or reference. CAR and CDR - Wikipedia
  • cons or . form a cons cell out of two values.
  • list is a series of cons cell that reference the next cons cell and ends in nil

A list is a series of cons cells called nodes (CAR CDR) -> (CAR CDR) -> ..., with data in CAR and pointer to the next node in CDR. CDR also be used to store value instead of the pointer to the next node via (cons VAR1 VAR2), or equivalently (VAR1 . VAR2).

The Lisp reader (parser) reads the list and evaluate it if it is not quoted with (quote LIST) or equivalently 'LIST. The the function slot in the first element in the list is evaluated with the variable slot in the remaining elements as arguments.

  • `(... ,a ...) backquote can be used to evaluate only certain part of expression.
  • `(... ,@a ...) can be used instead, to unwrap the result of a.

There are named form of list: alist and plist. Alist, short for association list, is a list of cons cells that associate or map car to cdr:

(setq alist '((apple . 10) (banana . 5) (peach . 17)))

Plist, short for property list, is a list of alternating keywords and values:

(setq plist '(:name "Bob" :age 29 :smart t))

Array String "abc" , Vector [a b c] are array, which is a special type of list.

Function

(defun funcname (arguments)
  "optional documentation"
  (interactive "optional-argument-passing-info")
  (body))

Function that is defined interactively with (interactive OPTION) is a command, which can be bound

(require 'cl-lib) ;; Common Lisp library
(cl-defun funcname (a &key (b "Default B") (c 42))
  "A function with keyword arguments."
  (message "A is %s, B is %s, C is %s" a b c))

(funcname "Hello" :c 99)
A is Hello, B is Default B, C is 99

Package (provide 'PACKAGE) specified in the end of the package file. Later (require 'PACKAGE) is used to retrieve it.

Mode Simple mode defined as follow can be activated by M-x generic-mode

(define-generic-mode 'phits-mode
  '("#")         ;; comment character
  '("icntl")     ;; keywords
  '(("^\\[.*\\]" . 'font-lock-constant-face)) ;; font lock regex
  '("\\.inp\\'") ;; file extenstion
  nil            ;; list of functions to run
  "Genetic mode for phits input file")

(define-minor-mode MODE :init-value nil :lighter INDICATOR :global nil BODY) (defcustom var val "documentation" :type TYPE) it specify a variable that customize can control

2. Functions

2.1. Interactive Function

  • These are precisely the commands

Command is defined with (interactive OPTIONS) within the function defition.

The option can be nil, string, or lisp code. String option includes a sequence of code character and prompt string pairs separated by \n, with each user response assigned to the arguments of the function in order.

  • n number
  • s any string
    • the input is terminated by C-j or RET
  • c character
  • f filename
    • F file does not need to exist
  • b buffer name
    • B buffer does not need to exist
  • D directory
  • r region
    • take the start and end point of the region as the two argument.

The full list can be found here.

2.2. Build-in Functions

If the name ends in p, it is a predicate. If it ends in q, some of the arguments are quoted by default.

List

  • (setcar CELL NEWCAR), (setcdr CELL NEWCDR) modify the cons cell
  • (assoc KEY ALIST &optional TESTFN) return the key-value pair matching KEY within a alist as a reference.
  • (alist-get KEY ALIST &optional DEFAULT REMOVE TESTFN) similar to assoc, but create if there is no matching key.
  • (append LIST1 LIST2) produces the new concatenated list
  • Sequence Functions (GNU Emacs Lisp Reference Manual)
  • (copy-sequence LIST) copy the outer most sequence
    • (copy-alist LIST), (copy-tree LIST) are also available for deep copy.

String

  • (concat STR1 STR2) concatenate into one string
  • (format FORMAT_STR VAR)
  • (substring STR START_INDEX [END_INDEX]) zero-based end-excluded substring.

Point

  • (point) return current point position
  • (goto-char NUM) move point to the position NUM
  • (forward-char &optional NUM), (backward-char &optional NUM) move point
  • (beginning-of-buffer), (end-of-buffer) move point
  • Common motion command, such as (forward-word), (forward-sentence) are also available.
  • (point-min), (point-max) return possible point position while taking narrowing into account
  • (save-excursion ...) save the point position, and allow point motions to be contained within the scope

Buffer

  • Get/Set Buffer
    • (current-buffer) get the buffer object currented being edited #<buffer>
    • (get-buffer BUFFER-OR-NAME) get buffer by name
    • (get-file-buffer FILENAME) get buffer by file path
    • (get-buffer-create BUFFER-OR-NAME) get buffer while creating it when it does not exists.
    • (set-buffer BUFFER-OR-NAME) set current (editing) buffer to BUFFER
    • (with-current-buffer BUF ...) set the current buffer within the scope
    • (with-temp-buffer "CONTENT" ...) create a temporary buffer with given content
  • Buffer File
    • (buffer-file-name) the file path of the current buffer. It is nil if not applicable.
    • (find-file-noselect FILENAME) => BUF open a file into a buffer without displaying it
    • (save-buffer) save to buffer file
  • Buffer Text
    • (char-after NUM) return the character at the position
    • (thing-at-point THING &optional NO-PROPERTIES) the THING can be 'word, 'sentence, 'url and others
    • (search-forward STRING &optional BOUND NOERROR COUNT), (search-backward STRING) move the point after/before the (first) match
    • (buffer-substring START END) return string at the given range within current buffer
      • (buffer-substring-no-properties START END)
    • (insert STR) insert at point
    • (insert-file-contents-literally PATH)
    • (delete-region START END) delete the text within
  • Buffer positioning
    • (display-buffer-alist) set the rules for displaying buffers.

Window

  • (selected-window) return the active window object #<window>
  • (window-paramters &optional WINDOW) return alist of window parameters
  • (with-selected-window WINDOW ...) run within a given window and return to original window

Frame

  • (selected-frame) return the active frame object #<frame>
  • (frame-paramters &optional FRAME) return alist of frame parameters
  • (with-selected-frame FRAME ...) run within a given frame and return original frame

Command

  • (this-command) return the object that represent the last executed command

External Command

  • (shell-command COMMAND)
    • xdg-open can be used to open a file externally.
  • (shell-command-to-string COMMAND) insert the result of shell command
  • (call-process ...)
  • (start-process ...)

Hook

  • (add-hook HOOK FUNCTION)
  • (run-hook-with-args-until-success HOOK &rest ARGS) runs hooks sequenctially until one of them returns t.
  • (with-eval-after-load PKG BODY)

Interactive

  • (y-or-n p PROMPT), (yes-or-no-p PROMPT) ask yes or no and return t or nil
  • (message STRING) echo in the minibuffer
  • (message "message" optional-format-vars) print message to the echo area
    • %s, %d can be used to format the string
  • (read-buffer PROMPT), (read-file-name PROMPT), (read-char &optional PROMPT)

3. Flow Control

Conditionals

  • (if (test) (if-true) (if-false))
  • (when (condition) (if-ture) (if-ture) ...)
  • (unless (condition) (if-false) (if-false) ...)
  • (cond (condition1 if-true) (condition2 if-true) ...) it is similar to the switch in C.

Repetition Loop Facility:

(loop NAME_CLAUSE(named)
      VARIABLE_CLAUSE(initially, finally, for, as, with)
      MAIN_CLAUSE(do, when, collect, append,...))   ;; similar for cl-loop

4. Macro and Special Form

  • defmacro defines a macro that interprets expression differently, that it may not evaluate the expression.
  • Special form is similar to macro and it is often the language feature.
  • (progn EXPRESSIONS) execute the expressions in order

5. Packages

5.1. cl-lib

  • (cl-loop VAR_DEFINE(for, with, ...) BODY(if, repeat, collect, append, return, ...)

6. Byte Compilation

  • A lisp file from a package is byte compiled on installation. It needs to be recompiled via package-recompile to load the code.

7. History

The original Lisp came about in 1960 by John McCarthy. It diverged into several dialect in 1970s and unified with Common Lisp in 1980s. The ANSI standard was also established in 1990s.

It was a niche programming language among industry and academia and soon got outnumbered by other languages due to its low performance and lact of libraries. Java at work, Python at academia replaced them.

The Rise & Fall of LISP - Too Good For The Rest Of the World - YouTube

8. References

Author: Jeemin Kim

Created: 2026-08-09 Sun 07:11