M-x all-things-emacs

Copying Lines, not killing

May 18th, 2009 by Greg Reagle · 27 Comments

Do you find yourself often running a yank or undo immediately after killing lines? Would you like to copy a line instead of killing it? Do you wish that there was a prefix argument to C-k (kill-line) that made it copy instead of cut (to use the non-Emacs terminology). Here is your solution—a command that acts just like kill-line except that it is a copy.

(defun copy-line (&optional arg)
  "Do a kill-line but copy rather than kill.  This function directly calls
kill-line, so see documentation of kill-line for how to use it including prefix
argument and relevant variables.  This function works by temporarily making the
buffer read-only, so I suggest setting kill-read-only-ok to t."
  (interactive "P")
  (toggle-read-only 1)
  (kill-line arg)
  (toggle-read-only 0))
 
(setq-default kill-read-only-ok t)
(global-set-key "\C-c\C-k" 'copy-line)

See also http://www.emacswiki.org/emacs/CopyingWholeLines.

Tags: newbie · quick · tips

27 responses so far ↓

  • 1 Vimbo // May 19, 2009 at 12:04 am

    You mean Emacs doesn’t have the simple vim commands for kill-copy line (D) and yank line (Y)? =P

    Okay, okay. I’m a sucker for Lisp so I’ll let emacs’s quirks slide.

  • 2 WZ // May 19, 2009 at 12:13 am

    What’s wrong with M-w?

  • 3 Jacob // May 19, 2009 at 12:18 am

    yeah as WZ said kill-ring-save normally bound to M-w

  • 4 Greg Reagle // May 19, 2009 at 1:46 am

    Yes, M-w is an option, but it requires the region to be marked first instead of working on lines.

  • 5 bread // May 19, 2009 at 2:43 pm

    i use (kill-ring-save (line-beginning-position) (line-end-position)) to copy current line

  • 6 wilsaj // May 19, 2009 at 3:10 pm

    Is C-c C-k really easier than C-k C-y? I’m not being snarky, I’m legitimately curious.

  • 7 Ryan McGeary // May 19, 2009 at 4:54 pm

    To each, his own. For me, I’ll probably never rewire my brain away from C-k C-y, but Greg’s hack of playing off of the read-only features of kill-line is an interesting approach. There are probably a half a dozen good ways of doing this.

    For a key binding, I probably would chose M-k for copy-line to coincide with M-w (kill-ring-save). M-k is normally kill-sentence, but I never use it.

  • 8 Trey Jackson // May 19, 2009 at 5:33 pm

    Stylistic comment, might be cleaner to use a let (in case something ever goes wrong with the command)

    (let ((buffer-read-only t))
    (kill-line arg))

  • 9 Tim Christian // May 19, 2009 at 7:22 pm

    Very clever solutions.

    Caveat lector nostalgia: Back in the late nineties when I was moving to emacs from Q-Edit, I craved the same functionality, so I wrote the following after going through the elisp tutorial and still use it today. I don’t mark anything, I just use my bound key and it assumes I want the whole line copied. I’d revisit my hack more if it didn’t work reasonably and reliably for the last 10+ years.

    (defun tjc-duplicate-line (arg)
    “Copy current line beneath itself. Move point to new copy of line in
    exact same position as previous line.”
    (interactive “p”)
    (let ((orig (point)))
    (beginning-of-line)
    (let ((beg (point)))
    (end-of-line)
    (let ((end (point)))
    (copy-region-as-kill beg end)
    (newline)
    (yank)
    ;; Place point on copied line at column where point was on
    ;; previous line.
    (goto-char (+ orig (- end orig) (- orig beg) 1))))))

    (defun tjc-kill-line (arg)
    “Kill the current line and move to next line. Place point in same column
    as deleted line or place point at end of line if line is shorter than deleted
    line.”
    (interactive “p”)
    (let ((orig (point)))
    (beginning-of-line)
    (let ((beg (point)))
    (forward-line 1)
    (delete-region beg (point)))
    ;;If line is shorter than previous line, then just go to end of line.
    (end-of-line)
    (let ((new (point)))
    (if (< orig new)
    (goto-char orig)))))

  • 10 Greg Reagle // May 19, 2009 at 8:11 pm

    In response to ilsaj:
    > Is C-c C-k really easier than C-k C-y?
    > I’m not being snarky, I’m legitimately curious.

    Command copy-line could be bound to a single key (for instance M-k as Ryan suggested) then it would be less typing, but the significant advantage is not in the number of keystrokes. C-k C-y makes Emacs think the buffer has been modified when it hasn’t (see mode line), and adds to the undo-history when it shouldn’t—a copy doesn’t need to be undone.

    In response to WZ:
    > What’s wrong with M-w?

    Upon further consideration, this idea is really growing on me, and I might like it better than my custom function copy-line. I can copy lines by doing or some variation. Like the custom copy-line function that I wrote, it does not affect mode line (was buffer modified status) or undo history. It is a little less convenient, but it has the benefit of being standard, which I consider a significant advantage.

    Even if I ultimately wind up using M-w rather than the custom copy-line function, this has been a great discussion and I’ve learned a lot. Thanks everyone for your comments.

  • 11 Greg Reagle // May 19, 2009 at 8:32 pm

    Correction of my previous comment:
    “I can copy lines by doing C-SPC C-n M-w or some variation”

  • 12 Marius Andersen // May 19, 2009 at 11:39 pm

    I prefer the SlickEdit/TextMate way of copying and cutting lines: if no text is selected, the current line is acted on instead. No extra functions, just clever behavior.

    To implement this in Emacs, see http://www.emacswiki.org/emacs/SlickCopy

  • 13 Anonymous // May 22, 2009 at 12:53 am

    Call me a weenie if you like, but I like simply enabling (pc-selection-mode 1). Then all the hard work is done for you. Copying lines is done the same way you would in any editor or IDE from any platform: Make your selection and hit . To paste, C-y or work just as well.

    You can also cut a selection with . (C-k only kills up to the end of the line and is independent of the selection, so it’s not quite the same.)

  • 14 Anonymous // May 22, 2009 at 12:56 am

    Sorry, I didn’t realize that angle brackets were interpreted as HTML here. The universal copy command is <C-insert>. The universal paste command is <S-insert>, and the universal cut command is <S-delete>.

  • 15 A quick-tips Emacs post « Tech Rants // May 22, 2009 at 2:22 pm

    [...] 6) Another awesomely helpful tip: ;Copy-only from M-x all things emacs. (defun copy-line (&optional arg) “Do a kill-line but copy rather than kill. This function directly calls kill-line, so see documentation of kill-line for how to use it including prefix argument and relevant variables. This function works by temporarily making the buffer read-only, so I suggest setting kill-read-only-ok to t.” (interactive “P”) (toggle-read-only 1) (kill-line arg) (toggle-read-only 0)) (setq-default kill-read-only-ok t) (global-set-key “C-cC-k” ‘copy-line) From M-x all-things-emacs [...]

  • 16 Bodhi // May 24, 2009 at 12:25 pm

    Thanks for this, I’ve been annoyed ‘C-k M-y’ing too often. From the tips in the comments I’ve culled it down to:

    (defun copy-line (&optional arg)
    (interactive “P”)
    (let ((kill-read-only-ok t)
    (buffer-read-only t))
    (kill-line arg)))

    I tweaked it because (toggle-read-only) would complain with files under version-control. But is there anyway to get it to not move the cursor after the ‘kill’? I guess I could push a mark and pop back, or just see if the moving cursor is as annoying as i think! One side effect is you can copy several lines of text by repeated M-k as it appends the new text to the kill-ring.

  • 17 Ryan // Jun 5, 2009 at 12:48 pm

    Here’s an arguably better solution to both copying and killing lines.

    http://www.emacswiki.org/emacs/SlickCopy

  • 18 vinz // Jun 7, 2009 at 11:12 pm

    Wow, I found many things up here, but not what I dream of yet !
    I’d like to have a command which allows to copy a line wherever my cursor is on this line -so I don’t like much the “kill-line”-like functions.
    SlickCopy (link above) is pretty pretty, and does what I just described, but it requires transient-mark-mode enabled, and I don’t like it because I like to use marks with C-space and C-x-x.
    What do you think ?? any solution ?

    thanks

    Vincent

  • 19 vinz // Jun 9, 2009 at 7:55 pm

    You say, code in response 5 ? Allright, I hardly understand emacslisp for the moment so I didn’t understand; I’ll try to bind it to M-w or sthg.

    Thank you, bye !

  • 20 djarb // Jul 27, 2009 at 2:13 pm

    (global-set-key (kbd “C-S-k”)
    (lambda ()
    (interactive)
    (set ‘this-command ‘copy-to-kill)
    (set-mark (point))
    (if (= (point) (line-end-position))
    (forward-line)
    (goto-char (line-end-position)))
    (if (eq last-command ‘copy-to-kill)
    (append-next-kill))
    (kill-ring-save (mark) (point))))

  • 21 Stuart Overton // Jan 6, 2010 at 3:45 pm

    Here’s some code that works for me:

    (defun kill-ring-save-wrapper ()
    “If no region exists, call kill-ring-save with point and
    line-end-position as the beginning and end arguments.”
    (interactive)
    (if (ignore-errors (mark))
    (kill-ring-save (region-beginning) (region-end))
    (kill-ring-save (point) (line-end-position))))

    (global-set-key “\M-w” ‘kill-ring-save-wrapper)

  • 22 Michael Lockhart // May 14, 2010 at 11:45 am

    Based on Greg’s decision to go with M-w, and vinz wish, here’s my attempt:

    (defun whatever()
    “copy the line that point is on “
    (interactive “P”)
    (save-excursion
    (move-beginning-of-line)
    (next-line-mark)
    (copy-region-as-kill-nomark)))

    Basically this is C-o C-n M-w, wraped in a save-excursion so that your cursor / mark are unaffected. I too would bind this to M-k

  • 23 Michael Lockhart // May 14, 2010 at 11:58 am

    oh duh! check this out: http://www.emacswiki.org/emacs/CopyingWholeLines

    I found it in my .emacs when I went to add above. <blush/>

    
    

    (defun mjl-copy-line (arg)
    “Copy lines (as many as prefix argument) in the kill ring
    http://www.emacswiki.org/emacs/CopyingWholeLines”
    (interactive “p”)
    (kill-ring-save (line-beginning-position)
    (line-beginning-position (+ 1 arg)))
    (message “%d line%s copied” arg (if (= 1 arg) “” “s”)))

    I copyied this to my X clipboard thus: C-u 7 M-k — three key presses (5 if you count the modifier keys)

  • 24 My Tech Guru » sdgf // Sep 12, 2010 at 12:52 pm

    [...] May 18th, 2009 by Greg Reagle · 24 Comments [...]

  • 25 MaskRay // Jan 10, 2011 at 4:21 am

    whole-line-or-region is a great minor mode

  • 26 Nicole // Feb 26, 2011 at 9:06 am

    What’s the advantage of copying?

  • 27 Max Xie // May 30, 2012 at 4:53 am

    There is a serious problem with this function that you will be left in read-write mode after calling copy-line, even if you were in read-only mode and in that occasion, you surely don’t want such a command to change the status of read-only mode…