M-x apropos Emacs
Table of Contents
Emacs keymaps can have helpful and even dynamic prompts
Published: on Mastodon.
. Comments
Nowadays M-o
is unbound in Emacs by default, but it used to be used
for changing fonts in enriched text mode buffers. Enriched text is
what I consider an obscure format that Emacs supports pretty well for
some reason. I think rms had hopes of basing some Emacs word
processing functionality on enriched text, but I’m a little hazy on
the history —which I’d love more knowledgeable people to educate me
on. Enriched text (not to be confused with Microsoft’s Rich Text
Format) is the MIME text/enriched type defined by internet RFC 1563.
In Emacs its supported by the built-in enriched
library —see
(finder-commentary "enriched")
.
Now that M-o
is unbound by default, I recommend binding it to
other-window
and turning off repeat-mode
for that command with (put
'other-window 'repeat-map nil)
so you can switch to another window and
type a word starting with “o” without trouble —therwise you wind up
with an o-less word in the next window! In fact, I already used that
binding back when M-o
was used for enriched text fonts.
But enough rambling, the reason I’m talking about this is that back
when M-o
was bound to facemenu-keymap
, pressing it would show this
message in the echo area:
Set face: default, bold, italic, l = bold-italic, underline, Other…
That’s right: M-o
was bound not to a command, but to a keymap, and
pressing it would show a message in the echo area!
One day redditor sebhoagie, asked how to display a dynamic message
when a keymap is active, and I had that curiosity about M-o
filed away
in my brain. I didn’t know what exactly M-o
was bound to at that point
in time, but I did now it was a keymap, because I had attempted to use
C-h c M-o
only to have describe-key-briefly
wait for more input. So I
set out to find out how that keymap did its magic. I ran emacs -q
,
found out what M-o
was bound to by default (recall that I was using it
for other-window
), and here’s the result (this is mostly what I wrote
on reddit back then, with the code modernized a bit):
You can add a prompt for the prefix keymap when you create it, and also prompts for the individual keys bound in the keymap! For example, the following code defines a keymap for package-related operations:
(defvar-keymap pkg-ops-map :name "Package" "h" '("describe" . describe-package) "r" '("reinstall" . package-reinstall) "a" '("autoremove" . package-autoremove) "d" '("delete" . package-delete) "i" '("install" . package-install) "l" '("list" . list-packages)) (keymap-global-set "C-c p" pkg-ops-map)
(Here I’m using the recent family of commands, macros and functions
for dealing with keymaps, keymap-set
and friends from keymap-el
, which
only accept the key description strings that kbd
uses; I recommend
these above the older define-key
and friends.)
Now, as soon as you press C-c p
the following message appears in the
echo area:
Packages: list, install, delete, autoremove, reinstall, h = describe
Notice that Emacs cleverly noticed that for the key h
you gave the
prompt “describe”, which does not start with h
, so it actually prints
h = describe
. The other prompts do start with the letter they are
bound to, so Emacs just lists the prompt you gave.
Of course, if you don’t give a prompt for a binding, it’s not
mentioned in the overall prompt for the keymap, but the key is still
bound. For example, if you replace '("reinstall" . package-reinstall)
with a simple 'package-reinstall
in the above code, then the prompt
will change to:
Packages: list, install, delete, autoremove, h = describe
but r
will still be bound to reinstall-package
.
Now, sebhoagie said that they had an application in mind for which they wanted the prompt to change dynamically, so this trick wasn’t good enough. And I remember thinking: “Emacs Lisp is super imperative, I bet keymaps are mutable!”. I was right and as a proof of concept I cooked up this little example:
(defvar count 0) (defvar-keymap counter-map :name "Dynamic counter!" "i" '("increment" . inc-counter) "r" '("reset" . reset-counter)) (defun update-counter-map-prompt () (rplaca (last counter-map) (format "Counter is at %d!" count))) (defun inc-counter () (interactive) (setq count (1+ count)) (update-counter-map-prompt)) (defun reset-counter () (interactive) (setq count 0) (update-counter-map-prompt)) (keymap-global-set "<f5>" counter-map)
After running that code, try <f5> i
a few times to watch the counter
increment or <f5> r
to reset it back to zero.
If you are a keymap description you might think you are set for life and
just kick back and relax, but you are as rplaca
-ble as anyone else.
My quest for completion
Published:on Mastodon.
. CommentsThis is the entry I would have written for the “Take Two”-themed Emacs carnival if it had taken me less than a month to decide to participate. It’s about all the myriad minibuffer completion UIs I’ve been through as an Emacs user, and is quite long because I’ve tried so many!
Just to make sure we’re on the same page: Emacs commands prompt for
user input in the minibuffer and offer completion, which means some
sort of assistance typing sensible inputs. There are many possible
user interfaces for this in Emacs and I’ve tried many but all of them
(By the way, this is a constant in my Emacs usage: I try many but not
all of the options, since there are always too many. For example, of
the built-in ways to list buffers I’ve used switch-to-buffer
, ibuffer
,
electric-buffer-list
and several third party options —I currently
use consult-buffer
from the Consult package— but I’ve never tried
the built-in bs-show
, for example. Similarly, of the built-ins I’ve
only used GNUS to read email and RSS feeds, but never tried Rmail for
email or NewsTicker for RSS; let alone trying all third party options
—I did use mu4e for email for a bit and elfeed for RSS feeds!)
Just so this doesn’t take forever to write, I will write it all from memory, and let people correct me on details I get wrong —it’s only fair since I do that to other people all the freaking time (it’s a wonder I have any friends). This list attempts to be in chronological order of my usage, but I’m sure I’m getting some of this slightly wrong (and fortunately no-one is likely to be able to call me out about errors in the ordering of my personal usage of these UIs).
Default completion
In my early days as an Emacs user I simply used the default completion
UI. This UI doesn’t not show the completion candidates all the time.
If all the candidates have the next bit of text in common, pressing
TAB inserts it into the minibuffer (people call this TAB completion).
I’ve always found this funny since it makes zero progress towards
choosing a single completion candidate: it only inserts as much text
as will not narrow down things at all! But people like it for some
reason, I guess as visual feedback that what you thought the
completion candidates had in common they really do have in common. (To
be fair you can configure completion-cycle-threshold
to have TAB cycle
among candidates when there aren’t many left.)
Pressing TAB a second time will pop up the *Completions*
buffer, which
shows a list of all completion candidates. From there you can click on
a candidates, navigate to it and press RET, or just type some more and
press TAB again to get an updated candidate list.
Don’t knock the default completion UI. It is functional, powerful and perfectly usable out of the box. But most people want to see how the available candidates change automatically as you type. The other UIs I tried all have that feature in common; they also all have a notion of the “current completion candidate”, and there is a way to select that current candidate without finishing typing it —usually but not always this done simply by pressing RET.
Ido
Ido also comes with Emacs and is pretty funky. For one thing it
doesn’t take over all minibuffer completion services, it only provides
special versions of certain commands, mainly to open files and switch
buffers. Those commands also enable some additional key bindings while
you are using the commands: while opening a file you can press a key
to delete a file, or while switching buffers you can press a key to
kill a buffer. This sort of thing is called “acting on a completion
candidate”, and boy do I like it —more about this later. Ido uses
fuzzy completion, where characters only have to appear in order in a
completion candidate, not necessarily consecutively; for example epnf
matches eww-open-file
.
If you like Ido but want to use it for all minibuffer completion there
are some options: there’s the ido-completing-read+ package and the
built-in fido-mode
. I don’t particularly like fuzzy matching since it
feels inefficient to me, there are always two many matches for my
taste.
Helm
Helm is a comprehensive package that not only takes over all minibuffer completion duties but comes with many commands that take advantage of Helm’s additional features. It’s big and brash and opinionated. I used it for many months and was quite happy with it. I particularly liked that the Helm commands came with many actions you could perform on the completion candidates. I didn’t much like its default aesthetics or its long load time (although since you only incur that once per session it doesn’t really matter). One thing I didn’t like much is that somehow it didn’t seem to blend in very well with the rest of my Emacs experience. For example, only commands written specially to use Helm had actions for the completion candidates, and the actions had to be implemented in a particular way, you couldn’t use any old Emacs command as an action. But all in all Helm is great, an impressive piece of software that sprouted its own mini-ecosystem of related packages.
Ivy
After Helm I used Ivy and its companion Swiper and Counsel packages
for a while. It felt pretty similar to using Helm to me, except I
liked the default look of it better (which is not to say you couldn’t
easily configure the visual aspects of Helm). It also had a notion of
actions, but similarly to Helm, you needed to write them specially for
each command. I think it was less batteries-included than Helm, for
example I have a vague recollection of counsel-find-file
, its
substitute for find-file
, not coming with actions to rename or copy
files, which I wrote in my own configuration. It’s then that it
started to bother me that I couldn’t simply say “I want the Emacs
commands rename-file
and copy-file
as actions”, I was forced to write
little wrappers for them. Like Helm, I think the Ivy/Swiper/Counsel
family is great software and was a happy user. I did however, as I did
with Helm, that it reinvented the wheel too much and that something
like it would be possible that took more advantage of existing Emacs
APIs and functions.
Icomplete
This is another built-in option, which I think I only started using
after having used Helm and Ivy. I used it for a quite a while and
still think it is perfectly workable. One thing I like about it is
that, like the default completion UI, it only concerns itself with
displaying the completion candidates and leaves the important matter
of which candidates are considered to match the minibuffer input to
the current completion styles. There is no formal notion in Emacs of a
“well-behaved” completion UI, but in my head certainly such a UI
should limit itself to showing you the candidates and leave the user
to configure completion styles separately. This what I dislike about
fido-mode
: it ignores your completion style configuration and makes
you use the flex
completion style instead (you can change this but it
requires being sneaky, not simply setting completion-styles
).
One difference between Icomplete and Helm or Ivy, is that it displays the completion candidates in a compact horizontal list like Ido, instead of one per line, like Helm or Ivy. When I was an Icomplete user, I even wrote a package called icomplete-vertical that would configure Icomplete to display the candidates vertically, one per line. Nowadays there is also a built-in package of the same name which I did not write, nor does it use my code. I remember thinking the built-in package had a bug mine lacked, triggered when you switched from horizontal to vertical during a minibuffer completion session, but I couldn’t reproduce it now so either they fixed it, or I couldn’t remember exactly what the bug was, or my memory is playing tricks on me.
live-completions
The mention of icomplete-vertical above is the start of an embarrassing parade of completion UIs I wrote myself, for myself and which I don’t think more than a handful people ever used. What marred all of my feeble attempts, other than icomplete-vertical which is just some configuration code on top of icomplete, was a distinct lack of speed. The idea of these incremental, automatic completion UIs is to show you how the candidate list changes in real time, but most of mine struggled to do this fast enough.
My live-completions package had a very simple idea: pop up the
*Completions*
buffer that the default UI uses and just update it after
every key press. It let you format the completions in either a grid or
a single column, back before the default UI had the single column
view.
I think I used this for quite a while though it wasn’t very good. I believe that by the time I wrote this, I already had an initial version of Embark that took care of acting on completion candidates solving all of the complaints I had about actions in Ido, Helm or Ivy: Embark lets you use any Emacs command directly as an action, there is no need to write wrappers over existing commands; it endows every single command that has a minibuffer prompt with actions on its candidates, commands do not have to be written specially with Embark in mind to acquire actions.
grille
Another bad completion UI I wrote. Hey, at least it’s small. I don’t think I used this for very long, maybe a couple of weeks. It’s called grille because it displays completions in a grid. I have nothing else to say about it.
embark-completions
For a while Embark included its own completions UI! This is obviously a bad idea, which I only did because it was easy, since Embark had grown to have almost all the components necessary for this. It was slow, but other than that I found it surprisingly good. It was certainly featureful: it displayed the completions either one per line or in a grid, the grid optionally with zebra stripes to guide the eye. I stubbornly kept using it until I dropped it for Vertico and finally removed it from Embark.
Vertico
The excellent Vertico package is what I use now as a completion UI. The author, Daniel Mendler, and I have long worked together on a suite of packages that provide a full completion experience for Emacs. I wanted to switch from embark-completions to Vertico but held out until Daniel added a grid display to Vertico. In retrospect this was silly on my part, but I believe my stubbornness might have helped motivate Daniel to add the grid feature. Of this suite of packages, Daniel wrote Vertico, Corfu, Cape; I wrote Embark and Orderless (the latter of which we now co-maintain); and we wrote Marginalia together after noticing we were both writing something like it.
- Vertico
- a highly flexible completion UI, that can display completions one per line or in a grid, in the minibuffer or in a dedicated buffer.
- Orderless
- a highly configurable completion style, whose main
feature is matching space-separated bits of the input in any order
against the completion candidates; so
op eww
matcheseww-open-file
. - Embark
- lets you use any Emacs command as an action on any
minibuffer completion candidate or on a thing at point in a non-mini
buffer; it also comes with an extensive default configuration
assigning convenient keybindings to the most commonly used actions
(but you can always
M-x
to use whatever command you want as an action!) - Marginalia
- provides extra information about completion candidates of common types, most completion UIs that display candidates as one per line will shows this extra information to the right of the candidate.
- Corfu
- this is a completion UI for completion-at-point, which I
haven’t talked about here at all —it is the type of completion
that you get when writing code in a buffer, for example. Again here
I stubbornly held out a long time using my own contraption
(
consult-completion-in-region
, which I contributed to consult). - Cape
- a suite of completion-at-point functions; again I stubbornly held out using an embark-based substitute for this for a long time —I’m starting to notice an unflattering pattern.
Selectrum and MCT
I already finished listing the completion UIs that I actually used for
a period of time, but there are a couple of others I tried and
probably some I did not try (maybe snails, though I’m not exactly sure
what it is, since I’ve only every briefly skimmed its README). I tried
Selectrum once and, to my discredit, only complained about some minor
issues with it on reddit. At least I’m focused thematically in my
complaints: I thought it wasn’t Emacsy enough, that it disrespected
some Emacs variables it could easily respect. Well, that, and there
something I didn’t like about its completing-read-multiple
experience
(I think it was that you couldn’t easily see what you had already
selected). I never used Prot’s MCT package extensively, but I would
call it similar in idea to my live-completions package, and would hope
Prot does not disagree with this characterization. It somehow seemed
smoother than my live-completions, probably because Prot had more
patience tweaking the experience than I did.
Welcome to M-x apropos Emacs
Published:
.Recently Christian Tietze called for Emacs blog posts with the topic “Take Two”, meaning things that took two or more tries to get right. He also said:
Don’t have a blog, yet?
Well, just start one already! :)
It’s the future of the internet!
I mulled over this the whole month and finally decided to start a blog about Emacs just in time to miss that first round of the Emacs carnival! (I’m likely to miss deadlines like that again in the future.)
Now, about twenty years ago, when blogs did actually seem like the future of the internet, I had one on a hosted service. I think I may have started on Blogspot, but then moved to Wordpress.com. It was a personal blog about whatever random topic I wanted to write about. I did not write very frequently on that blog, and am unlikely to write often here either, although maybe constraining the topic to Emacs might inspire me more than having no constraints did.
I was already an Emacs user back then, but I wasn’t as gung-ho about it as now, and back then I meekly accepted Wordpress making all sorts of decisions for me, which seems cowardly today; so I definitely want a more Emacsy way to write this new blog. I figure all a blog needs is a publicly accessible web page and a publicly accessible RSS feed. An important optional component is a system for comments. So, to do the easiest thing possible, I will write my blog in a single Org file (for now, I’ll manually paginate if it turns out I do keep it up!), use ox-rss to create an RSS feed, and for comments I’ll just use Mastodon.
Since I threw this together in about ten minutes, I’m sure there will be bugs. I probably don’t have permalinks correct at all.