Rethinking Minibuffer Movement
18 Dec 2024 Charles Choi
For your consideration, a possible quality of life improvement in using Emacs. Typically the next-to-the-smallest unit of point movement is by word. This is reinforced by binding M-f
and M-b
to forward and backwards word movement respectively.
When editing prose, this is sensible. For editing code and commands, I would argue this is less so. This is because the unit of text I most want to move by is via symbol. Common examples of symbols include variable/function/class names, command line options & arguments, and Makefile targets. Symbols frequently embed non-alphabetic characters (e.g. ‘foo-bar’, ‘bar_foo’, ‘foo/bar’) which are treated as word-separators by the commands forward-word
and backward-word
.
Movement by symbol is what I want whenever I’m editing in the minibuffer. Muscle memory wants me to type M-f
or M-b
, which does the “wrong” thing here. But there are movement commands for a unit of text that handles symbols gracefully: that unit of text is called a balanced expression (aka sexp). By default, moving by balanced expression is bound to C-M-f
for forwards movement, C-M-b
for backwards.
Personally, I’m loathe to use keybindings involving more than two keys, so I’ve taken this tack: Swap (M-f
, M-b
) for balanced expression movement and (C-M-f
, C-M-b
) for word movement in modes that involve a lot of symbols.
Another detail to consider is moving the point so that it is at the start of a unit of text. Both forward-word
and forward-sexp
are implemented so that the point is set at the end of a text unit. In many cases this adds editing friction for me because what I really want is for the point to be at the start of a text unit. To allow for this, I’ve implemented a function for moving forward a balanced expression that places the point at the start of the next sexp (cc/next-sexp
).
Code showing the implementation of cc/next-sexp
and configuring the minibuffer to swap the bindings for word and sexp movement is shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
The same swap can be applied when calling eval-expression
(M-:
). The keymap to configure here is minibuffer-local-shell-command-map
.
1 2 3 4 |
|
Why stop there? Let’s change it for Elisp mode:
1 2 3 4 |
|
This idea can be extended to other modes such as Eshell.
Closing Thoughts
I’ve been living with this setup for a month now and anecdotally I’ve found this to feel “right” enough to merit making a post. For those readers who do not consider this post’s suggestion heretical, I’d encourage to give these changes a try. Perhaps you’ll find yourself pleasantly surprised.