我在 VIM 上看到了同样的问题,我自己也想知道如何为 Emacs 做这件事。在 ReSharper 中,我使用 CTRL-D 来执行此操作。在 Emacs 中执行此操作的最少命令数是多少?
34 回答
我用
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
: paste ("yank") (我们回到第一格)C-y
: 再次粘贴(现在我们有两个副本)
与您的编辑器相比,这些都非常冗长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 文件将使 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)
将光标放在行上,如果不是在开头做CTRL- A,那么:
CTRL-K
CTRL-K
CTRL-Y
CTRL-Y
我的复制行的函数版本与撤消配合得很好,并且不会弄乱光标位置。这是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)
而不是kill-line
( C-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
没有做)。
这是执行此操作的另一个功能。我的版本没有触及杀伤环,光标最终出现在原来的新行上。如果区域处于活动状态(瞬态标记模式),它将复制该区域,否则默认复制该行。如果给定前缀 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
后面跟着一个(未修改的)字母是为用户绑定保留的。
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)
我已经copy-from-above-command
绑定了一个键并使用它。它由 XEmacs 提供,但我不了解 GNU Emacs。
`copy-from-above-command' 是一个交互式编译的 Lisp 函数
-- 从 "/usr/share/xemacs/21.4.15/lisp/misc.elc" (copy-from-above-command & optional ARG) 加载文档:从上一个非空行复制字符,从点上方开始。复制 ARG 字符,但不要超过该行的末尾。如果没有给出参数,则复制该行的整个其余部分。复制的字符在点之前插入到缓冲区中。
我不太记得行复制在其他任何地方是如何工作的,但作为前 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))))
请注意,在过程中实际上没有任何东西被杀死,留下标记和当前选择完好无损。
顺便说一句,当有这个漂亮的'n'clean kill-whole-line thingy(CS-backspace)时,为什么你们这么喜欢摇晃光标?
因为我不知道,我将用慢球开始这一轮高尔夫:
ctrl-k, y, y
您可能希望在 .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 的优点是您可以在其他地方复制该行,而不是在当前行下方。
' 我写了我自己的版本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)
有一个名为Avy的包它有命令 avy-copy-line。当您使用该命令时,窗口中的每一行都会获得字母组合。然后你只需要输入组合,你就会得到那条线。这也适用于地区。然后你只需要输入两个组合。
在这里你可以看到界面:
C-a C-k 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 ...
.
我喜欢 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)))))
使用最近的 emacs,您可以在行中的任何位置使用 Mw 来复制它。所以它变成:
M-w C-a RET C-y
当在没有活动区域的情况下以交互方式调用时,COPY (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)))))
在没有活动区域的情况下以交互方式调用时,改为 KILL (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 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)
ctrl- k, ctrl- k, (位置到新位置) ctrl-y
添加ctrl-a如果您不是从行首开始。第二个ctrl-k是抓住换行符。如果您只想要文本,可以将其删除。
@[Kevin Conner]:据我所知,非常接近。唯一要考虑的另一件事是打开在kill-whole-line
Ck 中包含换行符。
此功能应与 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)
这是复制当前行的功能。使用前缀参数,它将多次复制该行。例如,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)
如果您使用的是 Spacemacs,您可以简单地使用duplicate-line-or-region
, 绑定到:
SPC x l d
Melpa 上有一个名为“move-dup”的软件包可以帮助您。
免责声明:我是该软件包的作者。
我根据自己的喜好写一篇。
(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)
我无法相信所有这些复杂的解决方案。这是两次击键:
<C-S-backspace>
运行命令 kill-whole-line
C-/
运行命令撤消
所以<C-S-backspace> C-/
要“复制”一整行(杀死和撤消)。
当然,您可以将其与数字和负 args 结合起来,以向前或向后终止多行。
正如其他答案中提到的,将击键绑定到 lisp 代码比将它们绑定到另一个击键更好。使用@mw 的答案,代码会复制该行并将标记移动到新行的末尾。此修改将标记位置保持在新行的同一列:
fun duplicate-line ()
(interactive)
(let ((col (current-column)))
(move-beginning-of-line 1)
(kill-line)
(yank)
(newline)
(yank)
(move-to-column col)))
使用前缀参数,以及(我希望)什么是直观的行为:
(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)
;; 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 复制一行。
最简单的方法是 Chris Conway 的方法。
C-a C-SPACE C-n M-w C-y
这是 EMACS 规定的默认方式。在我看来,最好使用标准。我总是小心翼翼地在 EMACS 中自定义自己的键绑定。EMACS 已经足够强大了,我认为我们应该尽量适应它自己的键绑定。
虽然有点冗长,但是当你习惯了它,你可以做的很快,会发现这很有趣!
相对于 Chris Conway 选择的答案,这感觉更自然。
(全局设置键 "\Cc\Cd" "\Ca\C- \Cn\Mw\Cy\Cp\Ce")
这允许您通过简单地重复 \Cc\Cd 键击来多次复制一行。
我通常使用:
Ctl-Space(设置标记) 移动到行尾 Ctl-K 杀线 Ctl-Y * 2(拉回线)
不过可能有更好的方法:P