Go to the first, previous, next, last section, table of contents.

Cutting and Storing Text

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))))

The 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.

The Body of 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.

The 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:

  1. The first argument is the target, what is searched for. This must be a string, such as `"z"'. As it happens, the argument passed to 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.
  2. The second argument bounds the search; it is specified as a position in the buffer. In this case, the search can go to the end of the buffer, so no bound is set and the second argument is nil.
  3. The third argument tells the function what it should do if the search fails--it can signal an error (and print a message) or it can return nil. A nil as the third argument causes the function to signal an error when the search fails.
  4. The fourth argument to 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.

The 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.

Summing up 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

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.

The body of the 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 in progn.
        (if (> arg 0)       ; If arg is positive,
            (1- (point))    ;   move back one character;
          (1+ (point))))    ;   else move forward one character.

  (point))                  ; Second expression in progn:
                            ;   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:

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.

Initializing a Variable with 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.

The Body of 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.

The 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" ...

The else-part of 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'.

Review

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
Return the result of taking 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
Evaluate each argument in sequence and then return the value of the last. For example:
(progn 1 2 3 4)
     => 4
save-restriction
Record whatever narrowing is in effect in the current buffer, if any, and restore that narrowing after evaluating the arguments.
search-forward
Search for a string, and if the string is found, move point. Takes four arguments:
  1. The string to search for.
  2. Optionally, the limit of the search.
  3. Optionally, what to do if the search fails, return nil or an error message.
  4. Optionally, how many times to repeat the search; if negative, the search goes backwards.
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.

Searching Exercises


Go to the first, previous, next, last section, table of contents.