www.delorie.com/gnu/docs/emacs-lisp-intro/emacs-lisp-intro_143.html   search  
 
Buy the book!


Programming in Emacs Lisp

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

The kill-new function

The kill-new function looks like this:

 
(defun kill-new (string &optional replace)
  "Make STRING the latest kill in the kill ring.
Set the kill-ring-yank pointer to point to it.
If `interprogram-cut-function' is non-nil, apply it to STRING.
Optional second argument REPLACE non-nil means that STRING will replace
the front of the kill ring, rather than being added to the list."
  (and (fboundp 'menu-bar-update-yank-menu)
       (menu-bar-update-yank-menu string (and replace (car kill-ring))))
  (if (and replace kill-ring)
      (setcar kill-ring string)
    (setq kill-ring (cons string kill-ring))
    (if (> (length kill-ring) kill-ring-max)
        (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
  (setq kill-ring-yank-pointer kill-ring)
  (if interprogram-cut-function
      (funcall interprogram-cut-function string (not replace))))

As usual, we can look at this function in parts.

The first line of the documentation makes sense:

 
Make STRING the latest kill in the kill ring.

Let's skip over the rest of the documentation for the moment.

Also, let's skip over the first two lines of code, those involving menu-bar-update-yank-menu. We will explain them below.

The critical lines are these:

 
  (if (and replace kill-ring)
      ;; then
      (setcar kill-ring string)
    ;; else
    (setq kill-ring (cons string kill-ring))
    (if (> (length kill-ring) kill-ring-max)
        ;; avoid overly long kill ring
        (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
  (setq kill-ring-yank-pointer kill-ring)
  (if interprogram-cut-function
      (funcall interprogram-cut-function string (not replace))))

The conditional test is (and replace kill-ring). This will be true when two conditions are met: the kill ring has something in it, and the replace variable is true.

The kill-append function sets replace to be true; then, when the kill ring has at least one item in it, the setcar expression is executed:

 
(setcar kill-ring string)

The setcar function actually changes the first element of the kill-ring list to the value of string. It replaces the first element.

On the other hand, if the kill ring is empty, or replace is false, the else-part of the condition is executed:

 
(setq kill-ring (cons string kill-ring))
(if (> (length kill-ring) kill-ring-max)
    (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))

This expression first constructs a new version of the kill ring by prepending string to the existing kill ring as a new element. Then it executes a second if clause. This second if clause keeps the kill ring from growing too long.

Let's look at these two expressions in order.

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 an 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. Here is the line again:

 
(setq kill-ring (cons string kill-ring))

Now for the second part of the if clause. This expression keeps the kill ring from growing too long. It looks like this:

 
(if (> (length kill-ring) kill-ring-max)
    (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))

The 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 60, 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 kill-new, 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 expression in the kill-new 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).

Now, to return to the first two lines in the body of the function:

 
  (and (fboundp 'menu-bar-update-yank-menu)
       (menu-bar-update-yank-menu string (and replace (car kill-ring))))

This is an expression whose first element is the function and.

The and special form evaluates each of its arguments until one of the arguments returns a value of nil, in which case the and expression returns nil; however, if none of the arguments returns a value of nil, the value resulting from evaluating the last argument is returned. (Since such a value is not nil, it is considered true in Emacs Lisp.) In other words, an and expression returns a true value only if all its arguments are true.

In this case, the expression tests first to see whether menu-bar-update-yank-menu exists as a function, and if so, calls it. The fboundp function returns true if the symbol it is testing has a function definition that `is not void'. If the symbol's function definition were void, we would receive an error message, as we did when we created errors intentionally (see section Generate an Error Message).

Essentially, the and is an if expression that reads like this:

 
if the-menu-bar-function-exists
  then execute-it

menu-bar-update-yank-menu is one of the functions that make it possible to use the `Select and Paste' menu in the Edit item of a menu bar; using a mouse, you can look at the various pieces of text you have saved and select one piece to paste.

Finally, the last expression in the kill-new function adds the newly copied string to whatever facility exists for copying and pasting among different programs running in a windowing system. In the X Windowing system, for example, the x-select-text function takes the string and stores it in memory operated by X. You can paste the string in another program, such as an Xterm.

The expression looks like this:

 
  (if interprogram-cut-function
      (funcall interprogram-cut-function string (not replace))))

If an interprogram-cut-function exists, then Emacs executes funcall, which in turn calls its first argument as a function and passes the remaining arguments to it. (Incidentally, as far as I can see, this if expression could be replaced by an and expression similar to the one in the first part of the function.)

We are not going to discuss windowing systems and other programs further, but merely note that this is a mechanism that enables GNU Emacs to work easily and well with other programs.

This code for placing text in the kill ring, either concatenated with an existing element or as a new element, 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'.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

  webmaster   donations   bookstore     delorie software   privacy  
  Copyright 2003   by The Free Software Foundation     Updated Jun 2003