How well does it work?
It doesn't work very well. There are a lot of rough edges. In theory you can use it for editing, and it's possible to save buffers. But it's missing a lot of features that other editors have.
Currently work is being done to make vi mode more functional. Implementing most of the classic BSD vi functionality (i.e. without vim extensions) is definitely within sight at this point, and would make the editor a lot more usable.
The project is not yet self-hosting (I'm editing the code in Emacs).
Love it or hate it, one of the things that makes Emacs a really, really great editor is that it's not written in C or C++, it's written in elisp. Only the lowest-level I/O bits are written in C, and exported to elisp code.
This makes Emacs really extensible. The author of e normally uses Emacs, and runs it using viper-mode, a minor mode that makes Emacs behave like vi. That's pretty crazy -- using Emacs, you can pretend like you're using vi, but also tap into this huge millions-of-lines-of-code Emacs elisp ecosystem. The fact that you can completely customize Emacs down to the lowest level of keyboard handling to tack on a brand new editing system -- and have it still be fast -- shows the power of this approach.
That said, if you've written much elisp you know it's not a very good language. It's very antiquated, and very complicated (and I'm not just saying that because it's a Lisp -- it's antiquated and complicated compared to pretty much every other Lisp implementation in wide use today). Elisp also has the problem that it doesn't have a state-of-the-art bytecode interpreter. This can make elisp rather slow, particularly when loading new files and while garbage collections are running.
Editors like vim feel fast and have great editing capabilities, but are hard to customize. If you've ever tried to really dive into vimscript or its Python bindings you'll recognize that the scripting features feel tacked on and clunky.
Why this project? Why not use Node.js?
I think Node.js is a great project. It has I/O capabilities, and there's at least one curses binding floating around, so there's no reason you couldn't write the same thing using node.
The main answer is I wanted a project to expand my C++ skills, hence this project. That said, I think there are some other advantages to a separate V8 embedding for an editor:
- After compiling, you get a real bona-fide binary; you can copy it around on different machines if they have the right shared libraries built.
- It's easy to statically link things, creating a stand-alone binary; this makes it even easier to copy around and install on different machines.
- The I/O model is a lot simpler (mostly due to doing synchronous I/O).
- You can still do asynchronous I/O if you want; as a matter of fact, behind the
scenes e is using boost::asio to process keypresses asynchronously (to allow
various timers to run in the background). Look at the implementation of
CursesWindow::Loopif you want to learn more about this.
What does it look like?
Here's a screenshot. It's not very exciting.
Help! How do I quit?
Ctrl-C will always exit the editor.
How do I save files? How do I open new buffers?
You can save a file with Ctrl-S. There's currently no way to open a new buffer.
How can I customize/configure the editor?
~/.e.js. The way the
editor starts up is that by default it will do the following (in the order
- load any scripts passed on the command line with
Because you can use the
require() method to include other scripts, you can
structure your own customizations however you like (e.g. by splitting them out
into multiple files).
In general most of the core event loop uses the same event listener pattern as browsers, which makes it easy to extend/customize behavior in a non-intrusive way. The various events and listeners that you can use are not well documented, however.
make, documentation will be generated at
will happen every time the
e binary is successfully compiled.
C++ code all lives in the
src directory. The C++ code all passes the checks by
third_party/cpplint.py (which you should install as a git hook if you're
hacking on the editor).
Third party code, regardless of language or origin, is in the
directory. This also includes some third party "data", such as the terminfo
Read on to get the appropriate instructions for your operating system.
The following are dependencies that must be satisified to build the editor:
- boost, including the boost::asio and boost::program_options components
- ncurses (you probably already have this; other curses implementations might work too)
- V8 (built as a shared library)
The following dependencies are optional:
- liblzma (only needed if you want to build the
- ncursesw (the unicode version of curses)
Many of these "optional" dependencies are controlled by
USE_ defines in
e.gyp; if you're having problems with an optional dependency, you may find it
useful to take a look at
e.gyp and tweak it according to your needs.
happens is the editor will look for a file named
js/core.js and load that as
the first script.
For an optimized editor build (i.e. the
will be bundled into the binary. This is done by the script
scripts/gen_bundled_core.py. This script will attempt to recursively expand
requires() statements seen in the file
js/core.js, until it has a single
scripts/precompile.cc which uses the public V8 pre-compilation methods, and
additionally compressed using LZMA.
The pre-compilation data and the LZMA compressed core scripts are written out to
src/bundled_core.cc and end up included in the final
executable. When the executable starts up, it will decompress the LZMA data and
load the core script.
e --debug <args>
--debug flag is actually a shortcut for, and identical to, running the editor
e --skip-core -s js/core.js
In the future the meaning of
--debug may expand to give more debugging
information, but that's unlikely to happen until the editor is out of alpha
Building on Linux
You'll need GYP installed. You ought to then be
able to simply run
make to build the project. Internally, this will create a
build with a generated
Makefile from GYP, and then invoking
make in the future will run any necessary build scripts and then do a
recursive make using that file. (Note: the file generated by GYP is
build/Makefile, the root-level
Makefile is different.)
To have GYP build your auto-generated
Makefile, just run
script will correctly invoke GYP for the project, and report errors if it fails
to run GYP.
If you have any build problems while running
make, you might want to try
which sets verbose build output. This will help you hunt down the exact compiler/linker errors.
Building on Ubuntu
Building on Ubuntu, both 11.10 (Oneiric) and 12.04 (Precise), is supported. For both releases you need to install the following packages:
sudo apt-get install binutils-gold build-essential git gyp libboost-dev \ libboost-program-options-dev libboost-system-dev liblzma-dev \ libncurses5-dev libncursesw5-dev libtcmalloc-minimal0 libunwind7-dev \ libv8-dev pkg-config python-lzma python-jinja2
Then you will need to set up a
sudo ln -s /usr/lib/libtcmalloc_minimal.so.0 /usr/lib/libtcmalloc.so
After that you should be good to go.
Building on Fedora
Pretty much the same as Ubuntu, with slightly different packages (not listed
here; inquire if you need assistance). You will also need to manually create a
tcmalloc.so symlink, as with Ubuntu. Unfortunately, Ubuntu and Fedora version
the tcmalloc .so files differently, so there's not a straightforward way to
handle this setup automatically.
Building on Mac OS X
This should be pretty similar to building on Linux, except that before it will
work someone needs to modify
e.gyp. It's probably just a matter of instructing
GYP to correctly link things.
Building on Windows
This is unlikely to work. There are a fair number of Unix-isms in the code (although nothing too nasty, they should be fixable by using various Boost interfaces).
Probably the more difficult thing about this would be getting a working curses implementation. There seem to be a couple out there but who knows how well they work.