Delete the Next Word or the Current Selection in Emacs with the Same Shortcut
When you delete a character or the current selection, you usually hit C-d
(Control + d) in Emacs.
I got into the habit of revising drafts by deleting whole words, and the M-d
(Meta + d) key combination is super useful for that. It also works into the other direction with backspace. It’s essentially the same effect of ⌥+backspace everywhere else in macOS.
When I delete words with these shortcuts for a while, I get into the habit of reaching for that key combo a lot. Deleting and rewriting words is often times faster than carefully positioning the insertion point inside an existing word to fix it, especially if you’re accustomed to 10-finger-typing.
Problems arose whenever I wanted to delete a selection, though: when I want to select a couple of words, I enter the “selection mode” and then expand the selection forward a couple of words using M-f
(Meta + f, for “forward”); it’s like ⌥+rightarrow on macOS. With the thumb already on the Meta key, I usually just leave it there, press down, and hit “d” to delete – but by default, emacs would delete the next word after the end of the selection instead of the selection itself. This bummed me every single time.
So here’s a fix.
The default M-d
key binding calls the interactive function kill-word
:
(defun kill-word (arg)
"Kill characters forward until encountering the end of a word.
With argument ARG, do this that many times."
(interactive "p")
(kill-region (point) (progn (forward-word arg) (point))))
It kills (aka deletes and puts into the kill-ring/clipboard) everything from the current point
up to the next word, determined by forward-word
. The actual call forwards the numerical argument from the key binding, so you can press C-u 10 M-d
and delete the next 10 words this way; that’s what the progn
call and stuff is for.
Now I want to add an option to delete the current selection if there is any; if not, proceed with the default behavior. My simple wrapper is this:
(defun ct/kill-word (arg)
"Kill characters forward until encountering the end of a word, or the current selection."
(interactive "p")
(if (use-region-p)
(delete-active-region 'kill)
(kill-word arg)))
(global-set-key (kbd "M-d") 'ct/kill-word)
use-region-p
is a test if there is currently any selection active;delete-active-region
deletes the selected range
If you pass any non-nil argument to delete-active-region
, you toggle a flag where the removed content is put into the kill ring (aka clipboard) instead of just being discarded. The value could be anything, really anything: t
for “true”, the numerical value 1
, an empty list ()
, a non-empty list with the names of your favorite pop songs from the 80s, or any string, like 'kill
, which I find makes this flag very readable. (I hate to guess what positional arguments do.)
There you go, problem fixed. Happy (manu)script editing.