Manipulating Elisp code in Python
The emacs.elisp
module contains utilities for building and manipulating Emacs Lisp (Elisp)
expressions in Python. These can then be passed to an EmacsBatch
or
EmacsClient
instance to be executed.
Expr Objects
Elisp expressions are represented by subtypes of the Expr
abstract base class:
Literal
(value)
wraps Pythonint
s,str
s, andfloat
s.Symbol
(name: str)
represents a symbol.Cons
(car: Expr, cdr: Expr)
represents a cons cell.List
(items: Iterable[Expr])
represents a list.Quote
(expr: Expr)
represents a quoted expression.Raw
(src: str)
can be used to wrap a raw Elisp code string.
Generally you should use the functions detailed in the following section to build expressions rather than instantiating them directly.
You can use str(expr)
to produce (hopefully) syntactically-correct Elisp code.
Building Elisp expressions
The to_elisp()
function can be used to convert various Python values to Elisp expressions.
Elements of composite data types (lists, tuples, dicts) are converted recursively.
Most parts of this package’s API will use to_elisp()
to convert arguments that are not already
instances of Expr
, so it is often not necessary to use it directly.
Basic data types
to_elisp()
converts numbers and strings to literals and bool
s and None
to the
correct symbols:
>>> import emacs.elisp as el
>>> el.to_elisp(123)
<el 123>
>>> el.to_elisp(1.23)
<el 1.23>
>>> el.to_elisp('foo')
<el "foo">
>>> el.to_elisp(True)
<el t>
>>> el.to_elisp(False)
<el nil>
>>> el.to_elisp(None)
<el nil>
The nill
and t
symbols are also available as nil
and el_true
.
Symbols
Create a symbol with the symbol()
function:
>>> el.symbol('foo')
<el foo>
The symbols()
function can be used to create a list of symbols:
>>> el.symbols('a', 'b', 'c')
<el (a b c)>
Lists
el_list()
converts any iterable to a list expression:
>>> el.el_list(range(1, 5))
<el (1 2 3 4)>
to_elisp()
converts Python lists to quoted Elisp lists, while tuples are left unquoted:
>>> el.to_elisp([1, 2, 3])
<el '(1 2 3)>
>>> el.to_elisp(('a', 'b', 'c'))
<el ("a" "b" "c")>
Function calls
Function call expressions can be created with funccall()
, or by calling a
Symbol
instance. Keyword arguments are converted to
kebab-case
and prefixed with a “:” character.
>>> el.funccall('+', 1, 2)
<el (+ 1 2)>
>>> foo = el.symbol('foo')
>>> foo(el.symbol('x'), el.symbol('y'), kw_arg=123)
<el (foo x y :kw-arg 123)>
Quoting
The quote()
method produces a quoted version of an
expression:
>>> s = el.symbol('foo')
>>> s.quote()
<el 'foo>
>>> el.symbols('a', 'b', 'c').quote()
<el '(a b c)>
The q
property acts as a shortcut:
>>> s.q
<el 'foo>
Cons cells
An expression that must be constructed directly because it has no Python equivalent
is the cons cell, represented with the class Cons
:
>>> c = el.cons(el.symbol('a'), 1)
>>> c
<el (cons a 1)>
>>> c.q
<el '(a . 1)>
Mapping formats (alists and plists)
You can use make_alist()
or make_plist()
to convert mapping types like dict
s
to their Elisp equivalents. These functions will always treat string keys as symbols:
>>> el.make_alist({'a': 1, 'b': 2}).q
<el '((a . 1) (b . 2))>
>>> el.make_plist({':x': 1, ':y': 2}).q
<el '(:x 1 :y 2)>
to_elisp()
converts mapping types like dicts to plists or alists, depending on
the value of the dict_format
argument (defaults to "alist"
.
Raw code strings
Finally, use Raw
to wrap a raw Elisp code string to be inserted verbatim
in the given location:
>>> el.Raw('(print "hi")')
<el (print "hi")>
>>> el.el_list([1, 2, el.Raw('(+ a b)')])
<el (1 2 (+ a b))>
Elisp DSL
This package also includes an unholy abomination of a DSL that lets you write Elisp code in Python.
It is implemented through the singleton object emacs.elisp.E
.
Calling the singleton as a function converts a Python object into an Elisp object
using to_elisp()
:
>>> from emacs.elisp import E
>>> E(3)
<el 3>
>>> E('foo')
<el "foo">
>>> E(['a', 'b', 'c'])
<el '("a" "b" "c")>
Attribute access produces Elisp symbols, converting snake_case
to kebab-case
. The
same can be done by indexing with a string (without the case conversion):
>>> E.abc
<el abc>
>>> E.foo_bar
<el foo-bar>
>>> E[':baz']
<el :baz>
Symbols can be called as functions, generating Elisp function calls:
>>> E.message("Hello from %s", E('python-emacs'))
<el (message "Hello from %s" "python-emacs")>
>>> E['='](E.a, E.b)
<el (= a b)>
Additionally, the C
, S
, and R
methods are aliases for
cons
, symbols()
, and Raw
, respectively.
Using just the E
object, it is possible to write complex Elisp expressions:
>>> E.defun(E.my_elisp_function, E.S('a', 'b'),
... E.message("I am a crime against God."),
... E['+'](E.a, E.b))
<el (defun my-elisp-function (a b) (message "I am a crime against God.") (+ a b))>