Cet article est un brouillon.
This article is a draft.
One of the things I would love to have in Emacs is a “normal mode” similar to the one Vim has, ie a mode made of primitive editing commands called by entering single-key shortcuts. The usual answer to the question “how to bring Vim’s cool features to Emacs?” is Evil, the Extensible Vi Layer. But Evil focuses on the very different task of emulating Vim’s behavior in Emacs, and simply transforms Emacs into a Lisp-powereed Vim, ultimately bringing Emacs’ features to a Vim emulated in Emacs. This approach seem to suit a lot of people’s needs, and it has objective qualities, but doesn’t suit me. Whenener I tried evil, I mostly forgot I was in Emacs and when I remembered it, Emacs wouldn’t behave normally.
What I want is not full Vim emulation in Emacs, but a normal mode that would feel native to Emacs, which doesn’t try to emulate Vim’s behavior or idiosyncrasies, but instead provides a different way to access Emacs’ features. This is something that can’t be built out of Evil, because:
- Evil is globally monolithic, with a “take it or leave it” approach. This has improved over time, but even with
evil-disable-insert-state-bindings t), I still can’t find a way to get only the normal mode. When Evil’s activated, activating the mark toggles it to visual state, for example. A lot of hacking may probably improve this, but that’s probably more than it would take to write something nicer and lighter from scratch.
- Evil tries to follow Vim’s behavior and metaphors, even where they differ for Emacs. Yanking text is
C-yin Emacs and
yin Vim, but yanking has opposite meanings in Emacs and Vim. That means that
ymeans copy. Not intuitive, doesn’t help building “muscle memory”.
- I can’t for the life of me force Evil to always start in a given mode. Whatever I try, when I start a new email the buffer always appear in normal mode.
What I want is an Emacs normal mode, not Vim’s. That is, a mode where
y yanks à la Emacs, that is, paste. What follows describe my attempt to create a normal mode inspired by Vim’s one, which tries to borrow what’s good in Vim, and nothing more.
God mode and hydras to the rescue
There’s a very basic “normal” mode available for Emacs as a minor mode, called God-Mode. By default, it simply remaps
C- something keybindings by removing their modifier (turning
p), and understands g as meta, waiting for next stroke. This mode’s README provides the following example:
Before: C-p C-k C-n M-^ ) C-j C-y M-r C-x z z M-2 M-g M-g C-x C-s After: p k n g ^ ) j y g r . . 2 g g x s
God mode also allows us to set our own keybindings. This is where the cool stuff may begin. Instead of simply removing Ctrl from our Emacs bindings, you can come up with a full set of bindings for a normal mode.
Let’s first summarize what we want. Each line of this table describes one or more keys. “Trivial?” tries to describe what should be, well, trivial to implement in Emacs, and what may be a bit harder. The latter is discussed just below the table.
||Append at end of line||Yes|
||Open line below/above||Yes|
Besides what’s in this table, I also want:
- Multiplier prefix
- like 12a (insert “a” twelve times), or 12g (goto line 12): Emacs has these, I simply have to take care my functions use these.
- Motion commands
- should be trivial to implement, but because they can construct text objects, read the note on text objects below.
- This should be trivial, but as I said in the introduction, the problem is that I want
yto mean paste, and not copy.
kcan be kept as is (Emacs and Vim surprisingly use the word “kill” to describe the very same operation). I need to find an available shortcut for copy,
pmay not be a bad first choice. It is a good mnemonic: p is the hard consonant in coPy, and for French speakers, “presse-papier” is French for clipboard). Furthermore, people who want something closer to Vim but for some reasons don’t want the fully-fledged evil may simply reverse the bindings.
Motion commands and text objects
A very fundamental notion in Vim that Emacs doesn’t have is the text object. Text objects are the reason Vim’s commands are so intuitive: they share a lot of syntax, and are constructed like actual sentences; eg
ci) stands for Change what’s Inside parentheses. Here,
i) is a text object: it “selects” some text and pass it back to the command.
Most text objects constructors are actually motion commands:
d$ uses the motion command
$ (end of line) to create an object “from the point to end of line” and pass it back to delete. But some text object constructs aren’t motion commands:
p are text objects only (sentence, paragraph).
I believe motion commands and text objects could be implemented as Elisp functions which take a parameter
nil and return a pair of integers, the buffer positions of the objects’ boundaries (probably using the thing-at-point library).
(require 'thingatp) (defun divine-textobject-sentence (around) ;; ... )
Then, we should allow duplication between the “awaiting-text-object” hydra and the basic god-mode bindings. Avoiding such a duplication may be elegant, but may also lead to useless pain.
I believe commands working on text objects
- Whether there’s an active region.
- If yes, apply the command to the active region;
- If not, run a
A few questions which will have to be solved
Here’s a short list of things that may be difficult to implement.
“Inside” and “around” prefixes to text objects
This may be hard to deal with. A solution would be:
Run an initial
divine-hydra-around-insidehydra with two heads
i, and from it, simply assign some variable or return some value.
Then call the main “text object” hydra.
For this point and the next, see also “Don’t use hydras?” below.
In Emacs, most editing primitives can operate on the current line when being called with their binding as text object constructor.
yy yanks (copies) the current line,
dd deletes it, and so on. This may be hard to implemented on simple hydras.
Where commands such as
12dw should be easy to implemented,
d12w is also legal in Vim, and would be really nice to have. This may not be that hard: if we use native text objects as motion commands, they should understand digit arguments already.
Don’t use hydras?
Hydras are meant for high-level, interactive functions. Maybe using Emacs’ native
(read-char) would be really easier.