如何在 Emacs 中复制整行?

我看到了 同样的问题,它一直是我自己想知道如何为 Emacs 做的东西。在 ReSharper 中,我使用 CTRL-D 进行这个操作。在 Emacs 中执行此操作的命令的最少数量是多少?

81989 次浏览

我经常使用:

Ctl-Space (set the mark)
move to end of line
Ctl-K kill line
Ctl-Y * 2 (yank the line back)

也许还有更好的办法

因为我不知道,我会用慢球开始这轮高尔夫:

Ctrl-k,y,y

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

如果你不是从这行的开头开始,那么添加一个 ctrl-a。第二个 ctrl-k是抓取换行符。如果您只想要文本,它可以被删除。

把光标放在线上,如果不是在开始做一个 CTRL-A,然后:

CTRL-K

CTRL-K

CTRL-Y

CTRL-Y

@ [ Kevin Conner ] : 据我所知,很接近了。另一件需要考虑的事情是打开 kill-whole-line,在 C-k 中包含换行符。

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

我吸毒

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

分解成

  • 移动光标到行的起点
  • C-SPACE: 开始选择(“设置标记”)
  • 移动光标到下一行
  • 复制区域
  • C-y: 粘贴(“ yank”)

前面提到的

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

相当于同样的东西(TMTOWTDI)

  • 移动光标到行的起点
  • 切断(“杀死”)线路
  • 切断新线路
  • 粘贴(“ yank”)(我们又回到起点了)
  • 再粘贴一次(现在我们已经得到了这行的两个副本)

与编辑器中的 C-d相比,它们都冗长得令人尴尬,但是在 Emacs 中总是有一个定制。C-d默认绑定到 delete-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来做其他事情。

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

(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)

我把 copy-from-above-command绑定到一个密钥并使用它。它提供了 XEmacs,但我不知道 GNU Emacs。

“ copy-from-above-command”是一个 交互式编译的 Lisp 函数
——从“/usr/share/xemacs/21.4.15/lisp/misc.elc”加载 (复制-从上面-命令 & 可选 ARG)

文档: < strong > 从 前面的非空行 ,刚开始 复制 ARG 字符,但是 如果没有的话 参数给定,复制整个休息 复制的字符是 插入到点前的缓冲区中。

内森添加到您的.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)

你可能希望在你的.emacs 中有

(setq kill-whole-line t)

当你调用 kill-line (即通过 C-k)时,它基本上会杀死整个行和换行。然后不需要额外的代码,你只需要做 C-a C-k C-y C-y 来复制这一行。分解成

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.

但是如果你经常使用它,那么一个专门的密钥绑定可能是一个更好的主意,但是只使用 C-a C-k C-y C-y 的好处是你可以在其他地方复制这一行,而不是仅仅在当前行的下面。

这种情况下的违约太可怕了。但是,您可以扩展 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 ...

我不太记得其他任何地方的行复制是如何工作的,但作为一名前 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))))

请注意,在过程中没有任何东西实际上被杀死,留下的标记和当前选择完好无损。

顺便说一下,为什么你们这些家伙这么喜欢摆动光标时,有这个不错的’干净杀死整行的东西(C-S-退格) ?

我的版本的函数,以复制一行,工程与撤消很好,不会与光标位置混乱。这是 1997年11月在 gnu.emacs.source 上的讨论的结果。

(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)

我写了我自己版本的 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)

使用 kill-whole-line命令代替 C-a C-k C-k C-y C-y中的 kill-line(C-k) :

C-S-Backspace
C-y
C-y

C-k相比,它的优点包括: 点在线上的哪个位置并不重要(与 C-k不同,C-k要求位于线的开始位置) ,它还会杀死换行(同样,C-k不会这样做)。

我喜欢 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)))))

前缀参数,以及什么是(我希望是)直觉行为:

(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))

我发现自己经常同时使用这两种方法,使用包装函式来切换前缀参数的行为。

还有钥匙扣: (global-set-key (kbd "C-S-d") 'duplicate-line)

这里还有另外一个函数用于执行此操作。我的版本没有触及到死环,光标最终出现在原来的新行上。如果它处于活动状态(暂时标记模式) ,它将复制该区域,否则默认情况下将复制该行。如果给定一个前缀 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后面跟着一个(未修改的)字母是为用户绑定保留的。

;; 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.

将上面的省略符添加到 init.el 中,现在就可以获得 cut/copy 整行函数,然后可以用 F3 F4复制一行。

最简单的方法是 Chris Conway 的方法。

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

这是 EMACS 指定的默认方式。在我看来,最好使用标准。在 EMACS 中,我总是小心翼翼地定制自己的密钥绑定。EMACS 已经足够强大了,我认为我们应该尽力去适应它自己的密钥绑定。

虽然它有点长,但是当你习惯了它,你可以做得很快,并会发现这是乐趣!

对于最近的 emacs,你可以在行中的任何地方使用 M-w 来复制它,所以它变成:

M-w C-a RET C-y

我按照自己的喜好写了一首。

(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)

安装 melpa 的复制品:

M-x 软件包-安装 RET 复制件

并将此密钥绑定添加到 初始化文件:

(global-set-key (kbd“ M-c”)‘ copy-thing)

当没有活动区域的交互式调用时,COPY (M-w)改为一行:

(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)))))

当没有活动区域交互调用时,KILL (C-w)改为单行。

(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 the current line up."
(interactive)
(transpose-lines 1)
(forward-line -2)
(indent-according-to-mode))


(defun move-line-down ()
"Move the current line down."
(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)

我看到了非常复杂的解决方案。

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

这个功能应该与 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)

有一个叫 艾薇的软件包,它有 avy-copy-line 命令。当您使用该命令时,窗口中的每一行都会得到字母组合。然后你只需要输入组合,就能得到那一行。这也适用于区域。然后你只需要输入两个组合。

这里你可以看到界面:

enter image description here

下面是一个复制当前行的函数。使用前缀参数,它将多次重复该行。例如,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 line))
)))


(global-set-key (kbd "C-S-o") 'duplicate-lines)

我不能相信所有这些复杂的解决方案。这是两个按键:

<C-S-backspace>运行 kill-whole-line 命令

C-/运行撤消命令

因此,<C-S-backspace> C-/可以“复制”整行(杀死和撤消)。

当然,您可以将它与数值参数和负参数组合起来,从而杀死多个向前或向后的行。

这感觉更自然,对于选择的答案由克里斯康威。

(global-set-key“ C-c C-d”“ C-a C-C-n M-w C-y C-p C-e”)

这允许您通过简单地重复 C-c C-d 键击来多次复制一行。

正如在其他答案中提到的,将键击绑定到 lisp 代码比将它们绑定到另一个键击更好。使用@mw 的回答,代码将复制该行并将标记移动到新行的末尾。此修改使标记位置保持在新行的同一列上:

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

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

SPC x l d

在梅尔帕有一个叫做“搬家”的软件包可以帮助你。

免责声明: 我是包的作者。