Whenever you cut or clip text out of a buffer with a `kill' command in GNU Emacs, it is stored in a list and you can bring it back with a `yank' command.
(The use of the word `kill' in Emacs for processes which specifically do not destroy the values of the entities is an unfortunate historical accident. A much more appropriate word would be `clip' since that is what the kill commands do; they clip text out of a buffer and put it into storage from which it can be brought back. I have often been tempted to replace globally all occurrences of `kill' in the Emacs sources with `clip' and all occurrences of `killed' with `clipped'.)
When text is cut out of a buffer, it is stored on a list. Successive pieces of text are stored on the list successively, so the list might look like this:
("a piece of text" "last piece")
The function cons
can be used to add a piece of text to the list,
like this:
(cons "another piece" '("a piece of text" "last piece"))
If you evaluate this expression, a list of three elements will appear in the echo area:
("another piece" "a piece of text" "last piece")
With the car
and nthcdr
functions, you can retrieve
whichever piece of text you want. For example, in the following code,
nthcdr 1 ...
returns the list with the first item removed;
and the car
returns the first element of that remainder--the
second element of the original list:
(car (nthcdr 1 '("another piece" "a piece of text" "last piece"))) => "a piece of text"
The actual functions in Emacs are more complex than this, of course. The code for cutting and retrieving text has to be written so that Emacs can figure out which element in the list you want--the first, second, third, or whatever. In addition, when you get to the end of the list, Emacs should give you the first element of the list, rather than nothing at all.
The list that holds the pieces of text is called the kill ring.
This chapter leads up to a description of the kill ring and how it is
used by first tracing how the zap-to-char
function works. This
function uses (or `calls') a function that invokes a function that
manipulates the kill ring. Thus, before reaching the mountains, we
climb the foothills.
A subsequent chapter describes how text that is cut from the buffer is retrieved. See section Yanking Text Back.
zap-to-char
The zap-to-char
function is written differently in GNU Emacs
version 18 and version 19. The version 19 implementation is simpler,
and works slightly differently. We will first show the function as it
is written for version 19 and then for version 18.
The Emacs version 19 implementation of the interactive
zap-to-char
function removes the text in the region between the
location of the cursor (i.e., of point) up to and including the next
occurrence of a specified character. The text that zap-to-char
removes is put in the kill ring; and it can be retrieved from the kill
ring by typing C-y (yank
). If the command is given an
argument, it removes text through that number of occurrences. Thus, if the
cursor were at the beginning of this sentence and the character were
`s', `Thus' would be removed. If the argument were two,
`Thus, if the curs' would be removed, up to and including the
`s' in `cursor'.
The Emacs version 18 implementation removes the text from point up to but not including the specified character. Thus, in the example shown in the previous paragraph, the `s' would not be removed.
In addition, the version 18 implementation will go to the end of the buffer if the specified character is not found; but the version 19 implementation will simply generate an error (and not remove any text).
In order to determine how much text to remove, both versions of
zap-to-char
use a search function. Searches are used extensively
in code that manipulates text, and it is worth focusing attention on the
search function as well as on the deletion command.
Here is the complete text of the version 19 implementation of the function:
(defun zap-to-char (arg char) ; version 19 implementation "Kill up to and including ARG'th occurrence of CHAR. Goes backward if ARG is negative; error if CHAR not found." (interactive "*p\ncZap to char: ") (kill-region (point) (progn (search-forward (char-to-string char) nil nil arg) (point))))
progn
function.
point
and search-forward
.
interactive
Expression
The interactive expression in the zap-to-char
command looks like
this:
(interactive "*p\ncZap to char: ")
The part within quotation marks, "*p\ncZap to char: "
, specifies
three different things. First, and most simply, the asterisk, `*',
causes an error to be signalled if the buffer is read-only. This means that
if you try zap-to-char
in a read-only buffer you will not be able to
remove text, and you will receive a message that says "Buffer is
read-only"; your terminal may beep at you as well.
The second part of "*p\ncZap to char: "
is the `p'. This
part is ended by a newline, `\n'. The `p' means that the
first argument to the function will be passed the value of a `processed
prefix'. The prefix argument is passed by typing C-u and a
number, or M- and a number. If the function is called
interactively without a prefix, 1 is passed to this argument.
The third part of "*p\ncZap to char: "
is `cZap to char:
'. In this part, the lower case `c' indicates that
interactive
expects a prompt and that the argument will be a
character. The prompt follows the `c' and is the string `Zap
to char: ' (with a space after the colon to make it look good).
What all this does is prepare the arguments to zap-to-char
so they
are of the right type, and give the user a prompt.
zap-to-char
The body of the zap-to-char
function contains the code that
kills (that is, removes) the text in the region from the current
position of the cursor up to and including the specified character.
The first part of the code looks like this:
(kill-region (point) ...
(point)
is the current position of the cursor.
The next part of the code is an expression using progn
. The body
of the progn
consists of calls to search-forward
and
point
.
It is easier to understand how progn
works after learning about
search-forward
, so we will look at search-forward
and
then at progn
.
search-forward
Function
The search-forward
function is used to locate the
zapped-for-character in zap-to-char
. If the search is
successful, search-forward
leaves point immediately after the
last character in the target string. (In this case the target string is
just one character long.) If the search is backwards,
search-forward
leaves point just before the first character in
the target. Also, search-forward
returns t
for true.
(Moving point is therefore a `side effect'.)
In zap-to-char
, the search-forward
function looks like this:
(search-forward (char-to-string char) nil nil arg)
The search-forward
function takes four arguments:
zap-to-char
is a single
character. Because of the way computers are built, the Lisp interpreter
treats a single character as being different from a string of
characters. Inside the computer, a single character has a different
electronic format than a string of one character. (A single character
can often be recorded in the computer using exactly one byte; but a
string may be longer or shorter, and the computer needs to be ready for
this.) Since the search-forward
function searches for a string,
the character that the zap-to-char
function receives as its
argument must be converted inside the computer from one format to the
other; otherwise the search-forward
function will fail. The
char-to-string
function is used to make this conversion.
nil
.
nil
. A nil
as the third argument causes the function to
signal an error when the search fails.
search-forward
is the repeat count--how
many occurrences of the string to look for. This argument is optional
and if the function is called without a repeat count, this argument is
passed the value 1. If this argument is negative, the search goes
backwards.
In template form, a search-forward
expression looks like this:
(search-forward "target-string" limit-of-search what-to-do-if-search-fails repeat-count)
We will look at progn
next.
progn
Function
progn
is a function that causes each of its arguments to be
evaluated in sequence and then returns the value of the last one. The
preceding expressions are evaluated only for the side effects they
perform. The values produced by them are discarded.
The template for a progn
expression is very simple:
(progn body...)
In zap-to-char
, the progn
expression has to do two things:
put point in exactly the right position; and return the location of
point so that kill-region
will know how far to kill to.
The first argument to the progn
is search-forward
. When
search-forward
finds the string, the function leaves point
immediately after the last character in the target string. (In this
case the target string is just one character long.) If the search is
backwards, search-forward
leaves point just before the first
character in the target. The movement of point is a side effect.
The second and last argument to progn
is the expression
(point)
. This expression returns the value of point, which in
this case will be the location to which it has been moved by
search-forward
. This value is returned by the progn
expression and is passed to kill-region
as kill-region
's
second argument.
zap-to-char
Now that we have seen how search-forward
and progn
work,
we can see how the zap-to-char
function works as a whole.
The first argument to kill-region
is the position of the cursor
when the zap-to-char
command is given--the value of point at
that time. Within the progn
, the search function then moves
point to just after the zapped-to-character and point
returns the
value of this location. The kill-region
function puts together
these two values of point, the first one as the beginning of the region
and the second one as the end of the region, and removes the region.
The progn
function is necessary because the kill-region
command takes two arguments; and it would fail if search-forward
and point
expressions were written in sequence as two
additional arguments. The progn
expression is a single argument
to kill-region
and returns the one value that kill-region
needs for its second argument.
The version 18 implementation of zap-to-char
is slightly
different from the version 19 implementation: it zaps the text up to but
not including the zapped-to-character; and zaps to the end of the buffer
if the specified character is not found.
The difference is in the second argument to the kill-region
command. Where the version 19 implementation looks like this:
(progn (search-forward (char-to-string char) nil nil arg) (point))
The version 18 implementation looks like this:
(if (search-forward (char-to-string char) nil t arg) (progn (goto-char (if (> arg 0) (1- (point)) (1+ (point)))) (point)) (if (> arg 0) (point-max) (point-min)))
This looks considerably more complicated, but the code can be readily understood if it is looked at part by part.
The first part is:
(if (search-forward (char-to-string char) nil t arg)
This fits into an if
expression that does the following job, as
we shall see:
(if able-to-locate-zapped-for-character-and-move-point-to-it then-move-point-to-the-exact-spot-and-return-this-location else-move-to-end-of-buffer-and-return-that-location)
Evaluation of the if
expression specifies the second argument to
kill-region
. Since the first argument is point, this process
makes it possible for kill-region
to remove the text between
point and the zapped-to location.
We have already described how search-forward
moves point as a
side effect. The value that search-forward
returns is t
if the search is successful and either nil
or an error message
depending on the value of the third argument to search-forward
.
In this case, t
is the third argument and it causes the function
to return nil
when the search fails. As we will see, it is easy
to write the code for handling the case when the search returns
nil
.
In the version 18 implementation of zap-to-char
, the search
takes place because the if
causes the search expression to be
evaluated as its true-or-false-test. If the search is successful,
Emacs evaluates the then-part of the if
expression. On the
other hand, if the search fails, Emacs evaluates the else-part of the
if
expression.
In the if
expression, when the search succeeds, a progn
expression is executed--which is to say, it is run as a program.
As we said earlier, progn
is a function that causes each of its
arguments to be evaluated in sequence and then returns the value of the
last one. The preceding expressions are evaluated only for the side
effects they perform. The values produced by them are discarded.
In this version of zap-to-char
, the progn
expression is
executed when the search-forward
function finds the character for
which it is searching. The progn
expression has to do two
things: put point in exactly the right position; and return the location
of point so that kill-region
will know how far to kill to.
The reason for all the code in the progn
is that when
search-forward
finds the string it is looking for, it leaves
point immediately after the last character in the target string. (In
this case the target string is just one character long.) If the search
is backwards, search-forward
leaves point just before the first
character in the target.
However, this version of the zap-to-char
function is designed so
that it does not remove the character being zapped to. For example, if
zap-to-char
is to remove all the text up to a `z', this
version will not remove the `z' as well. So point has to be moved
just enough that the zapped-to character is not removed.
progn
expression
progn
expression
The body of the progn
consists of two expressions. Spread out to
delineate the different parts more clearly, and with comments added, the
progn
expression looks like this:
(progn (goto-char ; First expression inprogn
. (if (> arg 0) ; Ifarg
is positive, (1- (point)) ; move back one character; (1+ (point)))) ; else move forward one character. (point)) ; Second expression inprogn
: ; return position of point.
The progn
expression does this: when the search is forward
(arg
is positive), Emacs leaves point just after the searched-for
character. By moving point back one position, the character is
uncovered. In this case, the expression in the progn
reads as
follows: (goto-char (1- (point)))
. This moves point one
character back. (The 1-
function subtracts one from its
argument, just as 1+
adds ones to its argument.) On the other
hand, if the argument to zap-to-character
is negative, the search
will be backwards. The if
detects this and the expression reads:
(goto-char (1+ (point)))
. (The 1+
function adds one to
its argument.)
The second and last argument to progn
is the expression
(point)
. This expression returns the value of the position to
which point is moved by the first argument to progn
. This
value is then returned by the if
expression of which it is a
part and is passed to kill-region
as kill-region
's
second argument.
In brief, the function works like this: the first argument to
kill-region
is the position of the cursor when the
zap-to-char
command is given--the value of point at that time.
The search function then moves point if the search is successful. The
progn
expression moves point just enough so the zapped to
character is not removed, and returns the value of point after all this
is done. The kill-region
function then removes the region.
Finally, the else-part of the if
expression takes care of the
situation in which the zapped-towards character is not found. If the
argument to the zap-to-char
function is positive (or if none is
given) and the zapped-to character is not found, all the text is
removed from the current position of point to the end of the accessible
region of the buffer (the end of the buffer if there is no narrowing).
If the arg
is negative and the zapped-to character is not found,
the operation goes to the beginning of the accessible region. The code
for this is a simple if
clause:
(if (> arg 0) (point-max) (point-min))
This says that if arg
is a positive number, return the value of
point-max
, otherwise, return the value of point-min
.
For review, here is the code involving kill-region
, with
comments:
(kill-region
(point) ; beginning-of-region
(if (search-forward
(char-to-string char) ; target
nil ; limit-of-search: none
t ; Return nil
if fail.
arg) ; repeat-count.
(progn ; then-part
(goto-char
(if (> arg 0)
(1- (point))
(1+ (point))))
(point))
(if (> arg 0) ; else-part
(point-max)
(point-min))))
As you can see, the version 19 implementation does slightly less than the version 18 implementation, but is much simpler.
kill-region
The zap-to-char
function uses the kill-region
function.
This function is very simple; leaving out part of its documentation
string, it looks like this:
(defun kill-region (beg end) "Kill between point and mark. The text is deleted but saved in the kill ring." (interactive "*r") (copy-region-as-kill beg end) (delete-region beg end))
The main point to note is that it uses the delete-region
and
copy-region-as-kill
functions which are described in following
sections.
delete-region
: A Digression into C
The zap-to-char
command uses the kill-region
function,
which in turn uses two other functions, copy-region-as-kill
and
delete-region
. The copy-region-as-kill
function will be
described in a following section; it puts a copy of the region in the
kill ring so it can be yanked back. (See section copy-region-as-kill
.)
The delete-region
function removes the contents of a region and
you cannot get it back.
Unlike the other code discussed here, delete-region
is not written
in Emacs Lisp; it is written in C and is one of the primitives of the GNU
Emacs system. Since it is very simple, I will digress briefly from Lisp
and describe it here.
Like many of the other Emacs primitives, delete-region
is written
as an instance of a C macro, a macro being a template for code. The
first section of the macro looks like this:
DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r", "Delete the text between point and mark.\n\ When called from a program, expects two arguments,\n\ character numbers specifying the stretch to be deleted.")
Without getting into the details of the macro writing process, let me
point out that this macro starts with the word DEFUN
. The word
DEFUN
was chosen since the code serves the same purpose as
defun
does in Lisp. The word DEFUN
is followed by seven
parts inside of parentheses:
delete-region
.
Fdelete_region
.
By convention, it starts with `F'. Since C does not use hyphens
in names, an underscore is used instead.
interactive
declaration in a function written in Lisp: a letter
followed, perhaps, by a prompt. In this case, the letter is "r"
which indicates that the two arguments to the function will be the
position of the beginning and end of a region in the buffer. In this
code, there isn't any prompt.
The formal parameters come next, with a statement of what kind of object
they are, and then what might be called the `body' of the macro. For
delete-region
the `body' consists of the following three lines:
validate_region (&b, &e); del_range (XINT (b), XINT (e)); return Qnil;
The first function, validate_region
checks whether the values
passed as the beginning and end of the region are the proper type and
are within range. The second function, del_range
, actually
deletes the text. If the function completes its work without error, the
third line returns Qnil
to indicate this.
del_range
is a complex function we will not look into. It
updates the buffer and does other things. However, it is worth
looking at the two arguments passed to del_range
. These are
XINT (b)
and XINT (e)
. As far as the C language
is concerned, b
and e
are two thirty-two bit integers
that mark the beginning and end of the region to be deleted. But like
other numbers in Emacs Lisp, only twenty-four bits of the thirty-two
bits are used for the number; the remaining eight bits are used for
keeping track of the type of information and other purposes. (On
certain machines, only six bits are so used.) In this case, the eight
bits are used to indicate that these numbers are for buffer positions.
When bits of a number are used this way, they are called a tag.
The use of the eight bit tag on each thirty-two bit integer made it
possible to write Emacs to run much faster than it would otherwise.
On the other hand, with numbers limited to twenty-four bits, Emacs
buffers are limited to approximately eight megabytes. (You can
sharply increase the maximum buffer size by adding defines for
VALBITS
and GCTYPEBITS
in the `emacs/src/config.h'
file before compiling. See the note in the `emacs/etc/FAQ' file
that is part of the Emacs distribution.)
`XINT' is C macro that extracts the 24 bit number from the
thirty-two bit Lisp object; the eight bits used for other purposes are
discarded. So del_range (XINT (b), XINT (e))
deletes the
region between the beginning position, b
, and the ending
position, e
.
From the point of view of the person writing Lisp, Emacs is all very simple; but hidden underneath is a great deal of complexity to make it all work.
defvar
Unlike the delete-region
function, the copy-region-as-kill
function is written in Emacs Lisp. It copies a region in a buffer
and saves it in a variable called the kill-ring
. This section
describes how this variable is created and initialized.
(Again we note that the term kill-ring
is a misnomer. The text
that is clipped out of the buffer can be brought back; it is not a ring
of corpses, but a ring of resurrectable text.)
In Emacs Lisp, a variable such as the kill-ring
is created and
given an initial value by using the defvar
special form. The
name comes from "define variable".
The defvar
special form is similar to setq
in that it sets
the value of a variable. It is unlike setq
in two ways: first,
it only sets the value of the variable if the variable does not already
have a value. If the variable already has a value, defvar
does
not override the existing value. Second, defvar
has a
documentation string.
You can see the current value of a variable, any variable, by using
the describe-variable
function, which is usually invoked by
typing C-h v. If you type C-h v and then kill-ring
(followed by RET) when prompted, you will see what is in your
current kill ring--this may be quite a lot! Conversely, if you have
been doing nothing this Emacs session except read this document, you
may have nothing in it. At the end of the `*Help*' buffer, you
will see the documentation for kill-ring
:
Documentation: List of killed text sequences.
The kill ring is defined by a defvar
in the following way:
(defvar kill-ring nil "List of killed text sequences.")
In this variable definition, the variable is given an initial value of
nil
, which makes sense, since if you have saved nothing, you want
nothing back if you give a yank
command. The documentation
string is written just like the documentation string of a defun
.
As with the documentation string of the defun
, the first line of
the documentation should be a complete sentence, since some commands,
like apropos
, print only the first line of documentation.
Succeeding lines should not be indented; otherwise they look odd when
you use C-h v (describe-variable
).
Most variables are internal to Emacs, but some are intended as options
that you can readily set with the edit-options
command. (These
settings last only for the duration of an editing session; to set a
value permanently, write a `.emacs' file. See section Your `.emacs' File.)
A readily settable variable is distinguished from others in Emacs by an asterisk, `*', in the first column of its documentation string.
For example:
(defvar line-number-mode nil "*Non-nil means display line number in mode line.")
This means that you can use the edit-options
command to change
the value of line-number-mode
.
Of course, you can also change the value of line-number-mode
by
evaluating it within a setq
expression, like this:
(setq line-number-mode t)
See section Using setq
.
copy-region-as-kill
The copy-region-as-kill
function copies a region of text from a
buffer and saves it in a variable called the kill-ring
.
If you call copy-region-as-kill
immediately after a
kill-region
command, Emacs appends the newly copied text to the
previously copied text. This means that if you yank back the text, you
get it all, from both this and the previous operation. On the other
hand, if some other command precedes the copy-region-as-kill
,
the function copies the text into a separate entry in the kill ring.
Here is the complete text of the version 18
copy-region-as-kill
, formatted for clarity with several
comments added:
(defun copy-region-as-kill (beg end) "Save the region as if killed, but don't kill it." (interactive "r") (if (eq last-command 'kill-region) ;; then-part: Combine newly copied text ;; with previously copied text. (kill-append (buffer-substring beg end) (< end beg)) ;; else-part: Add newly copied text as a new element ;; to the kill ring and shorten the kill ring if necessary. (setq kill-ring (cons (buffer-substring beg end) kill-ring)) (if (> (length kill-ring) kill-ring-max) (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))) (setq this-command 'kill-region) (setq kill-ring-yank-pointer kill-ring))
As usual, this function can be divided into its component parts:
(defun copy-region-as-kill (argument-list) "documentation..." (interactive "r") body...)
The arguments are beg
and end
and the function is
interactive with "r"
, so the two arguments must refer to the
beginning and end of the region. If you have been reading though this
document from the beginning, understanding these parts of a function is
almost becoming routine.
The documentation is somewhat confusing unless you remember that the word `kill' has a meaning different from its usual meaning.
The body of the function starts with an if
clause. What this
clause does is distinguish between two different situations: whether
or not this command is executed immediately after a previous kill-region
command. In the first case, the new region is appended to the
previously copied text. Otherwise, it is inserted into the beginning
of the kill ring as a separate piece of text from the previous piece.
The last two lines of the function are two setq
expressions. One
of them sets the variable this-command
to kill-region
and
the other sets the variable kill-ring-yank-pointer
to point to
the kill ring.
The body of copy-region-as-kill
merits discussion in detail.
copy-region-as-kill
copy-region-as-kill
The copy-region-as-kill
function is written so that two or more
kills in a row combine their text into a single entry. If you yank back
the text from the kill ring, you get it all in one piece. Moreover,
kills that kill forward from the current position of the cursor are
added to the end of the previously copied text and commands that copy
text backwards add it to the beginning of the previously copied text.
This way, the words in the text stay in the proper order.
The function makes use of two variables that keep track of the current
and previous Emacs command. The two variables are this-command
and last-command
.
Normally, whenever a function is executed, Emacs sets the value of
this-command
to the function being executed (which in this case
would be copy-region-as-kill
). At the same time, Emacs sets
the value of last-command
to the previous value of
this-command
. However, the copy-region-as-kill
command
is different; it sets the value of this-command
to
kill-region
, which is the name of the function that calls
copy-region-as-kill
.
In the first part of the body of the copy-region-as-kill
function, an if
expression determines whether the value of
last-command
is kill-region
. If so, the then-part of
the if
expression is evaluated; it uses the kill-append
function to concatenate the text copied at this call to the function
with the text already in the first element (the CAR) of the kill
ring. On the other hand, if the value of last-command
is not
kill-region
, then the copy-region-as-kill
function
attaches a new element to the kill ring.
The if
expression reads as follows; it uses eq
, which is
a function we have not yet seen:
(if (eq last-command 'kill-region) ;; then-part (kill-append (buffer-substring beg end) (< end beg))
The eq
function tests whether its first argument is the same Lisp
object as its second argument. The eq
function is similar to the
equal
function in that it is used to test for equality, but
differs in that it determines whether two representations are actually
the same object inside the computer, but with different names.
equal
determines whether the structure and contents of two
expressions are the same.
kill-append
function
copy-region-as-kill
kill-append
function
The kill-append
function looks like this:
(defun kill-append (string before-p) (setcar kill-ring (if before-p (concat string (car kill-ring)) (concat (car kill-ring) string))))
We can look at this function in parts. The setcar
function uses
concat
to concatenate the new text to the CAR of the kill
ring. Whether it prepends or appends the text depends on the results of
an if
expression:
(if before-p ; if-part (concat string (car kill-ring)) ; then-part (concat (car kill-ring) string)) ; else-part
If the region being killed is before the region that was killed in the
last command, then it should be prepended before the material that was
saved in the previous kill; and conversely, if the killed text follows
what was just killed, it should be appended after the previous text.
The if
expression depends on the predicate before-p
to
decide whether the newly saved text should be put before or after the
previously saved text.
The symbol before-p
is the name of one of the arguments to
kill-append
. When the kill-append
function is
evaluated, it is bound to the value returned by evaluating the actual
argument. In this case, this is the expression (< end beg)
.
This expression does not directly determine whether the killed text in
this command is located before or after the kill text of the last
command; what is does is determine whether the value of the variable
end
is less than the value of the variable beg
. If it
is, it means that the user is most likely heading towards the
beginning of the buffer. Also, the result of evaluating the predicate
expression, (< end beg)
, will be true and the text will be
prepended before the previous text. On the other hand, if the value of
the variable end
is greater than the value of the variable
beg
, the text will be appended after the previous text.
When the newly saved text will be prepended, then the string with the new text will be concatenated before the old test:
(concat string (car kill-ring))
But if the text will be appended, it will be concatenated after the old text:
(concat (car kill-ring) string))
To understand how this works, we first need to review the
concat
function. The concat
function links together or
unites two strings of text. The result is a string. For example:
(concat "abc" "def") => "abcdef" (concat "new " (car '("first element" "second element"))) => "new first element" (concat (car '("first element" "second element")) " modified") => "first element modified"
We can now make sense of kill-append
: it modifies the contents
of the kill ring. The kill ring is a list, each element of which is
saved text. The setcar
function actually changes the first
element of this list. It does this by using concat
to replace
the old first element of the kill ring (the CAR of the kill ring)
with a new first element made by concatenating together the old saved
text and the newly saved text. The newly saved text is put in front
of the old text or after the old text, depending on whether it is in
front of or after the old text in the buffer from which it is cut.
The whole concatenation becomes the new first element of the kill
ring.
Incidentally, this is what the beginning of my current kill ring looks like:
("concatenating together" "saved text" "element" ...
copy-region-as-kill
Now, back to the explanation of copy-region-as-kill
:
If the last command is not kill-region
, then instead of calling
kill-append
, it calls the else-part of the following code:
(if true-or-false-test what-is-done-if-test-returns-true ;; else-part (setq kill-ring (cons (buffer-substring beg end) kill-ring)) (if (> (length kill-ring) kill-ring-max) (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
The setq
line of the else-part sets the new value of the kill
ring to what results from adding the string being killed to the old kill
ring.
We can see how this works with a little example:
(setq example-list '("here is a clause" "another clause"))
After evaluating this expression with C-x C-e, you can evaluate
example-list
and see what it returns:
example-list => ("here is a clause" "another clause")
Now, we can add a new element on to this list by evaluating the following expression:
(setq example-list (cons "a third clause" example-list))
When we evaluate example-list
, we find its value is:
example-list => ("a third clause" "here is a clause" "another clause")
Thus, the third clause was added to the list by cons
.
This is exactly similar to what the setq
and cons
do in
the function, except that buffer-substring
is used to pull out a
copy of a region of text and hand it to the cons
. Here is the
line again:
(setq kill-ring (cons (buffer-substring beg end) kill-ring))
The next segment of the else-part of copy-region-as-kill
is
another if
clause. This if
clause keeps the kill ring
from growing too long. It reads as follows:
(if (> (length kill-ring) kill-ring-max) (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
This code checks whether the length of the kill ring is greater than the
maximum permitted length. This is the value of kill-ring-max
(which is 30, by default). If the length of the kill ring is too long,
then this code sets the last element of the kill ring to nil
. It
does this by using two functions, nthcdr
and setcdr
.
We looked at setcdr
earlier (see section setcdr
).
It sets the CDR of a list, just as setcar
sets the
CAR of a list. In this case, however, setcdr
will not be
setting the cdr
of the whole kill ring; the nthcdr
function is used to cause it to set the cdr
of the next to last
element of the kill ring--this means that since the cdr
of the
next to last element is the last element of the kill ring, it will set
the last element of the kill ring.
The nthcdr
function works by repeatedly taking the CDR of a
list--it takes the CDR of the CDR of the CDR
... It does this N times and returns the results.
Thus, if we had a four element list that was supposed to be three
elements long, we could set the CDR of the next to last element
to nil
, and thereby shorten the list.
You can see this by evaluating the following three expressions in turn.
First set the value of trees
to (maple oak pine birch)
,
then set the CDR of its second CDR to nil
and then
find the value of trees
:
(setq trees '(maple oak pine birch)) => (maple oak pine birch) (setcdr (nthcdr 2 trees) nil) => nil trees => (maple oak pine)
(The value returned by the setcdr
expression is nil
since
that is what the CDR is set to.)
To repeat, in copy-region-as-kill
, the nthcdr
function
takes the CDR a number of times that is one less than the maximum
permitted size of the kill ring and sets the CDR of that element
(which will be the rest of the elements in the kill ring) to
nil
. This prevents the kill ring from growing too long.
The next to last line of the copy-region-as-kill
function is
(setq this-command 'kill-region)
This line is not part of either the inner or the outer if
expression, so it is evaluated every time copy-region-as-kill
is
called. Here we find the place where this-command
is set to
kill-region
. As we saw earlier, when the next command is given,
the variable last-command
will be given this value.
Finally, the last line of the copy-region-as-kill
function is:
(setq kill-ring-yank-pointer kill-ring)
The kill-ring-yank-pointer
is a global variable that is set to be
the kill-ring
.
Even though the kill-ring-yank-pointer
is called a
`pointer', it is a variable just like the kill ring. However, the
name has been chosen to help humans understand how the variable is used.
The variable is used in functions such as yank
and
yank-pop
(see section Yanking Text Back).
This leads us to the code for bringing back text that has been cut out of the buffer--the yank commands. However, before discussing the yank commands, it is better to learn how lists are implemented in a computer. This will make clear such mysteries as the use of the term `pointer'.
Here is a brief summary of some recently introduced functions.
car
cdr
car
returns the first element of a list; cdr
returns the
second and subsequent elements of a list.
For example:
(car '(1 2 3 4 5 6 7)) => 1 (cdr '(1 2 3 4 5 6 7)) => (2 3 4 5 6 7)
cons
cons
constructs a list by prepending its first argument to its
second argument.
For example:
(cons 1 '(2 3 4)) => (1 2 3 4)
nthcdr
cdr
`n' times on a list. The `rest
of the rest' as it were.
For example:
(nthcdr 3 '(1 2 3 4 5 6 7)) => (4 5 6 7)
setcar
setcdr
setcar
changes the first element of a list; setcdr
changes the second and subsequent elements of a list.
For example:
(setq triple '(1 2 3)) (setcar triple '37) triple => (37 2 3) (setcdr triple '("foo" "bar")) triple => (37 "foo" "bar")
progn
(progn 1 2 3 4) => 4
save-restriction
search-forward
nil
or an
error message.
kill-region
delete-region
copy-region-as-kill
kill-region
cuts the text between point and mark from the
buffer and stores that text in the kill ring, so you can get it back
by yanking.
delete-region
removes the text between point and mark from the
buffer and throws it away. You cannot get it back.
copy-region-as-kill
copies the text between point and mark into
the kill ring, from which you can get it by yanking. The function
does not cut or remove the text from the buffer.
search-forward
for the name
of this function; if you do, you will overwrite the existing version of
search-forward
that comes with Emacs. Use a name such as
test-search
instead.)
copy-region-as-kill
no longer
sets this-command
. What are the consequences of this change?
What do you suppose motivated it?