Previous: kill-append function, Up: copy-region-as-kill body [Contents][Index]
kill-new
functionIn version 22 the kill-new
function looks like this:
(defun kill-new (string &optional replace yank-handler) "Make STRING the latest kill in the kill ring. Set `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. …"
(if (> (length string) 0) (if yank-handler (put-text-property 0 (length string) 'yank-handler yank-handler string)) (if yank-handler (signal 'args-out-of-range (list string "yank-handler specified for empty string"))))
(if (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) (push 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))))
(Notice that the function is not interactive.)
As usual, we can look at this function in parts.
The function definition has an optional yank-handler
argument, which
when invoked tells the function how to deal with properties added to the
text, such as bold or italics. We will skip that.
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 initial if
expression and those lines of
code 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
(push 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.
When the kill-append
function sets replace
to be true and 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:
(push string kill-ring)
push
puts its first argument onto the second. It is similar to the
older
(setq kill-ring (cons string kill-ring))
or the newer
(add-to-list kill-ring string)
When it is false, the expression first constructs a new version of the kill
ring by prepending string
to the existing kill ring as a new element
(that is what the push
does). 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 push
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.
First,
(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:
(push "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 is added to the list by push
.
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 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. (See nthcdr
.)
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. (If you set the last element to some other
value than nil
, which you could do, then you would not have shortened
the list. See setcdr
.)
You can see shortening 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 (list '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 setcdr
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.
Now, to return to an early expression in the body of the function:
(if (fboundp 'menu-bar-update-yank-menu) (menu-bar-update-yank-menu string (and replace (car kill-ring))))
It starts with an if
expression
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 Generate an Error Message).
The then-part contains 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. (See Second Buffer Related Review.)
The expression determines whether the second argument to
menu-bar-update-yank-menu
is true or not.
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.
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”. But before that, we will digress into C.
Previous: kill-append function, Up: copy-region-as-kill body [Contents][Index]