emacs lisp cheatsheet
a dialect of lisp https://stackoverflow.com/questions/6492704/what-exactly-does-homoiconicity-mean a homoiconic language. homoinoic means "code as data". the homo prefix stands for this characteristic.
this is cheatsheet for emacs lisp programming language syntax and semantic the following notes are organized from this website
a emacs cheatsheet website https://alhassy.com/ElispCheatSheet/
numberic types
(+ 1 3) ; -> 4
(+ 1.0 2) ; -> 3.0
(/ 3 2) ; -> 1
1e2 ; -> 100
(+ 1 1000000000000000000000000000000000000000) ; -> like python, it supports big num
character types
(string ?f ?o ?o) ; => "foo"
?A ; => 65 (#o101, #x41, ?A)
(format "I have %s bananas" 3) ; => "I have 3 bananas"
lists
(equal '(1 2 3 4 5) (list 1 2 3 4 5)) ;; both are the same
string vs symbol
'this-is-a-symbol ;;
"this-is-a-string" ;;
(string= "a" "a") ; => t check string and equality
(string= "a" 'a) ; => t
Basic types predicate
there is no false in emacs lisp, everything is evaluated to be nil will be thought as false
(print (null nil))
(print (numberp 2))
(print (numberp "2"))
(print (atom nil))
t t nil t
Get Object Type
(type-of (current-buffer))
buffer
defvar vs setq, defcustom
They both are nearly the same except for defvar
will not overwrite the origin definition if the variable-name is already be defined.
(defvar var-name value "doc")
(setq var-name value)
Defcustom provide a more user-friendly customization with the built-in function customize
.
non destructive
ex. reverse vs nreverse append vs nconc remove vs delete
but the “n” in this context stands for “non-consing”
progn vs cl-block
they are almost the same. cl-block can name the block ex.
(cl-block yo
(print "hello")
(print "world"))
(progn
(print "hello")
(print "world"))
optional arguements
Every arguement that follows the &optional
keyword is optional.
(defun hi(&optional msg1) ...BODY)
set vs setf vs setq vs setq-default
Setq-default is globally set a variable( which is the default for buffer variable).
(set ls '(1 2 3 4)) => Error - ls has no value
(set 'ls '(1 2 3 4)) => OK
(setq ls '(1 2 3 4)) => OK - make ls to (quote ls) and then have the usual set
(setf ls '(1 2 3 4)) => OK - same as setq so far BUT
(setf (car ls) 10) => Makes ls '(10 2 3 4) - not duplicated by setq/set
associative list
(setq a '(("yo" . 20) ("bea" . 10))
assoc, assq, alist-get
retrieve the pair by assq
and it use eq
to compare the equality of elements
(assq "yo" a)
assoc
allows you to custom the comparison function
alist-get
is very similar to assoc but more powerful. it can do things like get with fallback to default value and pop the element
(setq foo '((a . 1) (b . 2)))
(setf (alist-get 'b foo nil 'remove) nil)
hash table
(setq xx (make-hash-table :test 'equal))
(puthash 'key 10 xx)
(gethash "key" xx) ;; 10
(remhash 'key xx)
get the values of hash tables
like python's dict.values()
(map-values xx)
anonymous function / lambda functions
(defvar add3 (lambda (x) (+ x 3))) ;; we can use setq to replace
(funcall add3 10) ;; will output 13
Anonymous function is different from the function. We can use type-of
to see the type of anonymous but funcitons not.
There is a setf
to set symbol-function so defun
actually equals to
(setf (symbol-function 'add2)
#' (lambda (x) (+ x 2)))
the name of a function needs to be of type
passing functions as arguments
(far #'func1 #'func2 x) ;; this is how to pass function as arguements
(defun far (func1 func2 x)
(+ (funcall fucn1 x) (funcall func2 x))) ;; this is the definition
I don't know why need to use this format
variadic functions and optional arguements
(defun sum (&rest nums) ;; variadic arguements
(apply #'+ nums))
(sum 1 2 3) ;; call sum with arbitrary arguements
(defun gen-list (a &optional b)
(list a b))
(gen-list 1)
1 | nil |
wow, it has keyword arguments like python..
(defun make-shell-interface (&rest params)
((let ((name (plist-get params :name))
(type (plist-get params :type)))
(...))))
emacs lisp doesn't support closure by default
That's because emacs use dynamic binging by default. However, you can use (setq lexical-binding t)
to enable lexical binding
to support the closure
(defun make-adder (n)
#'(lambda (x)
(+ x n)))
(setf add2 (make-adder 2))
(funcall add2 3) ;; this will fail
local variables
(let ((curr (point))
(start-pos 0)
)
;; some-body
(message "hi"))
if-let
Rust has the similar stuff.
(if-let ((name nil))
(message "yo")
(message "no"))
symbol
One of the more confusing parts of Elisp’s is that its symbols point to multiple storage locations;
a single symbol can refer to both a function
and a variable
(setq baz 123)
(defun baz (x y)
(- x y))
(message "baz as value: %s" baz) ; => "baz as value: 123"
(baz 10 3) ; => 7
symbol to string
(symbol-name 'hi) ;; will output hi because we 'hi is a symbol
closures
http://caiorss.github.io/Emacs-Elisp-Programming/Elisp_Programming.html#sec-1-6-7
By default, emacs lisp is dynamic binding so it does not support closure.
how to enable lexical binding in the org babel https://emacs.stackexchange.com/questions/61754/how-can-i-enable-lexical-binding-for-elisp-code-in-org-mode
(defun adder (a)
(lambda (b) (+ a b)))
adder
(funcall (adder 5) 3) ;; this will not work
(setq lexical-binding t)
;; this will not works for the org babel mode
;; the only way is set the correspond header
(defun adderx (a)
(lambda (b) (+ a b)))
(funcall (adderx 3) 4)
7
in ielm, this will work. I don't know why it broken at the org babel.
defstruct
(defstruct user id name balance) ;; this will implicitily define
;; make-user, user-p, copy-user
;; It's obviously defstruct is a kind of macro
quasiquote
`("1+1=" ,(+ 1 1)) ;; you will get ("1+1=" 2)
1+1= | 2 |
let's see how ,@ works
`(+ 1 2 3 ,@(list 1 2))
+ | 1 | 2 | 3 | 1 | 2 |
Advice vs Hook
https://www.emacswiki.org/emacs/AdviceVsHooks
interactive function
it means you can search and execute your function by execute-extended-command
To make this work you need to add (interactive)
(defun hi ()
(interactive)
(message "hi"))
pass a list in interactive
it will pass the list of args to the function
(defun ha (obj)
(interactive (list "hi"))
(message obj))
predicate methods means assertion method
ex. isEmpty. In emacs lisp, use suffix `p` in convention
ex. is_empty -> empty-p
#' (sharp quote) , which will warns you if the function is undefined. (provide 'foo) works like module.export in javascript use require to load library.
what the fuck is ###autoload doing?
pred
only works in pcase macro pred is a built-in function that takes a predicate function as an argument and returns a new function that applies the predicate to its argument.
A predicate function is a function that returns a boolean value (t or nil) depending on whether some condition is true or false. For example, integerp and stringp are predicate functions that return t if their argument is an integer or a string, respectively.
When pred is used in conjunction with pcase, it allows you to apply a predicate function to a value and check if the result is true. Here's an example:
(pcase '("hello" 42)
(`(,(pred stringp) ,(pred integerp))
(message "string followed by an integer")))
pcase-let
it works like a pattern matching and python's assignment unpacking
(pcase-let ((`(1 2 ,foo) '(3 4 10)))
(message "foo = %s" foo))
pcase-lambda works samely but binding as a function
elisp has many side effect functions
I think (maybe it's not suitable with functional programming ?)
(save-excursion &rest BODY)
;; example
(save-excursion
(beginning-of-line)
(search-forward "\"" (point-at-eol)) ;; point-at-eol is the bound we want to search
(1- (point)))
save-excursion works like transaction any move cursor function will finally be reset to reset destination.
how to defined a macro
need to read the ansi common lisp
often combine with quasiquote
(defmacro rebindfun (new-name old-name)
`(setf (symbol-function ,new-name) ,old-name)) ;; interesting usage
This works like the built-in function defalias
(defalias 'filter 'remove-if-not)
,@
will evaluate the express like ,
but it accepts a list and expands it into the resulting list.
macro expand
(macroexpand '(rebindfun 'abc 'message)
emacs lisp api faq
Coding Style
coding style's reference
emacs use two space for indentation but in func definition not always be
(format "%s %d"
something
something-else)
function body aligned with arguements
function indentation style
place all trailing parentheses on a single line instead of distinct lines.
(let ((x "20")
(y "30"))
sayhi "x"
)
if any text precedes an opening bracket ( { [ or follows an closing bracket ]}), separate that text from the bracket with a space.
(foo (bar baz) hi)
use unless is more authenticer
(when (not conds) () ()) == (unless () ())
ok.. there is a small util function for something like (+ x 1) which can be written to (1+ x). However, I think (+1 x) will be more clearer
(+ 1 2)
(1+ 2) ;; ok, I know why can not use (+1 x), it seems conflict ..
(1- 3)
8
what's the differnt between `with-eval-after-load` and `eval-after-load`
some naming convention
function naming use `lisp-case` ex. get-backage instead of getbackage or getBackage
private top-level definition
projectile--private-fun
Emacs API
Terminology | Description |
:--- | :--- |
Point | cursor position, number of ch from the beginning of buffer |
Buffer | Place where the user can edit the content |
Mark | Beginning of the selected area |
Region | Selected area/text |
Frame | The current window of emacs |
Fill | Wrod Wrap |
Yank | Copy |
Kill Region | Cut |
Kill Ring | Clipboard |
Kill Buffer | Close Buffer |
Mode Line | Status Bar |
Font Locking | Syntax Coloring |
Narrowing | shows only part of the buffer (a contiguous block of text, hiding the rest) |
example get selection
(defun get-selection ()
"Get the text selected in current buffer as string"
(interactive)
(buffer-substring-no-properties (region-beginning) (region-end))
)
Reference
Actually, we can use info mode to read elisp. An interesting usage is that we can use (info "(elisp) Symbols")
to show the documentation.