Advising Emacs
One of the delightful and surprising things about Emacs, as you get to know it better, is the depth of customisation which is available. Emacs can be a completely different editor for different people and for different purposes. Being able to tweak things on the fly and try them out before you commit to them, or even as a temporary fix to solve the particular problem you have right now, is empowering. The more you delve into it and try things out, the better you understand what is possible and the more comfortable you get with writing elisp. Recently I discovered the ‘advice’ system in Emacs, and now every problem looks like a situation for some well-placed advice!
Learning to simplify
Most of what I’ve learned comes from reading articles by Emacs users or
scrutinising their Emacs config files. I’ve found a treasure trove of handy
snippets and videos about Emacs which are produced by Protesilaos Stavrou (“also
known as Prot”, according to his videos). As far as I understand it from his
YouTube channel, he has only been using Emacs for a year or so, but he seems to
have made incredible progress in understanding it, and adapting it to his needs.
He has even released a pair of beautiful themes, modus-operandi
(a light theme)
and modus-vivendi
(dark) which meet accessibility standards for visual contrast.
I’ve started using these as they are extremely well-thought out and include
specific configuration for a huge range of packages.
His setup is ‘vanilla’ Emacs, in the sense that he does not use a framework like Doom Emacs or Spacemacs. While he does use some third party packages, his approach is to see how close he can get to the behaviour he prefers by leveraging Emacs’ built-in tools and tweaking them with his own customisation. While I am not planning to move away from Doom (because I love it), following the same approach has been a very useful one for me, especially since I disabled evil bindings in Doom. Reading his posts, watching his videos and looking at his comprehensive and well-annotated dotfiles, I have worked through my own configuration, thinking about how to simplify and improve my everyday experience with Emacs, and have learned some useful stuff along the way.
Advising the case-changing functions
Boon has some useful bindings for changing the case of words (or regions), but I also wanted to get more familiar with Emacs’ own bindings and commands for doing this. I found them initially frustrating, because the commands require you to move first to the beginning of a word before changing the case. This makes sense in that the cursor (or ‘point’ as it is known in Emacs) then ends up at the end of the word and you can continue typing or editing your text. However, it feels awkward to me, as I usually want to type a word lower case (I actually don’t have a caps lock key anymore) and then immediately upcase the preceding word.
Looking around, I found an example of how to fix this behaviour, and in the process, learned about Emacs’ advice system. This is a kind of arbitrary hook system, which works on any function. The idea is that you write some code, and then ‘advise’ Emacs to run that code before of after a particular function (which can be built-in or third party). In this case, I am advising the case changing functions in order to modify how the point is moved before they do their work. I could of course just write my own wrapper function around the case functions and bind a key to that, but the power of advice is that it is called on whenever and however the advised function is called. So if some third party bit of code also calls on the built-in case functions, my advice will also automatically be applied. It is as if I have changed the built-in command.
The example I found used the old form of advice (which still works I think, but is outdated), so I found this article by John SJ Anderson which was very helpful in understanding how to use the new advice syntax, and also let me clean up the code a bit. This is what I ended up with:
(defun my/word-start-dwim (&rest args)
"Go back to the beginning of the word if the point is not there.
Ignores `ARGS'. This function enables dwim case changes."
(unless (looking-back "\\W")
(backward-word)))
(advice-add 'upcase-word :before #'my/word-start-dwim)
(advice-add 'downcase-word :before #'my/word-start-dwim)
(advice-add 'capitalize-word :before #'my/word-start-dwim)
The command now ‘does what I mean’: if I am at the end of the word or in the middle of it the point moves to the start of the word, but if I am at the start of the word already (i.e. there is a non-word character before the point) it doesn’t move the point. I use these commands all the time now, as they are so much more useful to me than before. I’m sure that it could be improved, and there is some edge case which will make it fail, but so far it has worked the way I expect.
Hey navi - put my windows back!
Prot has some very nifty customisations for imenu
and outline-minor-mode
which I
have re-purposed. I have a binding to open a vertical ilist
buffer, which has a
linked outline of the headings in an org-mode
buffer, so I can get an overview
and move around large files easily. His customisation to outline-minor-mode
does
a similar thing for code buffers, using comment markers to form the outline.
Unfortunately, I could not get his method to work for me for some reason, but I
found outshine and navi, which together gave me the behaviour I wanted. Navi
provides a nice side window with a navigable outline, but it irritated me that
when I quit the window it left behind a split window, rather than putting my
windows back is it found them. Sounds like a job for advice!
(use-package! navi
:init
;; put windows back as they were after navi quits
(advice-add 'navi-quit-and-switch :after #'winner-undo)
:bind ("<f10>" . navi-search-and-switch))
Here, I just advise the navi quit window command that it should call
winner-undo
, which then puts the windows back how they were before. If you use
use-package
but not Doom, just drop the exclamation mark and it should work.
Moving around with isearch
Prot also convinced me of the power of isearch
— not just for searching and
replacing text, but also for moving around the buffer. I used a few of his
customisations, but also modified my Ergodox to map the keys for forward and
reverse search (C-s and C-r respectively) to a pair of big keys on the inner
column of the keyboard. The right-hand one searches forward and the left one
searches backward. Having these keys so accessible has also greatly increased
the amount I use isearch
, and it has come to be one of the main ways I move my
point around a buffer, when moving longer distances.
Emacs really is a tinkerer’s paradise!