DivINE

A native “normal mode” for Emacs
12 Décembre 2016

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-y in Emacs and y in Vim, but yanking has opposite meanings in Emacs and Vim. That means that C-y means paste, y means 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 C-p into 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.

On region? Action Trivial?
a Append Yes
A Append at end of line Yes
c Yes Change Nope
d Yes Delete Nope
g Goto somewhere Nope
o, O Open line below/above Yes
u, r Undo/redo Yes
x, X Delete character 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.
Copy/paste
This should be trivial, but as I said in the introduction, the problem is that I want y to mean paste, and not copy. k can 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, p may 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: s or p are text objects only (sentence, paragraph).

I believe motion commands and text objects could be implemented as Elisp functions which take a parameter inside, around or 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

  1. Whether there’s an active region.
  2. If yes, apply the command to the active region;
  3. If not, run a text-object hydra.

This hydra

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:

  1. Run an initial divine-hydra-around-inside hydra with two heads a and i, and from it, simply assign some variable or return some value.

  2. Then call the main “text object” hydra.

For this point and the next, see also “Don’t use hydras?” below.

Repeated commands

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.

Multipliers everywhere

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.