Emacs: How to yank the last yanked text regardless of subsequent kills?

只愿长相守 提交于 2019-12-20 08:57:31

问题


I often find myself repeatedly yanking something after doing some kills and it becomes a process like:

  1. C-y
  2. C-y M-y
  3. C-y M-y M-y
  4. C-y M-y M-y M-y

Each time I kill some text it pushes the first kill back in the kill ring so that I need to cycle through all the kills to return to text I want to yank. What I want to do is repeatedly yank the same text while killing text in-between yanks. Is this possible?


回答1:


This is a strange hack, but may help.

The first time you use M-y you normally get an error (no previous yank). So the idea is that this first time you get the last yank instead of the last kill.

For storing that last yank I use the 'Y' register in this example.

These 2 functions would wrap around yank and yank-pop. You expect bugs, I expect suggestions.

(defun jp/yank (&optional arg)
  "Yank and save text to register Y"
  (interactive)
  (set-register ?Y (current-kill 0 t))
  (yank arg))

(defun jp/yank-pop (&optional arg)
  "If yank-pop fails, then insert register Y"
  (interactive)
  (condition-case nil
      (yank-pop arg)
    (error (insert (get-register ?Y)))))

(global-set-key (kbd "M-y") (quote jp/yank-pop))
(global-set-key (kbd "C-y") (quote jp/yank))



回答2:


Don't use the kill ring; put the text into a register instead. C-x r s a to store the region's text into (say) register "a"; then C-x r i a to insert it elsewhere.




回答3:


You could use M-x delete-region instead to kill the text, possibly binding it to a key if you want to use it a lot.




回答4:


  1. If you want to repeatedly yank the same text, use the secondary selection instead of the region or killed text.

    What's missing from vanilla Emacs is a key binding to yank the secondary selection. I use C-M-y for that (see library second-sel.el).

  2. To get direct access to any kills in the kill ring, use M-y with Browse Kill Ring or with Icicles. In both cases, M-y at top level gives you access to all entries in the kill ring.

    And if you use library second-sel.el then, in addition to the kill ring, you have access to a ring of your past secondary selections.

    And if you use library second-sel.el and Icicles then M-y yanks an entry from the the ring you last yanked from (kill ring or secondary-selection ring).

    And if you use library browse-kill-ring+.el then the kill-ring browser gives you access to an alternative ring also (which, by default, is the ring of secondary selections if you use library second-sel.el).




回答5:


I am trying to hack along the line of using a minor mode. Let's call this delete-mode. Once you get into delete mode, kill commands (kill-line, kill-paragraph, kill-word, ...) will change their behavior so that the kill-region part of their commands will be replaced by delete-region, and new material will not be added to the kill ring. While in this mode, the kill ring will stay constant. When you switch back out of this mode, the behaviour returns to normal.

The following is an incomplete code attempting to implement what I wrote above. It works correctly in switching to delete mode, but it has problem switching back (turning the minor mode off). Any help fixing this would be appreciated.

(defvar delete-mode nil)

(defun delete-mode ()
    "delete minor-mode"
    (interactive)
    (setq delete-mode (not delete-mode))
    (if delete-mode
        (defalias 'kill-region 'delete-region)
        (defalias 'kill-region 'original-kill-region)
    )
)

(if (not (assq 'delete-mode minor-mode-alist))
    (setq minor-mode-alist
        (cons '(delete-mode "Delete mode on") minor-mode-alist)
    )
    (defalias 'original-kill-region 'kill-region)
)



回答6:


I'll try to use delete-region more, but I know the kill commands better. A trick that requires no programming or advance planning is to use M-w after a particularly annoying string of M-y. This puts a more accessible copy of the final yank into the kill ring.




回答7:


A Better Yank-Pop Implementation

This defines a better yank-pop implementation which tries to fix the increasing yank-pop problem.

It only overrides the function "current-kill". Due to the modular design of yank, yank-pop, and the kill ring variables and functions in Emacs, it turns out that overriding "current-kill" is all that is necessary to get the behavior we want.

The desired behavior is that (1) killing something still puts it at the front of the kill ring, but now (2) yanking or yank-popping something also puts it at the front of the kill ring (3) we preserve the ability of yank-pop to give the appearance of moving through the kill ring by incrementing a global variable and using this to replace the last yank-pop'ped item back where it was. This also means that (4) items which are transitionally yanked (i.e. items placed by yank or yank-pop commands, where the next command is a yank-pop) ultimately get to stay where they are in the kill ring.

;; Example:
;; (setq kill-ring '("a" "b" "c" "d" "e"))
;;
;; keystroke        kill ring contents              value of kill-ring-yank-index
;; C-y              ("a" "b" "c" "d" "e")           0
;; M-y              ("b" "a" "c" "d" "e")           1
;; M-y              ("c" "a" "b" "d" "e")           2
;; M-y              ("d" "a" "b" "c" "e")           3

;; C-y              ("d" "a" "b" "c" "e")           0
;; M-y              ("a" "d" "b" "c" "e")           1

;; M-d              ("x" "a" "d" "b" "c" "e")
;; etc.

the code:

;; ----------------------------------------------------------------
;; helper functions

(defun list-insert-before (l n x)
  (if (<= n 0) (cons x l)
    (cons (car l) (list-insert-before (cdr l) (- n 1) x))))

(defun list-prepend-nth (l n)
  (if (<= n 0) l
    (let* ((lx (list-prepend-nth (cdr l) (- n 1))))
      (cons (car lx) (cons (car l) (cdr lx))))))

(defun list-insert-car-at (l n)
  (list-insert-before (cdr l) n (car l)))


;; ----------------------------------------------------------------
;; overriding current-kill

(defvar kill-ring-yank-index 0
  "Index into kill-ring of last yank-pop. The item yank-popped
  will be at the head of the kill ring, but if the next command
  is also yank-pop, it will be returned here first before this
  variable is incremented.")

(defun current-kill (n)
  "Replaces standard 'current-kill' function. This version tries
to fix the increasing yank-pop problem.

TODO:
- respect second argument of original function
- deal with 'interprogram-{cut,paste}-function'
"
  (if (eq 0 n) ;; looks like we're doing a yank; reset
               ;; kill-ring-yank-index to 0 to indicate that the
               ;; current head of the list is useful to the user
      (progn (setq kill-ring-yank-index 0)
             (car kill-ring))

    ;; otherwise put the head of kill-ring back where we had
    ;; previously found it, and fetch the next element
    (setq kill-ring
        (list-insert-car-at kill-ring kill-ring-yank-index))
    (setq kill-ring-yank-index (+ kill-ring-yank-index n))
    (when (>= kill-ring-yank-index (- (length kill-ring) 1))
      (setq kill-ring-yank-index (- (length kill-ring) 1))
      (message "Reached end of kill-ring"))
    (when (< kill-ring-yank-index 0)
      (setq kill-ring-yank-index 0)
      (message "Reached beginning of kill-ring"))
    (setq kill-ring (list-prepend-nth kill-ring kill-ring-yank-index))
    (car kill-ring)))

;; ----------------------------------------------------------------
;; new key binding

;; Here's an auxiliary function and key binding that makes it easy to
;; go back and forth in the kill-ring while we're yank-popping
(defun yank-pop-back () "" (interactive "*")
       (yank-pop -1))

(global-set-key "\C-\M-y" 'yank-pop-back)



回答8:


I use

M-x browse-kill-ring

with keybinding 'M-y'. There is also helm support.

https://www.emacswiki.org/emacs/BrowseKillRing

offers more solutions.



来源:https://stackoverflow.com/questions/5823495/emacs-how-to-yank-the-last-yanked-text-regardless-of-subsequent-kills

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!