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


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


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