What a year this 2020. Beside the pandemic changing our lives in unpredictable
ways, from the perspective of my Emacs usage much was going on in my init.el
until I felt that a temporary break was
necessary.
Most of my tinkering concerned the minibuffer and its completion mechanisms. I finished last year and started this one with Helm, but I am about to close 2020 with the built-in minibuffer completion and Embark providing candidates. A solution that Protesilaos Stavrou explored and which has been really suiting me.
Before detailing how I adapted his approach to my preferences, though, let me give you a bit of rationale. First, Helm rocks and it rocks hard. Its power is evident after a couple of hours with it. I briefly used Icomplete tweaked to display its results vertically, but I didn’t find it responsive enough to stick with it. Then I found out about Selectrum, which fixed the responsiveness but eventually was not adding a significant difference compared to Helm. True, Selectrum has a simpler codebase, but were I only to look at my daily interactions with Emacs, only the user interface can tell Helm and Selectrum apart.
Protesilaos took a different path. He wants to understand the code in front of him, so the less changes the better. In this regard Helm, Selectrum, and even Icomplete add a layer of indirection between him and the minibuffer. He is right in this. The minibuffer is more capable than the plethora of completion frameworks may suggest, and one can leverage its strength without forcing it to behave in a totally new way. Protesilaos’ reasoning got me thinking. Once again, am I looking for a solution from the outside before having really understood what lies underneath my beloved text editor?
Following Protesilaos’ steps, I set up the minibuffer to rely only on
orderless and Embark, with
Consult chiming in for a some of operations
like better history in shell-mode
and an improved apropos
. What I added to
Protesilaos’ code is the only thing that I felt was missing: a command to search
for the symbol at point in my project, with the results displayed in an
embark-live-occur
window in order to quickly jump to a specific entry. Over at
the Consult’s GitHub there are talks about a consult-rg
utility which would
serves this purpose, and there has been suggestions of using
project-find-regexp
as well.
(defun mu-project-find-refs ()
"Use `project-find-regexp' to search for thing at point."
(interactive)
(if-let (tap (thing-at-point 'symbol))
(project-find-regexp tap)
(message "Nothing at point to search for")))
Easy enough to understand. However, if you, like me, set up Embark like
Protesilaos does you’ll notice that this command doesn’t show any candidate
unless you type something at the Jump to definition
prompt. The candidates are
there already, though, so I have to avoid waiting for an input and display the
candidate list immediately.
The solution is straightforward: just remove embark-live-occur-after-input
from minibuffer-setup-hook
and use embark-live-occur-after-delay
instead.
I added a :before
advice on mu-project-find-refs
for this. The beauty of
this advice is that it works elsewhere as well. For instance, I have been using
it for consult-flymake
and flyspell-correct-at-point
too.
Note that this advice requires a little change to the original
minibuffer-setup-hook
I have lifted from Protesilaos. Instead of adding
embark-live-occur-after-input
to it I am using this to ensure only
embark-live-occur-after-input
is present.
(defun mu-embark-live-occur-after-input ()
"Ensure only `embark-live-occur-after-input' is active."
(remove-hook 'minibuffer-setup-hook #'embark-live-occur-after-delay)
(add-hook 'minibuffer-setup-hook #'embark-live-occur-after-input))
Without a dedicated completion framework the minibuffer may feel rather basic at
first, but do not let it deceive you with its frugality. Like project.el
, all
it needs is love.