Skip to content

Commit 4d7555a

Browse files
committed
Documentation
1 parent f9f2275 commit 4d7555a

3 files changed

Lines changed: 235 additions & 0 deletions

File tree

docs/elisp.rst

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
Representing Emacs lisp code in Python
2+
======================================
3+
4+
The :mod:`emacs.elisp` module contains utilities for representing Emacs lisp
5+
Abstract Syntax Trees (AST's) as Python objects, see the :class:`ElispAstNode`
6+
abstract class and its subclasses.
7+
8+
9+
Creating Elisp forms
10+
--------------------
11+
12+
The fundamental data type in Elisp is the list. Other data types include symbols
13+
and self-evaluating types such as strings or numbers.
14+
15+
Use the :func:`to_elisp` function to convert simple Python values to their Elisp
16+
equivalents. This will wrap numbers and strings as Elisp literals, as well as
17+
convert bools and None to the correct symbols:
18+
19+
.. doctest::
20+
21+
>>> import emacs.elisp as el
22+
23+
>>> el.to_elisp(123)
24+
<el 123>
25+
26+
>>> el.to_elisp(1.23)
27+
<el 1.23>
28+
29+
>>> el.to_elisp('foo')
30+
<el "foo">
31+
32+
>>> el.to_elisp(True)
33+
<el t>
34+
35+
>>> el.to_elisp(False)
36+
<el nil>
37+
38+
>>> el.to_elisp(None)
39+
<el nil>
40+
41+
42+
Python lists are converted to quoted Elisp lists, while tuples are left unquoted:
43+
44+
.. doctest::
45+
46+
>>> el.to_elisp([1, 2, 3])
47+
<el '(1 2 3)>
48+
49+
>>> el.to_elisp(('a', 'b', 'c'))
50+
<el ("a" "b" "c")>
51+
52+
53+
Elements of lists/tuples are recursively converted using :meth:`to_elisp` if
54+
they are not already instances of :class:`ElispAstNode`.
55+
56+
You can use :func:`quote` to quote a value. It will also convert strings to
57+
quoted symbols:
58+
59+
.. doctest::
60+
61+
>>> s = el.Symbol('foo')
62+
>>> s
63+
<el foo>
64+
65+
>>> el.quote(s)
66+
<el 'foo>
67+
68+
>>> el.quote('foo')
69+
<el 'foo>
70+
71+
72+
Other shortcuts are :func:`cons` to create a cons cell, or :func:`symbols` to
73+
create a list of symbols:
74+
75+
.. doctest::
76+
77+
>>> el.cons(el.Symbol('a'), 1)
78+
<el (cons a 1)>
79+
80+
>>> el.symbols('a', 'b', 'c')
81+
<el (a b c)>
82+
83+
>>> el.symbols('a', 'b', 'c', quote=True)
84+
<el '(a b c)>
85+
86+
87+
You can use :func:`make_alist` or :func:`make_plist` to convert common mapping
88+
types to their Elisp equivalents. These functions will always treat string
89+
keys as symbols:
90+
91+
.. doctest::
92+
93+
>>> el.make_alist({'a': 1, 'b': 2}, quote=True)
94+
<el '((a . 1) (b . 2))>
95+
96+
>>> el.make_plist({':x': 1, ':y': 2}, quote=True)
97+
<el '(:x 1 :y 2)>
98+
99+
100+
Finally, use :class:`Raw` to wrap a raw Elisp code string so that it will just
101+
be inserted verbatim in the given location:
102+
103+
.. doctest::
104+
105+
>>> el.Raw('(print "hi")')
106+
<el (print "hi")>
107+
108+
109+
Using Elisp forms
110+
-----------------
111+
112+
Elisp forms can be passed to :meth:`Elisp.eval` and :meth:`Elisp.getresult` for
113+
execution. You can also convert them to strings to produce (hopefully)
114+
syntactically-correct Elisp code.
115+
116+
117+
Elisp DSL
118+
---------
119+
120+
This package also includes an unholy abomination of a DSL that lets you write
121+
Elisp code in Python. The DSL is implemented through a singleton object which
122+
is importable as :data:`emacs.elisp.E`::
123+
124+
>>> from emacs.elisp import E
125+
126+
127+
Calling the singleton as a function converts a Python object into an Elisp object
128+
using :meth:`to_elisp`:
129+
130+
.. doctest::
131+
132+
>>> E(3)
133+
<el 3>
134+
135+
>>> E('foo')
136+
<el "foo">
137+
138+
>>> E(['a', 'b', 'c'])
139+
<el '("a" "b" "c")>
140+
141+
142+
Attribute access produces Elisp symbols, converting underscores to dashes. The
143+
same can be done by indexing with a string:
144+
145+
.. doctest::
146+
147+
>>> E.abc
148+
<el abc>
149+
150+
>>> E.foo_bar
151+
<el foo-bar>
152+
153+
>>> E[':baz']
154+
<el :baz>
155+
156+
157+
Symbols can be called as functions, generating Elisp function calls:
158+
159+
.. doctest::
160+
161+
>>> E.message("Hello from %s", E('python-emacs'))
162+
<el (message "Hello from %s" "python-emacs")>
163+
164+
165+
Additionally, the ``Q``, ``C``, ``S``, and ``R`` methods are aliases for the
166+
:func:`quote`, :func:`cons`, :func:`symbols`, and :class:`Raw`, respectively.
167+
168+
Using just the ``E`` object, it is possible to write complex Elisp forms:
169+
170+
.. doctest::
171+
172+
>>> E.defun(E.my_elisp_function, E.S('a', 'b'),
173+
... E.message("I shouldn't exist"),
174+
... E['+'](E.a, E.b))
175+
<el (defun my-elisp-function (a b) (message "I shouldn't exist") (+ a b))>

docs/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Welcome to python-emacs's documentation!
1010
:maxdepth: 2
1111
:caption: Contents:
1212

13+
usage
14+
elisp
1315

1416

1517
Indices and tables

docs/usage.rst

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
Basic usage
2+
===========
3+
4+
Most of the functionality in this package is implemented in the :class:`Emacs`
5+
class, which represents an interface into the Emacs program.
6+
7+
8+
Instantiating the Emacs interface
9+
---------------------------------
10+
11+
You should generally create the :class:`Emacs` object using one of the following
12+
two class methods rather than invoking the constructor directly.
13+
14+
If you create the object with :meth:`Emacs.batch`, it will start a new Emacs
15+
process with the ``--batch`` argument each time you run a command or evaluate
16+
Elisp code. This will be slow if your ``init.el`` file takes a while to execute.
17+
18+
Alternatively, :meth:`Emacs.client` will create an instance which connects to
19+
an already-running Emacs process using the ``emacsclient`` program. This should
20+
make most commands run much faster. If you use this method make sure to start
21+
the server in Emacs using ``(server-start)``.
22+
23+
If the ``verbose`` keyword argument is set to 1 or higher, the subprocess'
24+
``stderr`` stream will be redirected to the console. If set to 2 ``stdout`` will
25+
be displayed as well.
26+
27+
28+
Low-level interface
29+
-------------------
30+
31+
At the lowest level, you can call the :meth:`Emacs.run` or
32+
:meth:`Emacs.getoutput` methods to invoke the program with the given list of
33+
command line arguments. The difference between the two is that
34+
:meth:`Emacs.getoutput` returns the value of stdout as a string while
35+
:meth:`Emacs.run` returns an entire :class:`subprocess.CompletedProcess`
36+
instance.
37+
38+
39+
Executing Emacs lisp code
40+
-------------------------
41+
42+
The main job of :class:`Emacs` is to execute elisp code.
43+
You can do this using the :meth:`Emacs.eval` method::
44+
45+
>>> emacs = Emacs.batch()
46+
>>> emacs.eval('(print "Hello world!")')
47+
'\n"Hello world!"\n'
48+
49+
This method records the output from stdout and returns it as a string.
50+
51+
Alternatively, you can use the :meth:`Emacs.getresult` method which returns the
52+
result of the execution as a Python value::
53+
54+
>>> emacs.getresult('(+ 1 2)')
55+
3
56+
57+
Note that it does this by converting the value to JSON in Emacs and then decoding
58+
it in Python, so the value must be json-encodable.

0 commit comments

Comments
 (0)