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)
1nil

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))
+12312

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

TerminologyDescription
:---:---
Pointcursor position, number of ch from the beginning of buffer
BufferPlace where the user can edit the content
MarkBeginning of the selected area
RegionSelected area/text
FrameThe current window of emacs
FillWrod Wrap
YankCopy
Kill RegionCut
Kill RingClipboard
Kill BufferClose Buffer
Mode LineStatus Bar
Font LockingSyntax Coloring
Narrowingshows 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.

Backlinks

If you like my content,

feel free to buy me a coffee

Enjoy crafting new things

Never stop learning.

Life is the sum of your daily habits.

Find things that you enjoy and please

Doit.

Feel free to connect with me.

Created by potrace 1.16, written by Peter Selinger 2001-2019

© Jing 2024. All rights reserved.