summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'lisp')
-rw-r--r--lisp/delsel.el2
-rw-r--r--lisp/isearch.el17
-rw-r--r--lisp/simple.el124
3 files changed, 114 insertions, 29 deletions
diff --git a/lisp/delsel.el b/lisp/delsel.el
index df2adc7aeba..e1087fb3919 100644
--- a/lisp/delsel.el
+++ b/lisp/delsel.el
@@ -274,6 +274,8 @@ to `delete-selection-mode'."
(put 'quoted-insert 'delete-selection t)
(put 'yank 'delete-selection 'yank)
+(put 'yank-pop 'delete-selection 'yank)
+(put 'yank-from-kill-ring 'delete-selection 'yank)
(put 'clipboard-yank 'delete-selection 'yank)
(put 'insert-register 'delete-selection t)
;; delete-backward-char and delete-forward-char already delete the selection by
diff --git a/lisp/isearch.el b/lisp/isearch.el
index 4fba4370d98..a0aa250c4b6 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -2500,11 +2500,18 @@ If search string is empty, just beep."
"Replace just-yanked search string with previously killed string."
(interactive)
(if (not (memq last-command '(isearch-yank-kill isearch-yank-pop)))
- ;; Fall back on `isearch-yank-kill' for the benefits of people
- ;; who are used to the old behavior of `M-y' in isearch mode. In
- ;; future, this fallback may be changed if we ever change
- ;; `yank-pop' to do something like the kill-ring-browser.
- (isearch-yank-kill)
+ ;; Yank string from kill-ring-browser.
+ (with-isearch-suspended
+ (let ((string (read-from-kill-ring)))
+ (if (and isearch-case-fold-search
+ (eq 'not-yanks search-upper-case))
+ (setq string (downcase string)))
+ (if isearch-regexp (setq string (regexp-quote string)))
+ (setq isearch-yank-flag t)
+ (setq isearch-new-string (concat isearch-string string)
+ isearch-new-message (concat isearch-message
+ (mapconcat 'isearch-text-char-description
+ string "")))))
(isearch-pop-state)
(isearch-yank-string (current-kill 1))))
diff --git a/lisp/simple.el b/lisp/simple.el
index bb28145502b..69b4639292a 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -5344,7 +5344,7 @@ Normally set from the UNDO element of a yank-handler; see `insert-for-yank'.")
(defun yank-pop (&optional arg)
"Replace just-yanked stretch of killed text with a different stretch.
-This command is allowed only immediately after a `yank' or a
+The main use of this command is 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 by
@@ -5359,30 +5359,36 @@ comes the newest one.
This command honors the `yank-handled-properties' and
`yank-excluded-properties' variables, and the `yank-handler' text
-property, in the way that `yank' does."
- (interactive "*p")
+property, in the way that `yank' does.
+
+When this command is called not immediately after a `yank' or a
+`yank-pop', then it activates the minibuffer with its completion
+and history filled with previously-killed items from the
+`kill-ring' variable, and reads a string to yank at point.
+See `yank-from-kill-ring' for more details."
+ (interactive "p")
(if (not (eq last-command 'yank))
- (user-error "Previous command was not a yank"))
- (setq this-command 'yank)
- (unless arg (setq arg 1))
- (let ((inhibit-read-only t)
- (before (< (point) (mark t))))
- (if before
- (funcall (or yank-undo-function 'delete-region) (point) (mark t))
- (funcall (or yank-undo-function 'delete-region) (mark t) (point)))
- (setq yank-undo-function nil)
- (set-marker (mark-marker) (point) (current-buffer))
- (insert-for-yank (current-kill arg))
- ;; Set the window start back where it was in the yank command,
- ;; if possible.
- (set-window-start (selected-window) yank-window-start t)
- (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)
+ (yank-from-kill-ring (read-from-kill-ring) current-prefix-arg)
+ (setq this-command 'yank)
+ (unless arg (setq arg 1))
+ (let ((inhibit-read-only t)
+ (before (< (point) (mark t))))
+ (if before
+ (funcall (or yank-undo-function 'delete-region) (point) (mark t))
+ (funcall (or yank-undo-function 'delete-region) (mark t) (point)))
+ (setq yank-undo-function nil)
+ (set-marker (mark-marker) (point) (current-buffer))
+ (insert-for-yank (current-kill arg))
+ ;; Set the window start back where it was in the yank command,
+ ;; if possible.
+ (set-window-start (selected-window) yank-window-start t)
+ (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 (\"paste\") the last stretch of killed text.
@@ -5449,6 +5455,76 @@ See also the command `yank-pop' (\\[yank-pop])."
With ARG, rotate that many kills forward (or backward, if negative)."
(interactive "p")
(current-kill arg))
+
+(defvar read-from-kill-ring-history)
+(defun read-from-kill-ring ()
+ "Read a string from `kill-ring' using completion and minibuffer history."
+ (let* ((history-add-new-input nil)
+ (ellipsis (if (char-displayable-p ?…) "…" "..."))
+ ;; Remove keymaps from text properties of copied string,
+ ;; because typing RET in the minibuffer might call
+ ;; an irrelevant command from the map of copied string.
+ (read-from-kill-ring-history
+ (mapcar (lambda (s)
+ (remove-list-of-text-properties
+ 0 (length s)
+ '(
+ keymap local-map action mouse-action
+ button category help-args)
+ s)
+ s)
+ kill-ring))
+ (completions
+ (mapcar (lambda (s)
+ (let* ((s (query-replace-descr s))
+ (b 0))
+ ;; Add ellipsis on leading whitespace
+ (when (string-match "\\`[[:space:]]+" s)
+ (setq b (match-end 0))
+ (add-text-properties 0 b `(display ,ellipsis) s))
+ ;; Add ellipsis at the end of a long string
+ (when (> (length s) (+ 40 b))
+ (add-text-properties
+ (min (+ 40 b) (length s)) (length s)
+ `(display ,ellipsis) s))
+ s))
+ read-from-kill-ring-history)))
+ (minibuffer-with-setup-hook
+ (lambda ()
+ ;; Allow ‘SPC’ to be self-inserting
+ (use-local-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map (current-local-map))
+ (define-key map " " nil)
+ (define-key map "?" nil)
+ map)))
+ (completing-read
+ "Yank from kill-ring: "
+ (lambda (string pred action)
+ (if (eq action 'metadata)
+ ;; Keep sorted by recency
+ '(metadata (display-sort-function . identity))
+ (complete-with-action action completions string pred)))
+ nil nil nil
+ 'read-from-kill-ring-history))))
+
+(defun yank-from-kill-ring (string &optional arg)
+ "Insert the `kill-ring' item selected from the minibuffer history.
+Use minibuffer navigation and search commands to browse the
+previously-killed items from the `kill-ring' variable in the
+minibuffer history before typing RET to insert the selected item,
+or use completion on the elements of `kill-ring'. You can edit
+the item in the minibuffer before inserting it.
+
+With \\[universal-argument] as argument, put point at beginning,
+and mark at end, like `yank' does."
+ (interactive (list (read-from-kill-ring) current-prefix-arg))
+ (push-mark)
+ (insert-for-yank string)
+ (if (consp arg)
+ ;; Swap point and mark like in `yank'.
+ (goto-char (prog1 (mark t)
+ (set-marker (mark-marker) (point) (current-buffer))))))
;; Some kill commands.