Emacs: Friend or Foe?

Now, what about bindings involving multiple keys? For
example, I like to use the key sequence C-d C-d
to delete a line (somewhat like its vi
counterpart), and C-d g to delete text from
point to the end of the buffer. The second argument to
global-set-key can include multiple keys, but
the problem is that C-d already has a meaning.
We want to use C-d as a “prefix” key for the
commands C-d C-d and C-d g,
so first we have to unbind C-d. Here's what we
do:

We simply use global-unset-key to unbind
C-d, and then bind new meanings to C-d
g and C-d C-d. However, these
functions are bound to the mysterious functions
my-nuke-to-end, and
my-nuke-line, which the astute among you will
notice aren't standard Emacs functions. We have to define
them.

Defining a new function

Defining an Emacs LISP function is rather simple. Of course,
Emacs functions can be quite powerful and complex, but in this case
we're going to use the function to call a short sequence of other
functions, which isn't so frightening. In general, if you need a
key binding to call several functions in sequence, you must define
a new function to wrap the sequence in.

Here is the definition of my-nuke-to-end,
which should be placed above the corresponding call to
global-set-key, which uses it, in the
.emacs file.

The defun function takes as arguments the function name to
define, a list of arguments (which, here, is empty), followed by
the body of the function. Note that the first line of the body is a
string constant, which is a short description of the function. This
string is displayed when describe-key or
describe-function is used to display information
about my-nuke-to-end.

The second line of the body is a call to the
interactive function. This is required for
functions that are bound to keys. It simply tells Emacs how to
execute the function interactively (that is, when called from a key
sequence). The argument to interactive, “*”, indicates that the
function should not be executed within a read-only buffer. Check
out the documentation for interactive if you
want the gritty details. (See the sidebar “Getting the Emacs LISP
Manual” for information on obtaining this documentation.)

The last line of the body uses the Emacs internal function
kill-region to delete a region of text. The two
functions point and point-max return the current
location of point, and the position of the end of the buffer,
respectively. kill-region deletes the text
between these two locations.

The definition for my-nuke-line is
somewhat more involved, because there is no single Emacs function
that this operation maps to. Here it is:

First of all, we see that this function now takes an
argument, which we have called arg. Many Emacs
key functions take a single numeric argument, which you can specify
by prefixing the key with C-u, followed by a
number. (That is, unless you've rebound C-u, as
we have.) This numeric argument changes the behavior of certain
functions. Here, arg is passed along to
kill-line, used on lines 4 and 9 of the function
body.

my-nuke-line is essentially a wrapper for
kill-line, but takes care of a special case for
the last line in the buffer. In this case, we want to delete the
newline before the last line, which causes the last line to be
clipped out altogether (otherwise, Emacs deletes the line, but
leaves a blank one in its place). After
interactive is called (with the “*p” argument,
which causes arg to be converted to a number),
beginning-of-line moves point to (surprise!) the
beginning of the line. kill-line is then
invoked. Note that kill-line only kills text
from point to the end of the line; not the entire line.

Next, we compare the cursor position (point) with the
end-of-buffer position (point-max). If they are
equal, then we are trying to delete the last line of the buffer,
and want to kill the previous terminating newline. We move back a
line (using forward-line with an argument of
-1), move to the end of that line, kill the rest
of the line (which consists only of the terminating newline), and
move back to the beginning of the line. All of this results in the
last line of the buffer being deleted.

I'm sure that there are Emacs gurus out there that can find
much better ways to accomplish the same thing; please bear with me.
I've been brainwashed by vi. One of Emacs'
better features is that there are many ways to modify its
behavior.