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

后端 未结 8 985
無奈伤痛
無奈伤痛 2021-01-31 16:23

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
相关标签:
8条回答
  • 2021-01-31 17:09

    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.

    0 讨论(0)
  • 2021-01-31 17:09

    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)
    )
    
    0 讨论(0)
  • 2021-01-31 17:13
    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).

    0 讨论(0)
  • 2021-01-31 17:19

    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))
    
    0 讨论(0)
  • 2021-01-31 17:19

    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.

    0 讨论(0)
  • 2021-01-31 17:20

    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)
    
    0 讨论(0)
提交回复
热议问题