Node:rotate-yk-ptr else-part, Next:, Previous:Digression concerning error, Up:rotate-yk-ptr body



The else-part of the if expression

The else-part of the if expression is dedicated to setting the value of kill-ring-yank-pointer when the kill ring has something in it. The code looks like this:

(setq kill-ring-yank-pointer
      (nthcdr (% (+ arg
                    (- length
                       (length kill-ring-yank-pointer)))
                 length)
              kill-ring)))))

This needs some examination. Clearly, kill-ring-yank-pointer is being set to be equal to some CDR of the kill ring, using the nthcdr function that is described in an earlier section. (See copy-region-as-kill.) But exactly how does it do this?

Before looking at the details of the code let's first consider the purpose of the rotate-yank-pointer function.

The rotate-yank-pointer function changes what kill-ring-yank-pointer points to. If kill-ring-yank-pointer starts by pointing to the first element of a list, a call to rotate-yank-pointer causes it to point to the second element; and if kill-ring-yank-pointer points to the second element, a call to rotate-yank-pointer causes it to point to the third element. (And if rotate-yank-pointer is given an argument greater than 1, it jumps the pointer that many elements.)

The rotate-yank-pointer function uses setq to reset what the kill-ring-yank-pointer points to. If kill-ring-yank-pointer points to the first element of the kill ring, then, in the simplest case, the rotate-yank-pointer function must cause it to point to the second element. Put another way, kill-ring-yank-pointer must be reset to have a value equal to the CDR of the kill ring.

That is, under these circumstances,

(setq kill-ring-yank-pointer
   ("some text" "a different piece of text" "yet more text"))

(setq kill-ring
   ("some text" "a different piece of text" "yet more text"))

the code should do this:

(setq kill-ring-yank-pointer (cdr kill-ring))

As a result, the kill-ring-yank-pointer will look like this:

kill-ring-yank-pointer
     => ("a different piece of text" "yet more text"))

The actual setq expression uses the nthcdr function to do the job.

As we have seen before (see nthcdr), the nthcdr function works by repeatedly taking the CDR of a list--it takes the CDR of the CDR of the CDR ...

The two following expressions produce the same result:

(setq kill-ring-yank-pointer (cdr kill-ring))

(setq kill-ring-yank-pointer (nthcdr 1 kill-ring))

In the rotate-yank-pointer function, however, the first argument to nthcdr is a rather complex looking expression with lots of arithmetic inside of it:

(% (+ arg
      (- length
         (length kill-ring-yank-pointer)))
   length)

As usual, we need to look at the most deeply embedded expression first and then work our way towards the light.

The most deeply embedded expression is (length kill-ring-yank-pointer). This finds the length of the current value of the kill-ring-yank-pointer. (Remember that the kill-ring-yank-pointer is the name of a variable whose value is a list.)

The measurement of the length is inside the expression:

(- length (length kill-ring-yank-pointer))

In this expression, the first length is the variable that was assigned the length of the kill ring in the let statement at the beginning of the function. (One might think this function would be clearer if the variable length were named length-of-kill-ring instead; but if you look at the text of the whole function, you will see that it is so short that naming this variable length is not a bother, unless you are pulling the function apart into very tiny pieces as we are doing here.)

So the line (- length (length kill-ring-yank-pointer)) tells the difference between the length of the kill ring and the length of the list whose name is kill-ring-yank-pointer.

To see how all this fits into the rotate-yank-pointer function, let's begin by analyzing the case where kill-ring-yank-pointer points to the first element of the kill ring, just as kill-ring does, and see what happens when rotate-yank-pointer is called with an argument of 1.

The variable length and the value of the expression (length kill-ring-yank-pointer) will be the same since the variable length is the length of the kill ring and the kill-ring-yank-pointer is pointing to the whole kill ring. Consequently, the value of

(- length (length kill-ring-yank-pointer))

will be zero. Since the value of arg will be 1, this will mean that the value of the whole expression

(+ arg (- length (length kill-ring-yank-pointer)))

will be 1.

Consequently, the argument to nthcdr will be found as the result of the expression

(% 1 length)