如何在Emacs中复制整行?


Answers:


150

我用

C-a C-SPACE C-n M-w C-y

分解为

  • C-a:将光标移到行首
  • C-SPACE:开始选择(“设置标记”)
  • C-n:将光标移到下一行
  • M-w:复制区域
  • C-y:粘贴(“扬”)

之前所提

C-a C-k C-k C-y C-y

等于同一件事(TMTOWTDI)

  • C-a:将光标移到行首
  • C-k:切断(“杀死”)线
  • C-k:剪切换行符
  • C-y:粘贴(“扬”)(我们回到第一个方框)
  • C-y:再次粘贴(现在我们有该行的两个副本)

C-d您的编辑器相比,它们都令人尴尬地冗长,但是在Emacs中始终有一个自定义项。C-ddelete-char默认绑定的,那又如何C-c C-d呢?只需将以下内容添加到您的.emacs

(global-set-key "\C-c\C-d" "\C-a\C- \C-n\M-w\C-y")

(@Nathan的elisp版本可能更可取,因为如果更改任何键绑定,它都不会中断。)

当心:某些Emacs模式可能会收回C-c C-d来做其他事情。


5
嗨!请注意,如果您具有'(setq kill-whole-line t)',则只需要一个'Ck'(解决方案2),因为它已经杀死了换行符以及该行的内容。我更喜欢使用“ C-k”。丹尼尔,干杯
丹尼尔普

179
这真是令人尴尬。
tofutim 2012年

18
C-S-backspace C-y C-y
ericzma 2013年

1
什么是Mw?该使用哪个键?
Bala 2013年

4
@Bala“ M”是“ Meta”(通常是Esc或Alt,这取决于您的键盘布局)。“ Mw”同时是“ Meta”和“ w”(在我的键盘上是“ Alt-w”)。
克里斯·康威

96

除了前面的答案,您还可以定义自己的函数来复制一行。例如,将以下内容放入您的.emacs文件将使Cd复制当前行。

(defun duplicate-line()
  (interactive)
  (move-beginning-of-line 1)
  (kill-line)
  (yank)
  (open-line 1)
  (next-line 1)
  (yank)
)
(global-set-key (kbd "C-d") 'duplicate-line)

我收到以下错误消息:Symbol's function definition is void: move-beginning-of-line
Rohaq 2012年

5
问题是“ Del”键也与复制行绑定在一起...
David Gomes

那么,关于如何解除Del此功能绑定的任何想法?
亚历山大·谢布利金

好的,找到了一种Del在保留新值的同时恢复正常的解决方案C-d(global-set-key (kbd "<delete>") 'delete-char)需要在C-d定义之后添加。
Alexander Shcheblikin 2014年

尝试在空行上插入两行,而不是仅插入一行。我不知道为什么 有简单的解决方法吗?
Zelphir Kaltstahl 2015年


52

我的函数版本可以复制一条行,该行可以与undo一起很好地工作,并且不会弄乱光标的位置。这是1997年11月在gnu.emacs.sources中进行讨论的结果。

(defun duplicate-line (arg)
  "Duplicate current line, leaving point in lower line."
  (interactive "*p")

  ;; save the point for undo
  (setq buffer-undo-list (cons (point) buffer-undo-list))

  ;; local variables for start and end of line
  (let ((bol (save-excursion (beginning-of-line) (point)))
        eol)
    (save-excursion

      ;; don't use forward-line for this, because you would have
      ;; to check whether you are at the end of the buffer
      (end-of-line)
      (setq eol (point))

      ;; store the line and disable the recording of undo information
      (let ((line (buffer-substring bol eol))
            (buffer-undo-list t)
            (count arg))
        ;; insert the line arg times
        (while (> count 0)
          (newline)         ;; because there is no newline in 'line'
          (insert line)
          (setq count (1- count)))
        )

      ;; create the undo information
      (setq buffer-undo-list (cons (cons eol (point)) buffer-undo-list)))
    ) ; end-of-let

  ;; put the point in the lowest line and return
  (next-line arg))

然后,您可以定义CTRL-D来调用此函数:

(global-set-key (kbd "C-d") 'duplicate-line)

优秀的!撤消和光标位置功能使其成为最佳选择。谢谢!
ptrn 2011年

另外,在链接上也有一些区域代码!
pcarvalho

非常好的解决方案。THX
Plankalkül

效果很好。感谢您的解决方案。
Stryker

@pesche crux-duplicate-current-line-or-region对我来说效果更好,因为使用您的功能,它可以撤消行重复和最后一次操作。
rofrol '18年

47

相反的kill-lineC-k),如C-a C-k C-k C-y C-y 使用kill-whole-line命令:

C-S-Backspace
C-y
C-y

超过的优点C-k包括:在线上的点无关紧要(与C-k要求在行的开始处不同)不一样,并且它还会终止换行符(同样,某些C-k操作无效)。


2
感谢@RayVega!我尝试了此解决方案,它的工作原理就像冠军(无论如何,在我的GNU Emacs 23.3.1中)。这种解决方案对某些人无效吗?这是对您(自己)问题的最佳答案。
JS。

1
您应该接受此答案作为正确答案。它完全按照“最小数量的命令”中的要求执行操作。
Davor Cubranic '16

24

这是执行此操作的另一个功能。我的版本没有碰到kill ring,光标最终移到了原来的新行上。如果该区域处于活动状态(瞬变标记模式),它将复制该区域;否则,默认情况下将复制该行。如果给定了前​​缀arg,它还将产生多个副本,如果给定一个负前缀arg,它将注释掉原始行(这对于在保留旧命令/语句的同时测试不同版本的命令/语句很有用)。

(defun duplicate-line-or-region (&optional n)
  "Duplicate current line, or region if active.
With argument N, make N copies.
With negative N, comment out original line and use the absolute value."
  (interactive "*p")
  (let ((use-region (use-region-p)))
    (save-excursion
      (let ((text (if use-region        ;Get region if active, otherwise line
                      (buffer-substring (region-beginning) (region-end))
                    (prog1 (thing-at-point 'line)
                      (end-of-line)
                      (if (< 0 (forward-line 1)) ;Go to beginning of next line, or make a new one
                          (newline))))))
        (dotimes (i (abs (or n 1)))     ;Insert N times, or once if not specified
          (insert text))))
    (if use-region nil                  ;Only if we're working with a line (not a region)
      (let ((pos (- (point) (line-beginning-position)))) ;Save column
        (if (> 0 n)                             ;Comment out original with negative arg
            (comment-region (line-beginning-position) (line-end-position)))
        (forward-line 1)
        (forward-char pos)))))

我将其绑定到C-c d

(global-set-key [?\C-c ?d] 'duplicate-line-or-region)

永远不要通过模式或其他任何方式重新分配它,因为C-c后面紧跟着一个(未修改的)字母供用户绑定。


迄今为止最好的解决方案
Leo Ufimtsev'Feb 9''15 at

1
我将其放在.emacs文件中,但是当我尝试使用时C-c d,出现错误command-execute: Wrong type argument: commandp, duplicate-line-or-region。知道发生了什么吗?我在Windows上使用Emacs 25.1.1
junius

真的是一个很好的解决方案,我非常喜欢区域功能和带负参数的注释功能。也像建议的键绑定。
Alex Trueman

18

内森(Nathan)在.emacs文件中的添加方式是可行的,但是可以通过替换来稍微简化它

  (open-line 1)
  (next-line 1)

  (newline)

屈服

(defun duplicate-line()
  (interactive)
  (move-beginning-of-line 1)
  (kill-line)
  (yank)
  (newline)
  (yank)
)
(global-set-key (kbd "C-d") 'duplicate-line)

很好 谢谢!
tejasbubane

7

从梅尔帕安装重复的东西:

MX软件包安装RET重复项

并将此键绑定添加到初始化文件

(全局设置密钥(kbd“ Mc”)'重复的内容)


看起来在这个日期之前还没有到。
MarkSkayff

5

我不太记得行复制在其他任何地方的工作方式,但是作为前SciTE用户,我喜欢SciTE-way的一件事:它不会碰到光标位置!因此,以上所有方法对我来说都不足够,这是我的嬉皮版本:

(defun duplicate-line ()
    "Clone line at cursor, leaving the latter intact."
    (interactive)
    (save-excursion
        (let ((kill-read-only-ok t) deactivate-mark)
            (toggle-read-only 1)
            (kill-whole-line)
            (toggle-read-only 0)
            (yank))))

请注意,实际上没有任何东西在进程中被杀死,不会留下任何痕迹和当前选择。

顺便说一句,为什么你们会喜欢在这种不错的“整洁的杀人”(CS退格键)(CS退格键)周围晃动光标?



4

您可能想要在.emacs中包含的内容是

(setq kill-whole-line t)

基本上,每当您调用kill-line(即通过Ck)时,都会杀死整行以及换行符。然后,无需额外的代码,您只需执行Ca Ck Cy Cy即可复制该行。它分解为

C-a go to beginning of line
C-k kill-line (i.e. cut the line into clipboard)
C-y yank (i.e. paste); the first time you get the killed line back; 
    second time gives the duplicated line.

但是,如果您经常使用它,那么专用的键绑定也许是一个更好的主意,但是仅使用Ca Ck Cy Cy的好处是您可以在其他位置复制该行,而不仅仅是在当前行下方。


4

copy-from-above-command绑定了一个键并使用它。它是XEmacs附带的,但是我不知道GNU Emacs。

“从上方复制命令”是一个交互式编译的Lisp函数
,从“ /usr/share/xemacs/21.4.15/lisp/misc.elc”加载(从上方复制命令和可选的ARG)

文档:从上一行非空白行复制字符。复制ARG字符,但不要超过该行的末尾。如果未提供任何参数,请复制该行的其余部分。复制的字符将插入到缓冲区之前。


至于版本23,它也是标准GNU Emacs发行版的一部分。
viam0Zah 2010年

它似乎不在我的版本中。是否需要加载某些东西?我的版本是GNU Emacs 23.2.1 (amd64-portbld-freebsd8.1) of 2010-11-14 on [host clipped]
qmega

2
@qmega您需要做(要求'misc)。
德米特里(Dmitry),

4

有一个名为Avy的程序包它具有命令avy-copy-line。使用该命令时,窗口中的每一行都会有字母组合。然后,您只需要输入“ combination”就可以了。这也适用于区域。然后,您只需键入两个组合。

在这里您可以看到界面:

在此处输入图片说明



3

默认设置对此非常可怕。但是,您可以扩展Emacs使其像SlickEdit和TextMate一样工作,也就是说,当没有选择任何文本时,复制/剪切当前行:

(transient-mark-mode t)
(defadvice kill-ring-save (before slick-copy activate compile)
  "When called interactively with no active region, copy a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (message "Copied line")
     (list (line-beginning-position)
           (line-beginning-position 2)))))
(defadvice kill-region (before slick-cut activate compile)
  "When called interactively with no active region, kill a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (list (line-beginning-position)
           (line-beginning-position 2)))))

将以上内容放在中.emacs。然后,复制一行M-w。要删除一行,C-w。要复制一行,C-a M-w C-y C-y C-y ...


3

'我写了自己的版本duplicate-line,因为我不想弄死杀手。

  (defun jr-duplicate-line ()
    "EASY"
    (interactive)
    (save-excursion
      (let ((line-text (buffer-substring-no-properties
                        (line-beginning-position)
                        (line-end-position))))
        (move-end-of-line 1)
        (newline)
        (insert line-text))))
  (global-set-key "\C-cd" 'jr-duplicate-line)

3

我喜欢FraGGod的版本,除了两件事:(1)它不检查缓冲区是否已经是只读的(interactive "*");(2)如果最后一行为空,则它在缓冲区的最后一行失败(如您在这种情况下将无法终止该行),从而使缓冲区保持只读状态。

我进行了以下更改以解决该问题:

(defun duplicate-line ()
  "Clone line at cursor, leaving the latter intact."
  (interactive "*")
  (save-excursion
    ;; The last line of the buffer cannot be killed
    ;; if it is empty. Instead, simply add a new line.
    (if (and (eobp) (bolp))
        (newline)
      ;; Otherwise kill the whole line, and yank it back.
      (let ((kill-read-only-ok t)
            deactivate-mark)
        (toggle-read-only 1)
        (kill-whole-line)
        (toggle-read-only 0)
        (yank)))))

3

使用最新的emacs,您可以在行中的任何位置使用Mw进行复制。这样就变成了:

M-w C-a RET C-y

真?那是哪个“最近的” Emacs?对于24.4则不是这样:您将获得“该标记现在未设置,因此没有区域。”
Davor Cubranic '16

当前的Emacs是24.5,并且M-w绑定到easy-kill。检查当您做得到的东西C-h c M-w
Louis Kottmann '16

在Emacs 24.5.1中不起作用。在插入前一个空白行之后,仅从行首复制到同一行的开头。
德里克·马哈尔

3

无论如何,我看到了非常复杂的解决方案...

(defun duplicate-line ()
  "Duplicate current line"
  (interactive)
  (kill-whole-line)
  (yank)
  (yank))
(global-set-key (kbd "C-x M-d") 'duplicate-line)

请注意,这将导致kill ring。
Dodgie '18

当它是最后一行并且文件没有以新行结尾时,这会将行附加到自身上
Mark

2

@ [凯文·康纳]:据我所知,非常接近。唯一需要考虑的另一件事是启用kill-whole-lineCk中的换行符。


@Allen:删除[]加入@[Kevin Conner]
jfs

2

ctrl- kctrl- k(到新位置的位置)ctrl-y

如果您不是从行首开始,请添加ctrl- a。而第二个ctrl- k就是抓住换行符。如果只需要文本,可以将其删除。


这必须是这里最直接的方法。谢谢!
bartlomiej.n

2

在没有活动区域的情况下进行交互式调用时,请复制(Mw)一行:

(defadvice kill-ring-save (before slick-copy activate compile)
  "When called interactively with no active region, COPY a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (message "Copied line")
     (list (line-beginning-position)
           (line-beginning-position 2)))))

在没有活动区域的情况下进行交互式调用时,请杀死(Cw)一行。

(defadvice kill-region (before slick-cut activate compile)
  "When called interactively with no active region, KILL a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (message "Killed line")
     (list (line-beginning-position)
           (line-beginning-position 2)))))

另外,在相关说明中:

(defun move-line-up ()
  "Move up the current line."
  (interactive)
  (transpose-lines 1)
  (forward-line -2)
  (indent-according-to-mode))

(defun move-line-down ()
  "Move down the current line."
  (interactive)
  (forward-line 1)
  (transpose-lines 1)
  (forward-line -1)
  (indent-according-to-mode))

(global-set-key [(meta shift up)]  'move-line-up)
(global-set-key [(meta shift down)]  'move-line-down)

1

我根据自己的喜好写一个。

(defun duplicate-line ()
  "Duplicate current line."
  (interactive)
  (let ((text (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
        (cur-col (current-column)))
    (end-of-line) (insert "\n" text)
    (beginning-of-line) (right-char cur-col)))
(global-set-key (kbd "C-c d l") 'duplicate-line)

但是我发现当当前行包含多字节字符(例如CJK字符)时,这将有一些问题。如果遇到此问题,请尝试以下方法:

(defun duplicate-line ()
  "Duplicate current line."
  (interactive)
  (let* ((text (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
         (cur-col (length (buffer-substring-no-properties (point-at-bol) (point)))))
    (end-of-line) (insert "\n" text)
    (beginning-of-line) (right-char cur-col)))
(global-set-key (kbd "C-c d l") 'duplicate-line)

1

在按行或区域复制,然后按预期保留点和/或活动区域方面,此功能应与JetBrains的实现相匹配:

只是交互形式的包装:

(defun wrx/duplicate-line-or-region (beg end)
  "Implements functionality of JetBrains' `Command-d' shortcut for `duplicate-line'.
   BEG & END correspond point & mark, smaller first
   `use-region-p' explained: 
   http://emacs.stackexchange.com/questions/12334/elisp-for-applying-command-to-only-the-selected-region#answer-12335"
  (interactive "r")
  (if (use-region-p)
      (wrx/duplicate-region-in-buffer beg end)
    (wrx/duplicate-line-in-buffer)))

哪个叫这个

(defun wrx/duplicate-region-in-buffer (beg end)
  "copy and duplicate context of current active region
   |------------------------+----------------------------|
   |        before          |           after            |
   |------------------------+----------------------------|
   | first <MARK>line here  | first line here            |
   | second item<POINT> now | second item<MARK>line here |
   |                        | second item<POINT> now     |
   |------------------------+----------------------------|
   TODO: Acts funky when point < mark"
  (set-mark-command nil)
  (insert (buffer-substring beg end))
  (setq deactivate-mark nil))

或这个

(defun wrx/duplicate-line-in-buffer ()
  "Duplicate current line, maintaining column position.
   |--------------------------+--------------------------|
   |          before          |          after           |
   |--------------------------+--------------------------|
   | lorem ipsum<POINT> dolor | lorem ipsum dolor        |
   |                          | lorem ipsum<POINT> dolor |
   |--------------------------+--------------------------|
   TODO: Save history for `Cmd-Z'
   Context: 
   http://stackoverflow.com/questions/88399/how-do-i-duplicate-a-whole-line-in-emacs#answer-551053"
  (setq columns-over (current-column))
  (save-excursion
    (kill-whole-line)
    (yank)
    (yank))
  (let (v)
    (dotimes (n columns-over v)
      (right-char)
      (setq v (cons n v))))
  (next-line))

然后我将其绑定到meta + shift + d

(global-set-key (kbd "M-D") 'wrx/duplicate-line-or-region)

1

如在其他答案中所述,将键击绑定到Lisp代码比将键击绑定到另一个键击是一个更好的主意。使用@mw的答案,代码将复制该行并将标记移至新行的末尾。此修改使标记位置保持在新行的同一列上:

fun duplicate-line ()
  (interactive)
  (let ((col (current-column)))
    (move-beginning-of-line 1)
    (kill-line)
    (yank)
    (newline)
    (yank)
    (move-to-column col)))

1

如果您使用的是Spacemacs,则可以简单地使用duplicate-line-or-region,绑定到:

SPC x l d 

0

具有前缀参数,什么是(我希望)直观的行为:

(defun duplicate-line (&optional arg)
  "Duplicate it. With prefix ARG, duplicate ARG times."
  (interactive "p")
  (next-line 
   (save-excursion 
     (let ((beg (line-beginning-position))
           (end (line-end-position)))
       (copy-region-as-kill beg end)
       (dotimes (num arg arg)
         (end-of-line) (newline)
         (yank))))))

光标将停留在最后一行。或者,您可能想要指定一个前缀以一次复制接下来的几行:

(defun duplicate-line (&optional arg)
  "Duplicate it. With prefix ARG, duplicate ARG times."
  (interactive "p")
  (save-excursion 
    (let ((beg (line-beginning-position))
          (end 
           (progn (forward-line (1- arg)) (line-end-position))))
      (copy-region-as-kill beg end)
      (end-of-line) (newline)
      (yank)))
  (next-line arg))

我发现自己经常使用包装函数来切换prefix参数的行为。

和一个绑定: (global-set-key (kbd "C-S-d") 'duplicate-line)


0
;; http://www.emacswiki.org/emacs/WholeLineOrRegion#toc2
;; cut, copy, yank
(defadvice kill-ring-save (around slick-copy activate)
  "When called interactively with no active region, copy a single line instead."
  (if (or (use-region-p) (not (called-interactively-p)))
      ad-do-it
    (kill-new (buffer-substring (line-beginning-position)
                                (line-beginning-position 2))
              nil '(yank-line))
    (message "Copied line")))
(defadvice kill-region (around slick-copy activate)
  "When called interactively with no active region, kill a single line instead."
  (if (or (use-region-p) (not (called-interactively-p)))
      ad-do-it
    (kill-new (filter-buffer-substring (line-beginning-position)
                                       (line-beginning-position 2) t)
              nil '(yank-line))))
(defun yank-line (string)
  "Insert STRING above the current line."
  (beginning-of-line)
  (unless (= (elt string (1- (length string))) ?\n)
    (save-excursion (insert "\n")))
  (insert string))

(global-set-key (kbd "<f2>") 'kill-region)    ; cut.
(global-set-key (kbd "<f3>") 'kill-ring-save) ; copy.
(global-set-key (kbd "<f4>") 'yank)           ; paste.

将上面的elisp添加到您的init.el中,您现在可以剪切/复制整行功能,然后可以按F3 F4复制一条线。


0

最简单的方法是克里斯·康威(Chris Conway)的方法。

C-a C-SPACE C-n M-w C-y

这是EMACS规定的默认方式。我认为,最好使用该标准。我始终对在EMACS中自定义自己的键绑定保持谨慎。EMACS已经足够强大,我认为我们应该尽力适应其自身的键绑定。

虽然有点冗长,但是当您习惯了它之后,您可以快速执行并发现这很有趣!


4
考虑到所有因素,Emacs几乎不需要执行任务-它给您带来的巨大成功就是可以轻松地根据自己的需要对其进行自定义。当然,实际上,很多标准的做事方法值得坚持,但是如果您使用的是“默认” Emacs,并且做一些比必要的更困难的事情,只是因为您认为“最好使用标准” ,您几乎做错了。
phils

0

这是复制当前行的功能。使用前缀参数,它将多次复制该行。例如,C-3 C-S-o将当前行重复三遍。不改变杀死戒指。

(defun duplicate-lines (arg)
  (interactive "P")
  (let* ((arg (if arg arg 1))
         (beg (save-excursion (beginning-of-line) (point)))
         (end (save-excursion (end-of-line) (point)))
         (line (buffer-substring-no-properties beg end)))
    (save-excursion
      (end-of-line)
      (open-line arg)
      (setq num 0)
      (while (< num arg)
        (setq num (1+ num))
        (forward-line 1)
        (insert-string line))
      )))

(global-set-key (kbd "C-S-o") 'duplicate-lines)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.