macOS keybinding tricks: The kill ring
So you may have seen my KeyBindings project before. It’s an insanely large collection of keybinding tricks that work in any macOS text field. Well, any native cocoa field. You won’t have much luck in Electron or other non-native text editors. But for most uses, including in Safari, Mail, Notes, nvUltra, and most of the Markdown editors, the tricks work great. You can do things like adding TextMate-style ⌘⏎ to any editor to create a new line no matter where your caret1 (cursor) is in the line.
I’ve written a bit about all of this before (and see the KeyBinding series), but I’ll recap the basics for this tip, since it’s been a while. To wit, you can create a (plain text) file located at ~/Library/KeyBindings/DefaultKeyBinding.dict
that tells every macOS app what to do when you hit certain keys, and you can override all kinds of defaults and add new functionality by editing it. If that file already exists, you can just add to it. I’ll offer more details when we get to that part of the trick.
Emacs Keybindings
You already have emacs-style shortcuts available, including ⌃K to delete (kill) to end of line, ⌃U to delete to beginning of line, and ⌃Y to paste (yank) text that was cut using either of the kill commands. You can delete an entire line by hitting ⌃A (go to beginning of line) and then ⌃K, then paste that line somewhere else with ⌃Y. Try it. You don’t have to do anything to enable this, it’s always been built into macOS. I think it also works on iOS, but I don’t have an external keyboard hooked up to test it out with right now. Let me know in the comments.
Bonus tip: ⌃T will transpose the characters to the left and right of the caret, allowing you to easily change frutive to furtive with one keystroke.
So this tip is a way to make this cut/paste process more useful. You’ve probably used (or at least seen) clipboard managers before. I use LaunchBar for this, but there are plenty of apps like Paste that can do it. Basically every time you cut or copy something, it gets added to a list in your clipboard manager, allowing you to paste anything you’ve copied elsewhere, rather than just the last thing you copied. I wouldn’t want to function without one. Those apps don’t work with the kill commands, though. So here’s what you can do instead.
Create the Kill Ring
First, run this command in Terminal:
defaults write -g NSTextKillRingSize -int 6
That creates a “kill ring” with 6 slots. Every time you cut, the text will be stored in the next available slot, cycling back to the beginning when the 6 slots are full. You can make that number anything you want, but be aware that to use items stored in the kill ring, you’ll have to cycle through them until you get to the one you want, and empty slots will still have to be cycled through. Which generally would mean pasting them all in a row, which is where the next part of the trick comes in.
Edit the Keybindings
- If you already have a file at
~/Library/KeyBindings/DefaultKeyBinding.dict
, open it in a text editor and add the keybinding inside of the main curly brackets that already exist in the file. If you don’t have that file, create a new, empty text file in your text editor of choice. -
If you’re working with an empty file, first insert a pair of curly brackets before inserting the text below. If you already have an existing
DefaultKeyBinding.dict
file, then just add the following between the existing parent curly brackets:"^y" = (yankAndSelect:);
- Save the file (as
~/Library/KeyBindings/DefaultKeyBinding.dict
if it’s new). - Running apps will need to be restarted to recognize the new keybindings.
In this circumstance, “yank” means “paste” from the register, as opposed to the Vim vernacular where it means “copy” (which makes more sense 🤷🏻♂️). So now, pressing ⌃Y (“^y”) will paste the next item from the kill ring, and immediately select it (yankAndSelect:
), so pressing ⌃Y again will overwrite what you just pasted with the next item in the kill ring. If there are registers in the kill ring that haven’t been filled yet, it will paste an empty string, but you can just keep hitting ⌃Y to cycle back around to where your populated registers are.
Note: The kill ring is shared between documents in the same app, but generally not between apps.
To try it out, restart your text editor (if it was running when you changed the DefaultKeyBinding.dict
file) and write several lines of text in a text field:
this is line 1
this is line 2
this is line 3
this is line 4
Put your caret at the beginning of each line and press ⌃K, once for each line (use arrow keys and ⌃A to get to each line start). Then, put your caret anywhere and type ⌃Y repeatedly. You should see your cut lines pasted and replaced in place. Note that these commands do register in the undo buffer, so if you cycle past the one you wanted, you can usually use ⌘Z to go backwards through the list. The kill ring is LIFO, so you’ll get your results in the reverse order you added them to the ring.
Have fun! If that was interesting to you, be sure to check out the rest of the KeyBindings project.
-
I’ll be referring to the text insertion point as a caret in this post, just because I’m feeling pedantic today. ↩