eintr: kill-new function

 
 The ‘kill-new’ function
 .......................
 
 In 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’ 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’ 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’ 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 '(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 (SeeGenerate an Error Message Making
 Errors.).
 
 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.  (SeeSecond 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.