Back in December, I started experimenting with getting Emacs set up to use Vim-style modal editing. I’d begun studying Clojure more deeply and Emacs’s CIDER is the most popular editing environment for Clojure, so I felt like I at least owed it a look. I’d also found myself thinking about and agreeing with a central tenant of Emacs philosophy: that your tools should evolve with you and become deeply customized over time.
But—and this is a big but—I couldn’t imagine leaving modal editing behind. Some background on my editing history: I used Emacs when I learned to program in college, writing Java, C++, Python with Emacs. It was what we used in the computer science lab, so it was what I adopted. Ironically, I barely customized my setup at all beyond cargo-culting a few different keybindings, tweaks and major modes. It wasn’t until about five years ago that some colleagues of mine convinced me to try out Vim instead. The idea that Vim’s modal editing is a language clicked with me and sounded a lot easier on the wrists than Emacs key-chords. I spent a weekend getting up to speed, researching plugins and I’ve been a modal-editing weenie ever since.
Fast-forward five years and articles on evil-mode started to make the rounds. Despite some skepticism, I began to wonder if I could get the best of both worlds: a deeply customizable editing environment and modal editing. The Clojure community’s preference for CIDER was a great excuse to try things out.
I used a couple blog posts as tutorials to start from and went from there:
What I Learned: The Highlights
Evil mode is actually that good: Any Vim user who’s tried to use a Vim-emulation plugin in other editors knows that they always fall jarringly short. Evil-mode… doesn’t. Text objects? Check. Visual block mode? Check. Registers? Check. Macros? Check. You really can sit down with Emacs, run
(evil-mode t) and edit text in a completely unsurprising way. This is impressive as hell.
What’s more, evil-mode doesn’t lock you into the default Vim keybindings; in fact, it makes customizing pretty easy. I was able to define custom normal-mode evil keys for various language modes after just a few quick tutorials.
Plugin management is much better than I remember: The Emacs package manager
package.el wasn’t a default part of Emacs until 24.0, well after I switched to Vim. Being able to install a plugin with a single command was great, but I wanted something a bit closer to Vundle that would help me keep my plugins synced across two laptops.
Behold: use-package works like Vundle with the
:ensure t argument. It also allows you to make sure the package is required before executing your plugin-specific configuration code. One gotcha: I needed to install one package with “M-x install
Elisp isn’t awful: Emacs isn’t so much configured by Elisp as it is a giant Elisp REPL. Everything, from keypresses on up, is handled by calling Elisp functions, and you can customize how Emacs works by writing further Elisp. I found it a lot easier to pick up and start writing customization code in Elisp than I did in Vimscript. Most would agree that’s a low bar, but there it is.
The degree to which Emacs is self-documenting was unexpectedly nice.
M-x describe-function over an Elisp symbol will bring up its documentation. I bound this to
K in evil-normal-mode as suggested by one of the above tutorials, and it’s a really great way to pick apart sample code and figure out how it works. Similarly,
M-x describe-key is super useful for figuring out what function a particular Emacs-style key shortcut is calling. After you have the function name, you can easily bind it to your own evil-flavored keys.
Nothing is quite as good as Ctrl-P: A fast fuzzy file matcher is something I can’t live without, and I struggled to find something to replace Ctrl-P. The projectile project management plugin can be configured to use various file matching plugins, but none of them were without issues:
ido-flx was just straight-up too slow for matching on a large project (just under 7k files). I tried setting a higher garbage collection threshold and lowering the number of completion candidates needed before the fuzzy matching would kick in, per the flx README, but it still was too laggy to use at work.
grizzl I couldn’t get working at all. I ran into this issue with a
Symbol's function definition is void: exitfunerror being thrown and didn’t find a solution.
helm came the closest. It was acceptably fast on a large project, though still noticeably slower than Ctrl-P. The completion algorithm was a bit different than what I’m used to; it used spaces to break up tokens instead of an implicit
.*after each character—so if you were searching for
ap mo filinstead of
apmofil. I wound up actually liking that better after a few days. Unfortunately, it would occasionally crash the vanilla OS X build of Emacs. This is apparently an Emacs bug and is purported to be fixed in the emacs-mac-port build but I haven’t stress-tested to be sure.
Evil-matchit just didn’t work with Ruby: I write Ruby by day, and Vim’s matchit lets me use
% to hop between
end blocks in Ruby as well parentheses, curly braces and so on. It’s really amazing useful for code navigation, especially if the code you’re working with doesn’t exactly hew to the idea of small methods. I was delighted that the Emacs evil-matchit had Ruby support; unfortunately, it doesn’t seem to work. Hitting
% on a block inside a method would take me to the block before the selected block, or to the top of the method, or to the beginning of the line I was on—essentially anywhere but where it should have gone.
Two Months Later
For now, I’m putting my Emacs configuration aside for a bit. I’m impressed with Evil, but feel a bit low on energy and like there’s too much yak-shaving ahead before I’m really comfortable back in Emacs. I also want to focus on just learning Clojure and its idioms without having to wrestle with learning and customizing a new editing environment at the same time. I started using Tim Pope’s vim-fireplace for working with Clojure, which works well enough, even if it’s not quite a real embedded REPL.
I do want to come back to this experiment someday. I feel like the issues I ran into should be tractable with more time and focus, and there are some plugins like org-mode that I really want to explore. The work I put in to get as far as I did is versioned on GitHub along with the rest of my dot-files, so hopefully the next time around I can just pick up where I left off.