Could Emacs be rewritten in Python?
imbosol-1049649076 at aerojockey.com
Sun Apr 6 20:40:16 CEST 2003
Patrick K. O'Brien wrote:
> If you were crazy enough to think that you could create a program
> along the lines of Emacs, but written in Python, how would you go
> about it? How would you design the domain model for files, buffers,
> windows, and frames? How would you allow the same level of
> customizability? How would you map functions (or methods or whatever)
> to keys? Any thoughts?
> Here is the background. I'm working on a file editor (called
> PyAlaMode) using wxPython and Scintilla. It's an extension of the
> PyCrust code base. I've got a basic version working, and it supports
> editing multiple files and all the usual, basic features. But I want
> it to be as customizable and extensible as Emacs. In fact, I want to
> model it after Emacs, so that elisp code could be rewritten in Python
> and work with PyAlaMode. To do that, I've got to support the same
> primitives as Emacs; expose files, buffers, regions, and windows the
> same way Emacs does; handle the Emacs keybindings and ability to remap
> keys, the same way Emacs does, etc.
> Sound like fun?
Sounds like a lot of refactoring.
Here's how I would do it. More experienced programmers, feel free to
correct anything experience says won't work so well.
What I recommend is to read through the Emacs Lisp manual and figure
out the functions you'll want to support. Obviously, you'll want to
make each type of object (buffer, windows, frames, positions, markers,
keymaps, etc.) a Python class. When you read through the manual, take
the lisp functions and assign them as method of the appropriate class.
(For now, don't *write* the methods yet; just prototype them.) This
builds a set of interfaces that the classes should follow. The point
of this is to give you an idea of exactly what the different objects
in Emacs do, and how they interact.
Don't be too slavish in trying to match the exact behavior of the lisp
functions, and be careful to assign functions to the class they really
belong to. Don't assign a function to the keymap class just because
it's in the keymap section.
As an example, take the section on buffers. First function is
"current-buffer". What class should it belong to? Certainly not
Buffer. The current buffer is a global property, so "current_buffer"
should be either a global function, or a method of an application
Next three functions are "save-current-buffer", "with-current-buffer",
and "with-temp-buffer". These are actually not functions, but special
forms and macros. Python has no analogue to these (barring some
obscure metaclass tricks). Depending on the form, it might be useful
to have a corresponding method in Python, or it might be better to
think about a more Pythonic way to do it. I haven't thought about it
too much, but off hand, I'd say I'd choose the latter in this case.
In fact, these seem to be mostly a convenience, so I wouldn't bother
to include them.
Next function is "buffer-name". This obviously belongs in the Buffer
class. I'd just call it "name". Perhaps you want to retain the exact
name, though. That's up to you.
Next function is "rename-buffer". This should belong in the Buffer
class--however, in Emacs, it only operates on the current buffer. I
think that's a design flaw; I would fix it. I would make "rename" a
method of Buffer.
You might want to also include global "buffer_name" and
"rename_buffer" functions that operate on the current buffer.
Next function is "get-buffer". This should be global, because the
list of buffers is global.
And so on.
Understand what I'm saying? Eventually, you'll have a nice list of
classes waiting to be fleshed out. It should be straightforward to do
The next thing you should do it refactor your original PyAlaMode code
to use these classes. Don't add functionality. Just implement what
you need to get back to the original behavior of PyAlaMode, but using
the new classes.
You said the keymaps aren't editable? Add one keymap. Don't worry
about adding functions to edit keymaps yet. Say you currently use a
string to hold the buffer. Change it to use a Buffer object.
Once you've done all this, then it should be straightforward to fill
out the interfaces and add features.
There is one potentially disasterous pitfall you should be aware of.
Emacs does all kinds of strange things with namespaces. It uses
dynamic binding, unlike Python, which uses lexical binding. Emacs has
one monolithic global namespace, as opposed to Python, which has an
organized infrastructure of "global" namespaces, that is, modules.
Also, Emacs has weird namespaces like buffer local variables. One
thing you'll have to do is think about how to sort all these namespace
It seems to me that a lot of these issues won't matter much if you
have a good and consistent strategy for organizing stuff and passing
More information about the Python-list