unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Colin Walters <walters@debian.org>
Subject: kill ring menu
Date: 28 Apr 2002 15:41:31 -0400	[thread overview]
Message-ID: <1020022891.27106.142.camel@space-ghost> (raw)

[-- Attachment #1: Type: text/plain, Size: 2068 bytes --]

Hello,

I received a mail from Michael Slass, which I will quote here with
permission:

On Tue, 2002-04-23 at 17:35, Michael Slass wrote:
> Colin:
> 
> I just found browse-kill-ring, and I really like it; thanks for
> writing it.  I wasn't sure where to bind it on my keyboard, but then
> I thought of that annoying message you get - "The last command was not
> a yank" - when you accidentally hit M-y, and thought that would be a
> great place to put it.

I think this idea is so good that it should be the default behavior for
Emacs.  

Attached is a patch for review.  This patch doesn't remove any behavior,
but it is conceptually a fairly large change, so I think we should
consider it carefully.

There are several pros and cons, as I see it.  The main thing we gain is
that the old behavior of M-y was useless if the previous command wasn't
a yank, and the suggested new behavior is, I personally believe, quite
useful.

The main disadvantage I see is that users may type just M-y accidentally
and be confused.  For this reason, I've made C-g quit the kill ring menu
as well (as Michael Slass suggested in a later message).  Further
suggestions here would be appreciated.

As for the patch itself: basically, I renamed `browse-kill-ring' to
`kill-ring-menu', removed the more esoteric functionality (like editing
kill ring entries), and rewrote it to use font lock, among other things.

Some minor points:

I have moved all the killing stuff out from simple.el into kill-ring.el;
I feel that anything which defines a mode should, as a general
principle, be in a separate file.  However, if there is disagreement
about this, we can put everything back in simple.el.  It is not
important to the main change.

There are some minor additions to font-lock.el; ignore those for the
moment, please.  I'm just sharing some code between replace.el and
kill-ring.el (and probably ibuffer.el soon).

Finally, I'm not totally satisfied with the manual additions; there are
some bootstrapping issues, since we haven't discussed windows at that
point in the manual yet, etc.

[-- Attachment #2: kill-ring.patch --]
[-- Type: text/plain, Size: 61834 bytes --]

--- NEWS.~1.660.~	Sat Apr 27 17:20:39 2002
+++ NEWS	Sun Apr 28 14:43:43 2002
@@ -49,6 +48,13 @@
 
 \f
 * Changes in Emacs 21.4
+
++++
+** The key `M-y' has been extended to display a menu of kill ring
+entries, if the previous command was not a 'C-y'.  Previously, `M-y'
+ran the command `yank-pop'.  Now it runs `yank-previous', which will
+either display a menu (`kill-ring-menu') or call `yank-pop'.  See the
+node "Yanking Earlier Kills" in the Emacs manual for more information.
 
 ---
 ** The new options `buffers-menu-show-directories' and
--- killing.texi.~1.26.~	Wed Sep 12 17:01:34 2001
+++ killing.texi	Sun Apr 28 13:08:24 2002
@@ -270,8 +270,7 @@
 @item C-y
 Yank last killed text (@code{yank}).
 @item M-y
-Replace text just yanked with an earlier batch of killed text
-(@code{yank-pop}).
+Choose previously yanked text to insert (@code{yank-pop}).
 @item M-w
 Save region as last killed text without actually killing it
 (@code{kill-ring-save}).
@@ -374,49 +373,92 @@
 
 @cindex yanking previous kills
 @kindex M-y
-@findex yank-pop
-  To recover killed text that is no longer the most recent kill, use the
-@kbd{M-y} command (@code{yank-pop}).  It takes the text previously
-yanked and replaces it with the text from an earlier kill.  So, to
-recover the text of the next-to-the-last kill, first use @kbd{C-y} to
-yank the last kill, and then use @kbd{M-y} to replace it with the
-previous kill.  @kbd{M-y} is allowed only after a @kbd{C-y} or another
-@kbd{M-y}.
-
-  You can understand @kbd{M-y} in terms of a ``last yank'' pointer which
-points at an entry in the kill ring.  Each time you kill, the ``last
-yank'' pointer moves to the newly made entry at the front of the ring.
-@kbd{C-y} yanks the entry which the ``last yank'' pointer points to.
-@kbd{M-y} moves the ``last yank'' pointer to a different entry, and the
-text in the buffer changes to match.  Enough @kbd{M-y} commands can move
-the pointer to any entry in the ring, so you can get any entry into the
+@findex yank-previous
+  To recover killed text that is no longer the most recent kill, use
+the @kbd{M-y} command (@code{yank-previous}).  This command can act in
+two different ways.  If the previous command was not a yank, then
+@kbd{M-y} will display a menu of kill ring entries, which you can
+choose from (@code{kill-ring-menu}).  If the previous command was a
+yank, then @kbd{M-y} will replace the previously yanked text with the
+text from an earlier kill (@code{yank-pop}).
+
+@subsubsection The Kill Ring Menu 
+If you are not sure how long ago you killed the piece of text you're
+loooking for, it can often be easiest to use the kill ring menu.
+Simply type @kbd{M-y} (which was not preceeded by a @kbd{C-y}), and a
+window should pop up, which will display the text previously killed,
+one entry on each line.  In this special mode, keys do not insert
+themselves; instead, they choose actions to perform.
+
+@table @kbd
+@item RET
+Choose the text at point to yank (@code{kill-ring-menu-insert}).
+@item n
+Move point forward by one kill ring entry
+(@code{kill-ring-menu-forward}).
+@item p
+Move point backwards by one kill ring entry
+(@code{kill-ring-menu-backward}).
+@item q
+Quit the kill ring menu without yanking any text
+(@code{kill-ring-menu-quit}).
+@item d
+Remove the text at point from the kill ring
+(@code{kill-ring-menu-delete}).
+@end table
+
+The kill ring menu can display multi-line text; In the default display
+style, all text is shown on one line, and newlines are shown as a
+@samp{\n}.
+
+@subsubsection Cycling Through Yanked Text
+
+If you know precisely where the text you previously yanked is in the
+@code{kill-ring}, or it was very recently yanked, you may find using
+the @code{yank-pop} functionality of @kbd{M-y} to be faster than the
+kill ring menu.  For example, to recover the text of the
+next-to-the-last kill, you could first use @kbd{C-y} to yank the last
+kill, and then type @kbd{M-y} to replace it with the previous kill.
+
+  You can understand @code{yank-pop} in terms of a ``last yank''
+pointer which points at an entry in the kill ring.  Each time you
+kill, the ``last yank'' pointer moves to the newly made entry at the
+front of the ring.  @kbd{C-y} yanks the entry which the ``last yank''
+pointer points to.  After that, typing @kbd{M-y} moves the ``last
+yank'' pointer to a different entry, and the text in the buffer
+changes to match.  Enough @code{yank-pop} commands can move the
+pointer to any entry in the ring, so you can get any entry into the
 buffer.  Eventually the pointer reaches the end of the ring; the next
 @kbd{M-y} loops back around to the first entry again.
 
-  @kbd{M-y} moves the ``last yank'' pointer around the ring, but it does
-not change the order of the entries in the ring, which always runs from
-the most recent kill at the front to the oldest one still remembered.
-
-  @kbd{M-y} can take a numeric argument, which tells it how many entries
-to advance the ``last yank'' pointer by.  A negative argument moves the
-pointer toward the front of the ring; from the front of the ring, it
-moves ``around'' to the last entry and continues forward from there.
-
-  Once the text you are looking for is brought into the buffer, you can
-stop doing @kbd{M-y} commands and it will stay there.  It's just a copy
-of the kill ring entry, so editing it in the buffer does not change
-what's in the ring.  As long as no new killing is done, the ``last
-yank'' pointer remains at the same place in the kill ring, so repeating
-@kbd{C-y} will yank another copy of the same previous kill.
-
-  If you know how many @kbd{M-y} commands it would take to find the
-text you want, you can yank that text in one step using @kbd{C-y} with
-a numeric argument.  @kbd{C-y} with an argument restores the text from
-the specified kill ring entry, counting back from the most recent as
-1.  Thus, @kbd{C-u 2 C-y} gets the next-to-the-last block of killed
+  @code{yank-pop} moves the ``last yank'' pointer around the ring, but
+it does not change the order of the entries in the ring, which always
+runs from the most recent kill at the front to the oldest one still
+remembered.
+
+  @code{yank-pop} can take a numeric argument, which tells it how many
+entries to advance the ``last yank'' pointer by.  A negative argument
+moves the pointer toward the front of the ring; from the front of the
+ring, it moves ``around'' to the last entry and continues forward from
+there.
+
+  Once the text you are looking for is brought into the buffer, you
+can stop doing @code{yank-pop} commands and it will stay there.  It's
+just a copy of the kill ring entry, so editing it in the buffer does
+not change what's in the ring.  As long as no new killing is done, the
+``last yank'' pointer remains at the same place in the kill ring, so
+repeating @kbd{C-y} will yank another copy of the same previous kill.
+
+  If you know how many @code{yank-pop} commands it would take to find
+the text you want, you can yank that text in one step using @kbd{C-y}
+with a numeric argument.  @kbd{C-y} with an argument restores the text
+from the specified kill ring entry, counting back from the most recent
+as 1.  Thus, @kbd{C-u 2 C-y} gets the next-to-the-last block of killed
 text---it is equivalent to @kbd{C-y M-y}.  @kbd{C-y} with a numeric
 argument starts counting from the ``last yank'' pointer, and sets the
 ``last yank'' pointer to the entry that it yanks.
+
+@subsubsection The Kill Ring Data
 
 @vindex kill-ring-max
   The length of the kill ring is controlled by the variable
+there.
+
+  Once the text you are looking for is brought into the buffer, you
+can stop doing @code{yank-pop} commands and it will stay there.  It's
+just a copy of the kill ring entry, so editing it in the buffer does
+not change what's in the ring.  As long as no new killing is done, the
+``last yank'' pointer remains at the same place in the kill ring, so
+repeating @kbd{C-y} will yank another copy of the same previous kill.
+
+  If you know how many @code{yank-pop} commands it would take to find
+the text you want, you can yank that text in one step using @kbd{C-y}
+with a numeric argument.  @kbd{C-y} with an argument restores the text
+from the specified kill ring entry, counting back from the most recent
+as 1.  Thus, @kbd{C-u 2 C-y} gets the next-to-the-last block of killed
 text---it is equivalent to @kbd{C-y M-y}.  @kbd{C-y} with a numeric
 argument starts counting from the ``last yank'' pointer, and sets the
 ``last yank'' pointer to the entry that it yanks.
+
+@subsubsection The Kill Ring Data
 
 @vindex kill-ring-max
   The length of the kill ring is controlled by the variable
--- simple.el	27 Apr 2002 23:16:18 -0000	1.539
+++ simple.el	28 Apr 2002 19:28:53 -0000
@@ -32,11 +32,6 @@
   (autoload 'shell-mode "shell")
   (require 'cl))
 
-
-(defgroup killing nil
-  "Killing and yanking commands"
-  :group 'editing)
-
 (defgroup paren-matching nil
   "Highlight (un)matching of parens and expressions."
   :group 'matching)
@@ -1656,334 +1651,6 @@
 		  unread-command-events)))
   (reset-this-command-lengths)
   (setq overriding-terminal-local-map nil))
-\f
-;;;; Window system cut and paste hooks.
-
-(defvar interprogram-cut-function nil
-  "Function to call to make a killed region available to other programs.
-
-Most window systems provide some sort of facility for cutting and
-pasting text between the windows of different programs.
-This variable holds a function that Emacs calls whenever text
-is put in the kill ring, to make the new kill available to other
-programs.
-
-The function takes one or two arguments.
-The first argument, TEXT, is a string containing
-the text which should be made available.
-The second, PUSH, if non-nil means this is a \"new\" kill;
-nil means appending to an \"old\" kill.")
-
-(defvar interprogram-paste-function nil
-  "Function to call to get text cut from other programs.
-
-Most window systems provide some sort of facility for cutting and
-pasting text between the windows of different programs.
-This variable holds a function that Emacs calls to obtain
-text that other programs have provided for pasting.
-
-The function should be called with no arguments.  If the function
-returns nil, then no other program has provided such text, and the top
-of the Emacs kill ring should be used.  If the function returns a
-string, that string should be put in the kill ring as the latest kill.
-
-Note that the function should return a string only if a program other
-than Emacs has provided a string for pasting; if Emacs provided the
-most recent string, the function should return nil.  If it is
-difficult to tell whether Emacs or some other program provided the
-current string, it is probably good enough to return nil if the string
-is equal (according to `string=') to the last text Emacs provided.")
-\f
-
-
-;;;; The kill ring data structure.
-
-(defvar kill-ring nil
-  "List of killed text sequences.
-Since the kill ring is supposed to interact nicely with cut-and-paste
-facilities offered by window systems, use of this variable should
-interact nicely with `interprogram-cut-function' and
-`interprogram-paste-function'.  The functions `kill-new',
-`kill-append', and `current-kill' are supposed to implement this
-interaction; you may want to use them instead of manipulating the kill
-ring directly.")
-
-(defcustom kill-ring-max 60
-  "*Maximum length of kill ring before oldest elements are thrown away."
-  :type 'integer
-  :group 'killing)
-
-(defvar kill-ring-yank-pointer nil
-  "The tail of the kill ring whose car is the last thing yanked.")
-
-(defun kill-new (string &optional replace)
-  "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."
-  (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))))
-
-(defun kill-append (string before-p)
-  "Append STRING to the end of the latest kill in the kill ring.
-If BEFORE-P is non-nil, prepend STRING to the kill.
-If `interprogram-cut-function' is set, pass the resulting kill to
-it."
-  (kill-new (if before-p
-		(concat string (car kill-ring))
-	      (concat (car kill-ring) string))
-	    t))
-
-(defun current-kill (n &optional do-not-move)
-  "Rotate the yanking point by N places, and then return that kill.
-If N is zero, `interprogram-paste-function' is set, and calling it
-returns a string, then that string is added to the front of the
-kill ring and returned as the latest kill.
-If optional arg DO-NOT-MOVE is non-nil, then don't actually move the
-yanking point; just return the Nth kill forward."
-  (let ((interprogram-paste (and (= n 0)
-				 interprogram-paste-function
-				 (funcall interprogram-paste-function))))
-    (if interprogram-paste
-	(progn
-	  ;; Disable the interprogram cut function when we add the new
-	  ;; text to the kill ring, so Emacs doesn't try to own the
-	  ;; selection, with identical text.
-	  (let ((interprogram-cut-function nil))
-	    (kill-new interprogram-paste))
-	  interprogram-paste)
-      (or kill-ring (error "Kill ring is empty"))
-      (let ((ARGth-kill-element
-	     (nthcdr (mod (- n (length kill-ring-yank-pointer))
-			  (length kill-ring))
-		     kill-ring)))
-	(or do-not-move
-	    (setq kill-ring-yank-pointer ARGth-kill-element))
-	(car ARGth-kill-element)))))
-
-
-
-;;;; Commands for manipulating the kill ring.
-
-(defcustom kill-read-only-ok nil
-  "*Non-nil means don't signal an error for killing read-only text."
-  :type 'boolean
-  :group 'killing)
-
-(put 'text-read-only 'error-conditions
-     '(text-read-only buffer-read-only error))
-(put 'text-read-only 'error-message "Text is read-only")
-
-(defun kill-region (beg end)
-  "Kill between point and mark.
-The text is deleted but saved in the kill ring.
-The command \\[yank] can retrieve it from there.
-\(If you want to kill and then yank immediately, use \\[kill-ring-save].)
-
-If you want to append the killed region to the last killed text,
-use \\[append-next-kill] before \\[kill-region].
-
-If the buffer is read-only, Emacs will beep and refrain from deleting
-the text, but put the text in the kill ring anyway.  This means that
-you can use the killing commands to copy text from a read-only buffer.
-
-This is the primitive for programs to kill text (as opposed to deleting it).
-Supply two arguments, character numbers indicating the stretch of text
- to be killed.
-Any command that calls this function is a \"kill command\".
-If the previous command was also a kill command,
-the text killed this time appends to the text killed last time
-to make one entry in the kill ring."
-  (interactive "r")
-  (condition-case nil
-      (let ((string (delete-and-extract-region beg end)))
-	(when string			;STRING is nil if BEG = END
-	  ;; Add that string to the kill ring, one way or another.
-	  (if (eq last-command 'kill-region)
-	      (kill-append string (< end beg))
-	    (kill-new string)))
-	(setq this-command 'kill-region))
-    ((buffer-read-only text-read-only)
-     ;; The code above failed because the buffer, or some of the characters
-     ;; in the region, are read-only.
-     ;; We should beep, in case the user just isn't aware of this.
-     ;; However, there's no harm in putting
-     ;; the region's text in the kill ring, anyway.
-     (copy-region-as-kill beg end)
-     ;; Set this-command now, so it will be set even if we get an error.
-     (setq this-command 'kill-region)
-     ;; This should barf, if appropriate, and give us the correct error.
-     (if kill-read-only-ok
-	 (message "Read only text copied to kill ring")
-       ;; Signal an error if the buffer is read-only.
-       (barf-if-buffer-read-only)
-       ;; If the buffer isn't read-only, the text is.
-       (signal 'text-read-only (list (current-buffer)))))))
-
-;; copy-region-as-kill no longer sets this-command, because it's confusing
-;; to get two copies of the text when the user accidentally types M-w and
-;; then corrects it with the intended C-w.
-(defun copy-region-as-kill (beg end)
-  "Save the region as if killed, but don't kill it.
-In Transient Mark mode, deactivate the mark.
-If `interprogram-cut-function' is non-nil, also save the text for a window
-system cut and paste."
-  (interactive "r")
-  (if (eq last-command 'kill-region)
-      (kill-append (buffer-substring beg end) (< end beg))
-    (kill-new (buffer-substring beg end)))
-  (if transient-mark-mode
-      (setq deactivate-mark t))
-  nil)
-
-(defun kill-ring-save (beg end)
-  "Save the region as if killed, but don't kill it.
-In Transient Mark mode, deactivate the mark.
-If `interprogram-cut-function' is non-nil, also save the text for a window
-system cut and paste.
-
-If you want to append the killed line to the last killed text,
-use \\[append-next-kill] before \\[kill-ring-save].
-
-This command is similar to `copy-region-as-kill', except that it gives
-visual feedback indicating the extent of the region being copied."
-  (interactive "r")
-  (copy-region-as-kill beg end)
-  (if (interactive-p)
-      (let ((other-end (if (= (point) beg) end beg))
-	    (opoint (point))
-	    ;; Inhibit quitting so we can make a quit here
-	    ;; look like a C-g typed as a command.
-	    (inhibit-quit t))
-	(if (pos-visible-in-window-p other-end (selected-window))
-	    (unless transient-mark-mode
-	      ;; Swap point and mark.
-	      (set-marker (mark-marker) (point) (current-buffer))
-	      (goto-char other-end)
-	      (sit-for 1)
-	      ;; Swap back.
-	      (set-marker (mark-marker) other-end (current-buffer))
-	      (goto-char opoint)
-	      ;; If user quit, deactivate the mark
-	      ;; as C-g would as a command.
-	      (and quit-flag mark-active
-		   (deactivate-mark)))
-	  (let* ((killed-text (current-kill 0))
-		 (message-len (min (length killed-text) 40)))
-	    (if (= (point) beg)
-		;; Don't say "killed"; that is misleading.
-		(message "Saved text until \"%s\""
-			(substring killed-text (- message-len)))
-	      (message "Saved text from \"%s\""
-		      (substring killed-text 0 message-len))))))))
-
-(defun append-next-kill (&optional interactive)
-  "Cause following command, if it kills, to append to previous kill.
-The argument is used for internal purposes; do not supply one."
-  (interactive "p")
-  ;; We don't use (interactive-p), since that breaks kbd macros.
-  (if interactive
-      (progn
-	(setq this-command 'kill-region)
-	(message "If the next command is a kill, it will append"))
-    (setq last-command 'kill-region)))
-\f
-;; Yanking.
-
-;; This is actually used in subr.el but defcustom does not work there.
-(defcustom yank-excluded-properties
-  '(read-only invisible intangible field mouse-face local-map keymap)
-  "*Text properties to discard when yanking."
-  :type '(choice (const :tag "All" t) (repeat symbol))
-  :group 'editing
-  :version 21.4)
-
-(defun yank-pop (arg)
-  "Replace just-yanked stretch of killed text with a different stretch.
-This command is allowed only immediately after a `yank' or a `yank-pop'.
-At such a time, the region contains a stretch of reinserted
-previously-killed text.  `yank-pop' deletes that text and inserts in its
-place a different stretch of killed text.
-
-With no argument, the previous kill is inserted.
-With argument N, insert the Nth previous kill.
-If N is negative, this is a more recent kill.
-
-The sequence of kills wraps around, so that after the oldest one
-comes the newest one."
-  (interactive "*p")
-  (if (not (eq last-command 'yank))
-      (error "Previous command was not a yank"))
-  (setq this-command 'yank)
-  (let ((inhibit-read-only t)
-	(before (< (point) (mark t))))
-    (delete-region (point) (mark t))
-    (set-marker (mark-marker) (point) (current-buffer))
-    (insert-for-yank (current-kill arg))
-    (if before
-	;; This is like exchange-point-and-mark, but doesn't activate the mark.
-	;; It is cleaner to avoid activation, even though the command
-	;; loop would deactivate the mark because we inserted text.
-	(goto-char (prog1 (mark t)
-		     (set-marker (mark-marker) (point) (current-buffer))))))
-  nil)
-
-(defun yank (&optional arg)
-  "Reinsert the last stretch of killed text.
-More precisely, reinsert the stretch of killed text most recently
-killed OR yanked.  Put point at end, and set mark at beginning.
-With just C-u as argument, same but put point at beginning (and mark at end).
-With argument N, reinsert the Nth most recently killed stretch of killed
-text.
-See also the command \\[yank-pop]."
-  (interactive "*P")
-  ;; If we don't get all the way thru, make last-command indicate that
-  ;; for the following command.
-  (setq this-command t)
-  (push-mark (point))
-  (insert-for-yank (current-kill (cond
-				  ((listp arg) 0)
-				  ((eq arg '-) -1)
-				  (t (1- arg)))))
-  (if (consp arg)
-      ;; This is like exchange-point-and-mark, but doesn't activate the mark.
-      ;; It is cleaner to avoid activation, even though the command
-      ;; loop would deactivate the mark because we inserted text.
-      (goto-char (prog1 (mark t)
-		   (set-marker (mark-marker) (point) (current-buffer)))))
-  ;; If we do get all the way thru, make this-command indicate that.
-  (setq this-command 'yank)
-  nil)
-
-(defun rotate-yank-pointer (arg)
-  "Rotate the yanking point in the kill ring.
-With argument, rotate that many kills forward (or backward, if negative)."
-  (interactive "p")
-  (current-kill arg))
-\f
-;; Some kill commands.
-
-;; Internal subroutine of delete-char
-(defun kill-forward-chars (arg)
-  (if (listp arg) (setq arg (car arg)))
-  (if (eq arg '-) (setq arg -1))
-  (kill-region (point) (forward-point arg)))
-
-;; Internal subroutine of backward-delete-char
-(defun kill-backward-chars (arg)
-  (if (listp arg) (setq arg (car arg)))
-  (if (eq arg '-) (setq arg -1))
-  (kill-region (point) (forward-point (- arg))))
-
 (defcustom backward-delete-char-untabify-method 'untabify
   "*The method for untabifying when deleting backward.
 Can be `untabify' -- turn a tab to many spaces, then delete one space;
@@ -2033,53 +1700,6 @@
 			 (search-forward (char-to-string char) nil nil arg)
 ;			 (goto-char (if (> arg 0) (1- (point)) (1+ (point))))
 			 (point))))
-
-;; kill-line and its subroutines.
-
-(defcustom kill-whole-line nil
-  "*If non-nil, `kill-line' with no arg at beg of line kills the whole line."
-  :type 'boolean
-  :group 'killing)
-
-(defun kill-line (&optional arg)
-  "Kill the rest of the current line; if no nonblanks there, kill thru newline.
-With prefix argument, kill that many lines from point.
-Negative arguments kill lines backward.
-With zero argument, kills the text before point on the current line.
-
-When calling from a program, nil means \"no arg\",
-a number counts as a prefix arg.
-
-To kill a whole line, when point is not at the beginning, type \
-\\[beginning-of-line] \\[kill-line] \\[kill-line].
-
-If `kill-whole-line' is non-nil, then this command kills the whole line
-including its terminating newline, when used at the beginning of a line
-with no argument.  As a consequence, you can always kill a whole line
-by typing \\[beginning-of-line] \\[kill-line].
-
-If you want to append the killed line to the last killed text,
-use \\[append-next-kill] before \\[kill-line].
-
-If the buffer is read-only, Emacs will beep and refrain from deleting
-the line, but put the line in the kill ring anyway.  This means that
-you can use this command to copy text from a read-only buffer."
-  (interactive "P")
-  (kill-region (point)
-	       ;; It is better to move point to the other end of the kill
-	       ;; before killing.  That way, in a read-only buffer, point
-	       ;; moves across the text that is copied to the kill ring.
-	       ;; The choice has no effect on undo now that undo records
-	       ;; the value of point from before the command was run.
-	       (progn
-		 (if arg
-		     (forward-visible-line (prefix-numeric-value arg))
-		   (if (eobp)
-		       (signal 'end-of-buffer nil))
-		   (if (or (looking-at "[ \t]*$") (and kill-whole-line (bolp)))
-		       (forward-visible-line 1)
-		     (end-of-visible-line)))
-		 (point))))
 
 (defun forward-visible-line (arg)
   "Move forward by ARG lines, ignoring currently invisible newlines only.
--- /dev/null	Wed Dec 31 19:00:00 1969
+++ kill-ring.el	Sun Apr 28 14:27:12 2002
@@ -0,0 +1,723 @@
+;;; kill-ring.el --- killing, yanking, and kill ring browsing
+
+;; Copyright (C) 1985, 86, 87, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, 2002
+;;        Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl)
+  (require 'derived))
+
+(defgroup killing nil
+  "Killing and yanking commands"
+  :group 'editing)
+
+\f
+;;;; Window system cut and paste hooks.
+
+(defvar interprogram-cut-function nil
+  "Function to call to make a killed region available to other programs.
+
+Most window systems provide some sort of facility for cutting and
+pasting text between the windows of different programs.
+This variable holds a function that Emacs calls whenever text
+is put in the kill ring, to make the new kill available to other
+programs.
+
+The function takes one or two arguments.
+The first argument, TEXT, is a string containing
+the text which should be made available.
+The second, PUSH, if non-nil means this is a \"new\" kill;
+nil means appending to an \"old\" kill.")
+
+(defvar interprogram-paste-function nil
+  "Function to call to get text cut from other programs.
+
+Most window systems provide some sort of facility for cutting and
+pasting text between the windows of different programs.
+This variable holds a function that Emacs calls to obtain
+text that other programs have provided for pasting.
+
+The function should be called with no arguments.  If the function
+returns nil, then no other program has provided such text, and the top
+of the Emacs kill ring should be used.  If the function returns a
+string, that string should be put in the kill ring as the latest kill.
+
+Note that the function should return a string only if a program other
+than Emacs has provided a string for pasting; if Emacs provided the
+most recent string, the function should return nil.  If it is
+difficult to tell whether Emacs or some other program provided the
+current string, it is probably good enough to return nil if the string
+is equal (according to `string=') to the last text Emacs provided.")
+\f
+
+;;;; The kill ring data structure.
+
+(defvar kill-ring nil
+  "List of killed text sequences.
+Since the kill ring is supposed to interact nicely with cut-and-paste
+facilities offered by window systems, use of this variable should
+interact nicely with `interprogram-cut-function' and
+`interprogram-paste-function'.  The functions `kill-new',
+`kill-append', and `current-kill' are supposed to implement this
+interaction; you may want to use them instead of manipulating the kill
+ring directly.")
+
+(defcustom kill-ring-max 60
+  "*Maximum length of kill ring before oldest elements are thrown away."
+  :type 'integer
+  :group 'killing)
+
+(defcustom kill-ring-menu-display-style 'one-line
+  "How to display the kill ring menu items.
+
+If `one-line', then replace newlines with \"\\n\" for display.
+
+If `separated', then display `kill-ring-menu-separator' between
+entries."
+  :type '(choice (const :tag "One line" one-line)
+		 (const :tag "Separated" separated))
+  :group 'killing)
+
+(defcustom kill-ring-menu-quit-action 'bury-and-delete-window
+  "What action to take when `kill-ring-menu-quit' is called.
+
+If `bury-buffer', then simply bury the *Kill Ring* buffer, but keep
+the window.
+
+If `bury-and-delete-window', then bury the buffer, and (if there is
+more than one window) delete the window.  This is the default.
+
+If `kill-and-delete-window', then kill the *Kill Ring* buffer, and
+delete the window on close.
+
+Otherwise, it should be a function to call."
+  :type '(choice (const :tag "Bury buffer" :value bury-buffer)
+		 (const :tag "Delete window" :value delete-window)
+		 (const :tag "Bury buffer and delete window" :value bury-and-delete-window)
+		 (const :tag "Kill buffer and delete window" :value kill-and-delete-window))
+  :group 'killing)
+
+(defcustom kill-ring-menu-maximum-display-length nil
+  "Whether or not to limit the length of displayed items.
+
+If this variable is an integer, the display of `kill-ring' will be
+limited to that many characters.
+Setting this variable to nil means no limit."
+  :type '(choice (const :tag "None" nil)
+		 integer)
+  :group 'browse-kill-ring)
+
+(defcustom kill-ring-menu-separator "-------"
+  "The string separating entries in the `separated' style.
+See `kill-ring-menu-display-style'."
+  :type 'string
+  :group 'killing)
+
+(defcustom kill-ring-menu-highlight-current-entry nil
+  "If non-nil, highlight the currently selected `kill-ring' entry."
+  :type 'boolean
+  :group 'killing)
+
+(defcustom kill-ring-menu-separator-face 'bold
+  "The face in which to highlight the `kill-ring-menu-separator'."
+  :type 'face
+  :group 'killing)
+
+(defvar kill-ring-yank-pointer nil
+  "The tail of the kill ring whose car is the last thing yanked.")
+
+(defvar kill-ring-menu-original-window nil
+  "The window in which chosen kill ring data will be inserted.
+It is probably not a good idea to set this variable directly; simply
+call `kill-ring-menu' again.")
+
+(defun kill-new (string &optional replace)
+  "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."
+  (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))))
+
+(defun kill-append (string before-p)
+  "Append STRING to the end of the latest kill in the kill ring.
+If BEFORE-P is non-nil, prepend STRING to the kill.
+If `interprogram-cut-function' is set, pass the resulting kill to
+it."
+  (kill-new (if before-p
+		(concat string (car kill-ring))
+	      (concat (car kill-ring) string))
+	    t))
+
+(defun current-kill (n &optional do-not-move)
+  "Rotate the yanking point by N places, and then return that kill.
+If N is zero, `interprogram-paste-function' is set, and calling it
+returns a string, then that string is added to the front of the
+kill ring and returned as the latest kill.
+If optional arg DO-NOT-MOVE is non-nil, then don't actually move the
+yanking point; just return the Nth kill forward."
+  (let ((interprogram-paste (and (= n 0)
+				 interprogram-paste-function
+				 (funcall interprogram-paste-function))))
+    (if interprogram-paste
+	(progn
+	  ;; Disable the interprogram cut function when we add the new
+	  ;; text to the kill ring, so Emacs doesn't try to own the
+	  ;; selection, with identical text.
+	  (let ((interprogram-cut-function nil))
+	    (kill-new interprogram-paste))
+	  interprogram-paste)
+      (or kill-ring (error "Kill ring is empty"))
+      (let ((ARGth-kill-element
+	     (nthcdr (mod (- n (length kill-ring-yank-pointer))
+			  (length kill-ring))
+		     kill-ring)))
+	(or do-not-move
+	    (setq kill-ring-yank-pointer ARGth-kill-element))
+	(car ARGth-kill-element)))))
+
+;;;; Commands for manipulating the kill ring.
+
+(defcustom kill-read-only-ok nil
+  "*Non-nil means don't signal an error for killing read-only text."
+  :type 'boolean
+  :group 'killing)
+
+(put 'text-read-only 'error-conditions
+     '(text-read-only buffer-read-only error))
+(put 'text-read-only 'error-message "Text is read-only")
+
+(defun kill-region (beg end)
+  "Kill between point and mark.
+The text is deleted but saved in the kill ring.
+The command \\[yank] can retrieve it from there.
+\(If you want to kill and then yank immediately, use \\[kill-ring-save].)
+
+If you want to append the killed region to the last killed text,
+use \\[append-next-kill] before \\[kill-region].
+
+If the buffer is read-only, Emacs will beep and refrain from deleting
+the text, but put the text in the kill ring anyway.  This means that
+you can use the killing commands to copy text from a read-only buffer.
+
+This is the primitive for programs to kill text (as opposed to deleting it).
+Supply two arguments, character numbers indicating the stretch of text
+ to be killed.
+Any command that calls this function is a \"kill command\".
+If the previous command was also a kill command,
+the text killed this time appends to the text killed last time
+to make one entry in the kill ring."
+  (interactive "r")
+  (condition-case nil
+      (let ((string (delete-and-extract-region beg end)))
+	(when string			;STRING is nil if BEG = END
+	  ;; Add that string to the kill ring, one way or another.
+	  (if (eq last-command 'kill-region)
+	      (kill-append string (< end beg))
+	    (kill-new string)))
+	(setq this-command 'kill-region))
+    ((buffer-read-only text-read-only)
+     ;; The code above failed because the buffer, or some of the characters
+     ;; in the region, are read-only.
+     ;; We should beep, in case the user just isn't aware of this.
+     ;; However, there's no harm in putting
+     ;; the region's text in the kill ring, anyway.
+     (copy-region-as-kill beg end)
+     ;; Set this-command now, so it will be set even if we get an error.
+     (setq this-command 'kill-region)
+     ;; This should barf, if appropriate, and give us the correct error.
+     (if kill-read-only-ok
+	 (message "Read only text copied to kill ring")
+       ;; Signal an error if the buffer is read-only.
+       (barf-if-buffer-read-only)
+       ;; If the buffer isn't read-only, the text is.
+       (signal 'text-read-only (list (current-buffer)))))))
+
+;; copy-region-as-kill no longer sets this-command, because it's confusing
+;; to get two copies of the text when the user accidentally types M-w and
+;; then corrects it with the intended C-w.
+(defun copy-region-as-kill (beg end)
+  "Save the region as if killed, but don't kill it.
+In Transient Mark mode, deactivate the mark.
+If `interprogram-cut-function' is non-nil, also save the text for a window
+system cut and paste."
+  (interactive "r")
+  (if (eq last-command 'kill-region)
+      (kill-append (buffer-substring beg end) (< end beg))
+    (kill-new (buffer-substring beg end)))
+  (if transient-mark-mode
+      (setq deactivate-mark t))
+  nil)
+
+(defun kill-ring-save (beg end)
+  "Save the region as if killed, but don't kill it.
+In Transient Mark mode, deactivate the mark.
+If `interprogram-cut-function' is non-nil, also save the text for a window
+system cut and paste.
+
+If you want to append the killed line to the last killed text,
+use \\[append-next-kill] before \\[kill-ring-save].
+
+This command is similar to `copy-region-as-kill', except that it gives
+visual feedback indicating the extent of the region being copied."
+  (interactive "r")
+  (copy-region-as-kill beg end)
+  (if (interactive-p)
+      (let ((other-end (if (= (point) beg) end beg))
+	    (opoint (point))
+	    ;; Inhibit quitting so we can make a quit here
+	    ;; look like a C-g typed as a command.
+	    (inhibit-quit t))
+	(if (pos-visible-in-window-p other-end (selected-window))
+	    (unless transient-mark-mode
+	      ;; Swap point and mark.
+	      (set-marker (mark-marker) (point) (current-buffer))
+	      (goto-char other-end)
+	      (sit-for 1)
+	      ;; Swap back.
+	      (set-marker (mark-marker) other-end (current-buffer))
+	      (goto-char opoint)
+	      ;; If user quit, deactivate the mark
+	      ;; as C-g would as a command.
+	      (and quit-flag mark-active
+		   (deactivate-mark)))
+	  (let* ((killed-text (current-kill 0))
+		 (message-len (min (length killed-text) 40)))
+	    (if (= (point) beg)
+		;; Don't say "killed"; that is misleading.
+		(message "Saved text until \"%s\""
+			(substring killed-text (- message-len)))
+	      (message "Saved text from \"%s\""
+		      (substring killed-text 0 message-len))))))))
+
+(defun append-next-kill (&optional interactive)
+  "Cause following command, if it kills, to append to previous kill.
+The argument is used for internal purposes; do not supply one."
+  (interactive "p")
+  ;; We don't use (interactive-p), since that breaks kbd macros.
+  (if interactive
+      (progn
+	(setq this-command 'kill-region)
+	(message "If the next command is a kill, it will append"))
+    (setq last-command 'kill-region)))
+\f
+;; Yanking.
+
+;; This is actually used in subr.el but defcustom does not work there.
+(defcustom yank-excluded-properties
+  '(read-only invisible intangible field mouse-face local-map keymap)
+  "*Text properties to discard when yanking."
+  :type '(choice (const :tag "All" t) (repeat symbol))
+  :group 'editing
+  :version 21.4)
+
+(defun yank-pop (arg)
+  "Replace just-yanked stretch of killed text with a different stretch.
+This command is allowed only immediately after a `yank' or a `yank-pop'.
+At such a time, the region contains a stretch of reinserted
+previously-killed text.  `yank-pop' deletes that text and inserts in its
+place a different stretch of killed text.
+
+With no argument, the previous kill is inserted.
+With argument N, insert the Nth previous kill.
+If N is negative, this is a more recent kill.
+
+The sequence of kills wraps around, so that after the oldest one
+comes the newest one."
+  (interactive "*p")
+  (setq this-command 'yank)
+  (let ((inhibit-read-only t)
+	(before (< (point) (mark t))))
+    (delete-region (point) (mark t))
+    (set-marker (mark-marker) (point) (current-buffer))
+    (insert-for-yank (current-kill arg))
+    (if before
+	;; This is like exchange-point-and-mark, but doesn't activate the mark.
+	;; It is cleaner to avoid activation, even though the command
+	;; loop would deactivate the mark because we inserted text.
+	(goto-char (prog1 (mark t)
+		     (set-marker (mark-marker) (point) (current-buffer))))))
+  nil)
+
+(defun yank-previous (arg)
+  "Replace previously yanked text, or display a kill ring menu.
+If the last command was a `yank', `yank-previous', or `yank-pop', then
+this command will replace a just-yanked section of text with a prevous
+entry in the kill ring, using ARG.  See `yank-pop'.
+Otherwise, this command will display a menu of kill ring entries; see
+`kill-ring-menu'."
+  (interactive "*p")
+  (if (not (memq last-command '(yank yank-previous)))
+      (kill-ring-menu)
+    (yank-pop arg)))
+
+(defun yank (&optional arg)
+  "Reinsert the last stretch of killed text.
+More precisely, reinsert the stretch of killed text most recently
+killed OR yanked.  Put point at end, and set mark at beginning.
+With just C-u as argument, same but put point at beginning (and mark at end).
+With argument N, reinsert the Nth most recently killed stretch of killed
+text.
+See also the command \\[yank-pop]."
+  (interactive "*P")
+  ;; If we don't get all the way thru, make last-command indicate that
+  ;; for the following command.
+  (setq this-command t)
+  (push-mark (point))
+  (insert-for-yank (current-kill (cond
+				  ((listp arg) 0)
+				  ((eq arg '-) -1)
+				  (t (1- arg)))))
+  (if (consp arg)
+      ;; This is like exchange-point-and-mark, but doesn't activate the mark.
+      ;; It is cleaner to avoid activation, even though the command
+      ;; loop would deactivate the mark because we inserted text.
+      (goto-char (prog1 (mark t)
+		   (set-marker (mark-marker) (point) (current-buffer)))))
+  ;; If we do get all the way thru, make this-command indicate that.
+  (setq this-command 'yank)
+  nil)
+
+(defun rotate-yank-pointer (arg)
+  "Rotate the yanking point in the kill ring.
+With argument, rotate that many kills forward (or backward, if negative)."
+  (interactive "p")
+  (current-kill arg))
+\f
+;; Some kill commands.
+
+;; Internal subroutine of delete-char
+(defun kill-forward-chars (arg)
+  (if (listp arg) (setq arg (car arg)))
+  (if (eq arg '-) (setq arg -1))
+  (kill-region (point) (forward-point arg)))
+
+;; Internal subroutine of backward-delete-char
+(defun kill-backward-chars (arg)
+  (if (listp arg) (setq arg (car arg)))
+  (if (eq arg '-) (setq arg -1))
+  (kill-region (point) (forward-point (- arg))))
+
+;; kill-line and its subroutines.
+
+(defcustom kill-whole-line nil
+  "*If non-nil, `kill-line' with no arg at beg of line kills the whole line."
+  :type 'boolean
+  :group 'killing)
+
+(defun kill-line (&optional arg)
+  "Kill the rest of the current line; if no nonblanks there, kill thru newline.
+With prefix argument, kill that many lines from point.
+Negative arguments kill lines backward.
+With zero argument, kills the text before point on the current line.
+
+When calling from a program, nil means \"no arg\",
+a number counts as a prefix arg.
+
+To kill a whole line, when point is not at the beginning, type \
+\\[beginning-of-line] \\[kill-line] \\[kill-line].
+
+If `kill-whole-line' is non-nil, then this command kills the whole line
+including its terminating newline, when used at the beginning of a line
+with no argument.  As a consequence, you can always kill a whole line
+by typing \\[beginning-of-line] \\[kill-line].
+
+If you want to append the killed line to the last killed text,
+use \\[append-next-kill] before \\[kill-line].
+
+If the buffer is read-only, Emacs will beep and refrain from deleting
+the line, but put the line in the kill ring anyway.  This means that
+you can use this command to copy text from a read-only buffer."
+  (interactive "P")
+  (kill-region (point)
+	       ;; It is better to move point to the other end of the kill
+	       ;; before killing.  That way, in a read-only buffer, point
+	       ;; moves across the text that is copied to the kill ring.
+	       ;; The choice has no effect on undo now that undo records
+	       ;; the value of point from before the command was run.
+	       (progn
+		 (if arg
+		     (forward-visible-line (prefix-numeric-value arg))
+		   (if (eobp)
+		       (signal 'end-of-buffer nil))
+		   (if (or (looking-at "[ \t]*$") (and kill-whole-line (bolp)))
+		       (forward-visible-line 1)
+		     (end-of-visible-line)))
+		 (point))))
+
+(put 'kill-ring-menu-mode 'mode-class 'special)
+(define-derived-mode kill-ring-menu-mode fundamental-mode
+  "Kill Ring"
+  "A major mode for browsing the `kill-ring'.
+You most likely do not want to call `kill-ring-menu-mode' directly; use
+`kill-ring-menu' instead.
+
+\\{kill-ring-menu-mode-map}"
+  (set (make-local-variable 'kill-ring-menu-original-window) nil)
+  (set (make-local-variable 'font-lock-defaults)
+       '(nil t nil nil nil
+	     (font-lock-fontify-region-function . kill-ring-menu-fontify-region-function)
+	     (font-lock-unfontify-region-function . kill-ring-menu-unfontify-region-function)))
+  (define-key kill-ring-menu-mode-map (kbd "q") 'kill-ring-menu-quit)
+  (define-key kill-ring-menu-mode-map (kbd "C-g") 'kill-ring-menu-quit)
+  (define-key kill-ring-menu-mode-map (kbd "d") 'kill-ring-menu-delete)
+  (define-key kill-ring-menu-mode-map (kbd "g") 'kill-ring-menu-update)
+  (define-key kill-ring-menu-mode-map (kbd "n") 'kill-ring-menu-forward)
+  (define-key kill-ring-menu-mode-map (kbd "p") 'kill-ring-menu-backward)
+  (define-key kill-ring-menu-mode-map [(mouse-2)] 'kill-ring-menu-mouse-insert)
+  (define-key kill-ring-menu-mode-map (kbd "?") 'describe-mode)
+  (define-key kill-ring-menu-mode-map (kbd "h") 'describe-mode)
+  (define-key kill-ring-menu-mode-map (kbd "RET") 'kill-ring-menu-insert))
+
+(defun kill-ring-menu-fontify-region-function (beg end &optional verbose)
+  (when verbose (message "Fontifying..."))
+  (let ((inhibit-read-only t))
+    (font-lock-fontify-on-text-properties
+     beg end 'kill-ring-menu-special 'bold)
+    (when verbose (message "Fontifying...done"))))
+
+(defun kill-ring-menu-unfontify-region-function (beg end)
+  (let ((inhibit-read-only t))
+    (remove-text-properties beg end '(face nil))))
+
+(defun kill-ring-menu-elide (str)
+  (if (and kill-ring-menu-maximum-display-length
+	   (> (length str)
+	      kill-ring-menu-maximum-display-length))
+      (concat (substring str 0 (- kill-ring-menu-maximum-display-length 3))
+	      (propertize "..." 'kill-ring-menu-special t)))
+  str)
+
+(defmacro kill-ring-menu-add-overlays-for (item &rest body)
+  (let ((beg (gensym "kill-ring-menu-add-overlays-"))
+	(end (gensym "kill-ring-menu-add-overlays-")))
+    `(let ((,beg (point))
+	   (,end
+	    (progn
+	      ,@body
+	      (point))))
+       (let ((o (make-overlay ,beg ,end)))
+	 (overlay-put o 'kill-ring-menu-target ,item)
+	 (overlay-put o 'mouse-face 'highlight)))))
+;; (put 'kill-ring-menu-add-overlays-for 'lisp-indent-function 1)
+
+(defun kill-ring-menu-insert-as-one-line (items)
+  (dolist (item items)
+    (kill-ring-menu-add-overlays-for item
+      (let* ((item (kill-ring-menu-elide item))
+	     (len (length item))
+	     (start 0)
+	     (newl (propertize "\\n" 'kill-ring-menu-special t)))
+	(while (and (< start len)
+		    (string-match "\n" item start))
+	  (insert (substring item start (match-beginning 0))
+		  newl)
+	  (setq start (match-end 0)))
+	(insert (substring item start len))))
+    (insert "\n")))
+
+(defun kill-ring-menu-insert-as-separated (items)
+  (while (cdr items)
+    (kill-ring-menu-insert-as-separated-1 (car items) t)
+    (setq items (cdr items)))
+  (when items
+    (kill-ring-menu-insert-as-separated-1 (car items) nil)))
+
+(defun kill-ring-menu-insert-as-separated-1 (origitem separatep)
+  (let* ((item (kill-ring-menu-elide origitem))
+	 (len (length item)))
+    (kill-ring-menu-add-overlays-for origitem
+	(insert item))
+    (insert "\n")
+    (when separatep
+      (insert (propertize kill-ring-menu-separator
+			  'kill-ring-menu-special t))
+      (insert "\n"))))
+
+;; (unintern 'kill-ring-menu-add-overlays-for)
+
+(defun kill-ring-menu-quit ()
+  "Take the action specified by `kill-ring-menu-quit-action'."
+  (interactive)
+  (case kill-ring-menu-quit-action
+    (kill-and-delete-window
+     (kill-buffer (current-buffer))
+     (unless (= (count-windows) 1)
+       (delete-window)))
+    (bury-and-delete-window
+     (bury-buffer)
+     (unless (= (count-windows) 1)
+       (delete-window)))
+    (t
+     (funcall kill-ring-menu-quit-action))))
+
+(defun kill-ring-menu-forward (&optional arg)
+  "Move forward by ARG `kill-ring' entries."
+  (interactive "p")
+  (beginning-of-line)
+  (while (not (zerop arg))
+    (if (< arg 0)
+	(progn
+	  (incf arg)
+	  (if (overlays-at (point))
+	      (progn
+		(goto-char (overlay-start (car (overlays-at (point)))))
+		(goto-char (previous-overlay-change (point)))
+		(goto-char (previous-overlay-change (point))))
+	    (progn
+	      (goto-char (1- (previous-overlay-change (point))))
+	      (unless (bobp)
+		(goto-char (overlay-start (car (overlays-at (point)))))))))
+      (progn
+	(decf arg)
+	(if (overlays-at (point))
+	    (progn
+	      (goto-char (overlay-end (car (overlays-at (point)))))
+	      (goto-char (next-overlay-change (point))))
+	  (goto-char (next-overlay-change (point)))
+	  (unless (eobp)
+	    (goto-char (overlay-start (car (overlays-at (point))))))))))
+  ;; This could probably be implemented in a more intelligent manner.
+  ;; Perhaps keep track over the overlay we started from?  That would
+  ;; break when the user moved manually, though.
+  (when (and kill-ring-menu-highlight-current-entry
+	     (overlays-at (point)))
+    (let ((overs (overlay-lists))
+	  (current-overlay (car (overlays-at (point)))))
+      (mapcar #'(lambda (o)
+		  (overlay-put o 'face nil))
+	      (nconc (car overs) (cdr overs)))
+      (overlay-put current-overlay 'face 'highlight))))
+
+(defun kill-ring-menu-backward (&optional arg)
+  "Move backward by ARG `kill-ring' entries."
+  (interactive "p")
+  (kill-ring-menu-forward (- arg)))
+
+(defun kill-ring-menu-do-insert (buf pt)
+  (let ((str (with-current-buffer buf
+	       (let ((overs (overlays-at pt)))
+		 (or (and overs
+			  (overlay-get (car overs) 'kill-ring-menu-target))
+		     (error "No kill ring item here"))))))
+    (let ((orig (current-buffer)))
+      (unwind-protect
+	  (progn
+	    (unless (window-live-p kill-ring-menu-original-window)
+	      (kill-ring-menu-quit)
+	      (error (substitute-command-keys "Window %s has been deleted; Try calling '\\[yank-previous]' again")
+		     kill-ring-menu-original-window))
+	    (set-buffer (window-buffer kill-ring-menu-original-window))
+	    (save-excursion
+	      (insert str)))
+	(set-buffer orig)))))
+
+(defun kill-ring-menu-mouse-insert (e)
+  "Insert the chosen text in the last selected buffer."
+  (interactive "e")
+  (let* ((end (event-end e))
+	 (win (posn-window end))
+	 (buf (window-buffer win)))
+    (select-window win)
+    (kill-ring-menu-do-insert buf (posn-point end))
+    (kill-ring-menu-quit)))
+
+(defun kill-ring-menu-insert (&optional noquit)
+  "Insert the kill ring item at point, and close the kill ring menu.
+If optional argument NOQUIT is non-nil, don't close the menu."
+  (interactive "P")
+  (kill-ring-menu-do-insert (current-buffer) (point))
+  (unless noquit
+    (kill-ring-menu-quit)))
+
+(defun kill-ring-menu-update ()
+  "Update the buffer to reflect outside changes to `kill-ring'."
+  (interactive)
+  (assert (eq major-mode 'kill-ring-menu-mode))
+  (kill-ring-menu-setup (current-buffer)
+			  kill-ring-menu-original-window))
+
+(defun kill-ring-menu-setup (buf window &optional regexp)
+  (with-current-buffer buf
+    (unwind-protect
+	(progn
+	  (kill-ring-menu-mode)
+	  (setq buffer-read-only nil)
+	  (when (eq kill-ring-menu-display-style
+		    'one-line)
+	    (setq truncate-lines t))
+	  (erase-buffer)
+	  (setq kill-ring-menu-original-window window)
+	  (let ((kill-ring-menu-maximum-display-length
+		 (if (and kill-ring-menu-maximum-display-length
+			  (<= kill-ring-menu-maximum-display-length 3))
+		     4
+		   kill-ring-menu-maximum-display-length))
+		(items (mapcar #'copy-sequence kill-ring)))
+;; 	    (when (not kill-ring-menu-display-duplicates)
+;; 	      (setq items (delete-duplicates items :test #'equal)))
+	    (when (stringp regexp)
+	      (setq items (delq nil
+				(mapcar
+				 #'(lambda (item)
+				     (when (string-match regexp item)
+				       item))
+				 items))))
+	    (funcall (intern
+		      (concat "kill-ring-menu-insert-as-"
+			      (symbol-name kill-ring-menu-display-style)))
+		     items)
+	    (if (not regexp)
+		(message "%s entries in the kill ring" (length kill-ring))
+	      (message "%s (of %s) entries in the kill ring shown"
+		       (length items) (length kill-ring)))
+	    (set-buffer-modified-p nil)
+	    (goto-char (point-min))
+	    (kill-ring-menu-forward 0)
+	    (when regexp
+	      (setq mode-name (concat "Kill Ring [" regexp "]")))
+	    (run-hooks 'kill-ring-menu-hook)))
+      (progn
+	(setq buffer-read-only t)))))
+
+;;;###autoload
+(defun kill-ring-menu ()
+  "Display items in the `kill-ring' in another buffer."
+  (interactive)
+  (let ((orig-buf (current-buffer))
+	(buf (get-buffer-create "*Kill Ring*")))
+    (kill-ring-menu-setup buf (selected-window))
+    (pop-to-buffer buf)
+    nil))
+
+(provide 'kill-ring)
--- killing.texi.~1.26.~	Wed Sep 12 17:01:34 2001
+++ killing.texi	Sun Apr 28 13:08:24 2002
@@ -270,8 +270,7 @@
 @item C-y
 Yank last killed text (@code{yank}).
 @item M-y
-Replace text just yanked with an earlier batch of killed text
-(@code{yank-pop}).
+Choose previously yanked text to insert (@code{yank-pop}).
 @item M-w
 Save region as last killed text without actually killing it
 (@code{kill-ring-save}).
@@ -374,49 +373,92 @@
 
 @cindex yanking previous kills
 @kindex M-y
-@findex yank-pop
-  To recover killed text that is no longer the most recent kill, use the
-@kbd{M-y} command (@code{yank-pop}).  It takes the text previously
-yanked and replaces it with the text from an earlier kill.  So, to
-recover the text of the next-to-the-last kill, first use @kbd{C-y} to
-yank the last kill, and then use @kbd{M-y} to replace it with the
-previous kill.  @kbd{M-y} is allowed only after a @kbd{C-y} or another
-@kbd{M-y}.
-
-  You can understand @kbd{M-y} in terms of a ``last yank'' pointer which
-points at an entry in the kill ring.  Each time you kill, the ``last
-yank'' pointer moves to the newly made entry at the front of the ring.
-@kbd{C-y} yanks the entry which the ``last yank'' pointer points to.
-@kbd{M-y} moves the ``last yank'' pointer to a different entry, and the
-text in the buffer changes to match.  Enough @kbd{M-y} commands can move
-the pointer to any entry in the ring, so you can get any entry into the
+@findex yank-previous
+  To recover killed text that is no longer the most recent kill, use
+the @kbd{M-y} command (@code{yank-previous}).  This command can act in
+two different ways.  If the previous command was not a yank, then
+@kbd{M-y} will display a menu of kill ring entries, which you can
+choose from (@code{kill-ring-menu}).  If the previous command was a
+yank, then @kbd{M-y} will replace the previously yanked text with the
+text from an earlier kill (@code{yank-pop}).
+
+@subsubsection The Kill Ring Menu 
+If you are not sure how long ago you killed the piece of text you're
+loooking for, it can often be easiest to use the kill ring menu.
+Simply type @kbd{M-y} (which was not preceeded by a @kbd{C-y}), and a
+window should pop up, which will display the text previously killed,
+one entry on each line.  In this special mode, keys do not insert
+themselves; instead, they choose actions to perform.
+
+@table @kbd
+@item RET
+Choose the text at point to yank (@code{kill-ring-menu-insert}).
+@item n
+Move point forward by one kill ring entry
+(@code{kill-ring-menu-forward}).
+@item p
+Move point backwards by one kill ring entry
+(@code{kill-ring-menu-backward}).
+@item q
+Quit the kill ring menu without yanking any text
+(@code{kill-ring-menu-quit}).
+@item d
+Remove the text at point from the kill ring
+(@code{kill-ring-menu-delete}).
+@end table
+
+The kill ring menu can display multi-line text; In the default display
+style, all text is shown on one line, and newlines are shown as a
+@samp{\n}.
+
+@subsubsection Cycling Through Yanked Text
+
+If you know precisely where the text you previously yanked is in the
+@code{kill-ring}, or it was very recently yanked, you may find using
+the @code{yank-pop} functionality of @kbd{M-y} to be faster than the
+kill ring menu.  For example, to recover the text of the
+next-to-the-last kill, you could first use @kbd{C-y} to yank the last
+kill, and then type @kbd{M-y} to replace it with the previous kill.
+
+  You can understand @code{yank-pop} in terms of a ``last yank''
+pointer which points at an entry in the kill ring.  Each time you
+kill, the ``last yank'' pointer moves to the newly made entry at the
+front of the ring.  @kbd{C-y} yanks the entry which the ``last yank''
+pointer points to.  After that, typing @kbd{M-y} moves the ``last
+yank'' pointer to a different entry, and the text in the buffer
+changes to match.  Enough @code{yank-pop} commands can move the
+pointer to any entry in the ring, so you can get any entry into the
 buffer.  Eventually the pointer reaches the end of the ring; the next
 @kbd{M-y} loops back around to the first entry again.
 
-  @kbd{M-y} moves the ``last yank'' pointer around the ring, but it does
-not change the order of the entries in the ring, which always runs from
-the most recent kill at the front to the oldest one still remembered.
-
-  @kbd{M-y} can take a numeric argument, which tells it how many entries
-to advance the ``last yank'' pointer by.  A negative argument moves the
-pointer toward the front of the ring; from the front of the ring, it
-moves ``around'' to the last entry and continues forward from there.
-
-  Once the text you are looking for is brought into the buffer, you can
-stop doing @kbd{M-y} commands and it will stay there.  It's just a copy
-of the kill ring entry, so editing it in the buffer does not change
-what's in the ring.  As long as no new killing is done, the ``last
-yank'' pointer remains at the same place in the kill ring, so repeating
-@kbd{C-y} will yank another copy of the same previous kill.
-
-  If you know how many @kbd{M-y} commands it would take to find the
-text you want, you can yank that text in one step using @kbd{C-y} with
-a numeric argument.  @kbd{C-y} with an argument restores the text from
-the specified kill ring entry, counting back from the most recent as
-1.  Thus, @kbd{C-u 2 C-y} gets the next-to-the-last block of killed
+  @code{yank-pop} moves the ``last yank'' pointer around the ring, but
+it does not change the order of the entries in the ring, which always
+runs from the most recent kill at the front to the oldest one still
+remembered.
+
+  @code{yank-pop} can take a numeric argument, which tells it how many
+entries to advance the ``last yank'' pointer by.  A negative argument
+moves the pointer toward the front of the ring; from the front of the
+ring, it moves ``around'' to the last entry and continues forward from
--- font-lock.el.~1.195.~	Fri Apr  5 04:37:40 2002
+++ font-lock.el	Sun Apr 28 03:41:17 2002
@@ -1358,6 +1358,32 @@
       (put-text-property start next prop value object)
       (setq start (text-property-any next end prop nil object)))))
 
+(defun font-lock-fontify-on-text-properties (beg end &rest plist)
+  "Match areas of text which have text properties with faces.
+Only areas of text between BEG and END are considered.  The remaining
+arguments should form a property list which looks like
+ (PROPERTY FACE PROPERTY FACE ...)."
+  (save-excursion
+    (let ((change-end nil))
+      (while plist
+	(goto-char beg)
+	(while (and plist
+		    (setq change-end (font-lock-fontify-on-text-property
+				      (car plist) (cadr plist) (point) end)))
+	  (goto-char change-end))
+	(setq plist (cddr plist))))))
+
+(defun font-lock-fontify-on-text-property (prop face beg end)
+  "Add face FACE to areas of text which have text property PROP.
+Only areas of text between BEG and END are considered."
+  (let ((prop-beg (or (and (get-text-property (point) prop) (point))
+		      (next-single-property-change (point) prop nil end))))
+    (when (and prop-beg (not (= prop-beg end)))
+      (let ((prop-end (next-single-property-change beg prop nil end)))
+	(when (and prop-end (not (= prop-end end)))
+	  (put-text-property prop-beg prop-end 'face face)
+	  prop-end)))))
+
 ;; For completeness: this is to `remove-text-properties' as `put-text-property'
 ;; is to `add-text-properties', etc.
 ;(defun remove-text-property (start end property &optional object)

             reply	other threads:[~2002-04-28 19:41 UTC|newest]

Thread overview: 82+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-04-28 19:41 Colin Walters [this message]
2002-04-28 20:06 ` kill ring menu Colin Walters
2002-04-29  5:05   ` Richard Stallman
2002-04-29 18:40     ` Richard Stallman
2002-04-28 22:53 ` Miles Bader
2002-04-28 23:36 ` Stefan Monnier
2002-04-28 23:42   ` Miles Bader
2002-04-29  4:34   ` Colin Walters
2002-04-30  4:49     ` Eli Zaretskii
2002-04-29  3:35 ` Miles Bader
2002-04-29  4:37   ` Colin Walters
2002-04-29  4:56     ` Miles Bader
2002-04-29  5:37       ` Colin Walters
2002-04-29  7:09         ` Miles Bader
2002-04-30  5:18           ` Richard Stallman
2002-04-30 10:18             ` Per Abrahamsen
2002-04-29  9:22         ` CC (was: Re: kill ring menu) Per Abrahamsen
2002-04-29 15:11           ` Benjamin Rutt
2002-04-29 15:31             ` Miles Bader
2002-04-30  5:19             ` Richard Stallman
2002-04-30 10:14           ` Per Abrahamsen
2002-04-30 11:08             ` Simon Josefsson
2002-04-29 10:10         ` Addressing email (was: " Eli Zaretskii
2002-04-29 13:13         ` kill ring menu Stefan Monnier
2002-04-29 18:40   ` Richard Stallman
     [not found] ` <200204290505.g3T55t006146@aztec.santafe.edu>
     [not found]   ` <1020059236.31789.358.camel@space-ghost>
     [not found]     ` <200204300519.g3U5Js306727@aztec.santafe.edu>
     [not found]       ` <1020212569.27106.2246.camel@space-ghost>
     [not found]         ` <200205011926.g41JQBC07690@aztec.santafe.edu>
     [not found]           ` <1020284783.27106.3417.camel@space-ghost>
2002-05-03 18:25             ` Richard Stallman
2002-05-03 18:46               ` Miles Bader
2002-05-03 19:05               ` Miles Bader
2002-05-03 20:20                 ` Colin Walters
2002-05-04  1:34                   ` Miles Bader
2002-05-04  3:36                 ` Richard Stallman
2002-05-04  3:49                   ` Miles Bader
2002-05-05  5:34                     ` Richard Stallman
2002-05-04  6:04                 ` Eli Zaretskii
     [not found]       ` <1020320725.27616.54.camel@space-ghost>
     [not found]         ` <200205031825.g43IPuD00768@aztec.santafe.edu>
     [not found]           ` <1020502030.5286.25.camel@space-ghost>
2002-05-05 17:46             ` Richard Stallman
2002-05-06  5:15               ` Colin Walters
2002-05-06  6:39                 ` Miles Bader
2002-05-06 22:55                   ` Colin Walters
2002-05-07  1:35                     ` Miles Bader
2002-05-07  3:55                       ` Colin Walters
2002-05-07  4:18                         ` Miles Bader
2002-05-07 20:07                         ` Richard Stallman
2002-05-07 20:38                           ` Colin Walters
2002-05-08  0:20                             ` Miles Bader
2002-05-08  6:05                               ` Colin Walters
2002-05-08  6:50                                 ` Miles Bader
2002-05-08  7:36                                   ` Colin Walters
2002-05-08  7:48                                     ` Miles Bader
2002-05-08  8:57                                     ` Colin Walters
2002-05-08 13:14                                       ` Stefan Monnier
2002-05-09  4:29                                         ` Colin Walters
2002-05-09 10:08                                           ` Kim F. Storm
2002-05-09  2:45                             ` Richard Stallman
2002-05-09  4:28                               ` Colin Walters
2002-05-10  0:30                                 ` Richard Stallman
2002-05-16 18:47                                   ` Colin Walters
2002-05-16 19:12                                     ` Miles Bader
2002-05-16 19:20                                       ` Colin Walters
2002-05-16 19:36                                         ` Miles Bader
2002-05-16 19:45                                           ` Miles Bader
2002-05-16 19:54                                           ` Colin Walters
2002-05-16 20:12                                     ` Miles Bader
2002-05-16 20:17                                       ` Colin Walters
2002-05-16 20:23                                         ` Miles Bader
2002-05-16 21:47                                           ` Colin Walters
2002-05-16 21:54                                           ` Kim F. Storm
2002-05-16 21:15                                             ` Miles Bader
2002-05-17 19:29                                       ` Richard Stallman
2002-05-07 19:22                     ` Alex Schroeder
2002-05-09 20:09                       ` Colin Walters
2002-05-11  6:30                       ` Richard Stallman
2002-05-13 22:17                         ` Colin Walters
2002-05-14  8:36                           ` Miles Bader
2002-05-14 12:49                           ` Emacs 21.4 (was: kill ring menu) Eli Zaretskii
2002-05-15  7:01                           ` kill ring menu Richard Stallman
2002-05-06  6:46                 ` Stephen J. Turnbull
2002-05-06 22:46                   ` Colin Walters
2002-05-08 10:06                     ` Francesco Potorti`
2002-05-08 10:20                       ` Eli Zaretskii
2002-05-06 19:32                 ` Richard Stallman
2002-05-07  4:03                   ` Colin Walters
2002-05-07  5:27                     ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1020022891.27106.142.camel@space-ghost \
    --to=walters@debian.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).