A better yank-pop binding

Update (2021-05-18): The inimitable Sacha Chua informs me that the functionality proposed in this post is already included in Emacs 28. If you’re using Emacs 27.2 or older, keep reading!

Update (2021-05-16): Daniel Mendler, the author of the Consult library, points out that this functionality is also built into Consult as well as Ivy+Counsel. If you’re using these, check out consult-yank-pop (or equivalent) instead.

A quick tweak to yanking in Emacs: Many completion systems provide a more fully featured version of yank-pop to yank text from the kill-ring. Ivy/Counsel has counsel-yank, Helm has helm-show-kill-ring (I assume) and Consult provides consult-yank. These show you items in the kill ring and let you select, with completion, which block of text you would like to yank (i.e. paste) into the buffer.

Here is Consult’s version, previewed in an Embark live-occur buffer:

This is quite useful when you know you copied something a while ago and want it inserted in your buffer now, but it involves navigating through a menu for something that could be near-instantaneous.

In comparison, Emacs’ built-in yank-pop command (bound to M-y) simply cycles through the kill ring, pasting the next item with each invocation, provided you call it after a yank. The idea is that you hit C-y first, and if this isn’t what you intended to paste you can repeatedly type M-y (or call with a prefix argument) until you see what you want on the screen. This sounds circuitous, but in practice it takes than a second when I want something that’s within the top three or four positions in the kill-ring, i.e. something I copied moments ago.

This approach is less than optimal in two ways:

  • The intended target text to be yanked is buried deep in the kill-ring and requires several presses of M-y. In this scenario consult-yank et al are a faster solution.
  • You call yank-pop without yanking (with C-y) first. Then yank-pop complains and does nothing.

The shortcomings of both approaches can be fixed with a little change in the behavior of yank-pop:

  • When called by itself (pressing M-y without pressing C-y first), call consult-yank to get the kill-ring as a menu. You do this when you know the text you copied a while ago is buried somewhere in the ring.
  • When called after yanking, run yank-pop as usual. If you pressed C-y first, you know the text you want is at or near the top of the kill-ring so Emacs’ default behavior makes sense.
(defun my/consult-yank-or-yank-pop (&optional arg)
  "Call `consult-yank'. If called after a yank, call `yank-pop' instead."
  (interactive "*p")
  (if (eq last-command 'yank)
      (yank-pop arg)
    (consult-yank)))

Replace consult-yank with your completion system equivalent.

Binding this to M-y ensures that you don’t need to build new muscle-memory, and that yanking now works in a somewhat DWIM fashion. In addition, this has the nice effect of assigning M-[key] to the advanced version of the C-[key] command, an irregular but somewhat prevalent aspect of the keybindings in Emacs.