KillingAndYanking

Vocabulary: In Emacs, we call killing what others call cutting, and yanking what others call pasting. killing moves text from the document to the top of the kill ring. We call “saving onto the kill-ring” what others call copying text. The kill-ring is similar to a clipboard: it is a list of the last 60 killed items, from which items can be yanked.

The default command for killing the selected region is ‘kill-region’ (‘C-w’). The command for saving (copying) text to the ‘kill-ring’ is ‘kill-ring-save’ (‘M-w’).

The default command for killing the rest of the current line is ‘kill-line’ (‘C-k’). The default command for killing the rest of a sentence is ‘kill-sentence’ (‘M-k’). As always, repeated invocations of kill commands prepend the kills, in order, to the ‘kill-ring’.

The default command for yanking a copy of the top entry on the kill-ring into the buffer is ‘yank’ (‘C-y’).

Yanking inserts the last killed item from the head of the list, but you can cycle through the list to instead yank previously killed or copied text using ‘M-y’.

Text removed with the ‘delete-*’ commands, such as ‘delete-backwards-char’ (‘DEL’), is not saved to the ‘kill-ring’.

Cycling through the kill-ring

‘M-y’ (‘yank-pop’) cycles backwards through the ‘kill-ring’. Here’s a way to cycle in the reverse direction with ‘M-Y’ (Meta-Shift-Y):

    (defun yank-pop-forwards (arg)
      (interactive "p")
      (yank-pop (- arg)))
    (global-set-key "\M-Y" 'yank-pop-forwards) ; M-Y (Meta-Shift-Y)

Deleting word backwards

The following may be of interest to people who (a) are happy with ‘C-w’ and friends for killing and yanking, (b) use ‘transient-mark-mode’, (c) also like the traditional Unix TTY behaviour that ‘C-w’ deletes a word backwards and (d) use GnuEmacs. It tweaks ‘C-w’ so that, if the mark is inactive, it deletes a word backwards instead of killing the region:

    (defadvice kill-region (before unix-werase activate compile)
      "When called interactively with no active region, delete a single word
    backwards instead."
      (interactive
       (if mark-active (list (region-beginning) (region-end))
         (list (save-excursion (backward-word 1) (point)) (point)))))

Doing this as advice (as opposed to a new function bound to C-w) seems like a bad idea – what happens if some other elisp function calls ‘kill-region’?

Could not agree more. What if ‘transient-mark-mode’ is not on? This is a poor use of advice.

    (defun unix-werase-or-kill (arg)
      (interactive "*p")
      (if (and transient-mark-mode
        	   mark-active)
          (kill-region (region-beginning) (region-end))
        (backward-kill-word arg)))

I don’t think this is a problem, since the advice is interactive. Thus it is not invoked in a regular function call.

As it happens, the same principle is employed in WholeLineOrRegion, which copies the current line when the mark is inactive.

Interleaved Yanking

I made the following function so that you could yank a block of lines onto an existing block of lines in the buffer – each line in the yanked block either goes at the front or the end of the existing buffer lines, depending on where point starts. The idea is that this is a bit like rectangle yanking, except line lengths are honored, and it won’t cut anything off.

    (defun yank-interleaved (separator)
      "Yank the previous kill, interleaving each line of the yanked
      text with a line in current buffer.
    
    Interleaving begins on the line containing point, and moves
    downward. If point is at the beginning of the line, the yanked
    lines are inserted before the buffer lines. If it is at the end
    of the line, the yanked lines are inserted after.
    
    If the argument SEPARATOR is given, insert this between each
    buffer line and yanked line."
      ;; TODO: Make it work with active region
      (interactive "MSeparator: ")
      (let ((yank (current-kill 1 t))
             dir line)
        (if (null (string-match-p "\n" yank))
    	    (yank)
          (setq dir
    	        (cond
    	         ((bolp) 'front)
    	         ((eolp) 'back)
    	         (t (user-error "Call with point at beginning or end of line"))))
          (setq yank (split-string yank "\n" t "\\s-"))
          (while (setq line (pop yank))
    	    (if (eq dir 'front)
    	        (progn
    	          (beginning-of-line)
    	          (insert line)
    	          (insert separator))
    	      (end-of-line)
    	      (insert separator)
    	      (insert line))
       	   (forward-line)))))

See also:


CategoryRegion