Emacs中类似Vim的yy10p命令的等效命令是什么?

23

如何在Emacs中轻松地复制一行10次? 我找不到复制整行的快捷键或函数。 我可以使用C-a C-spc C-e M-w来费力地复制该行,但我如何将其粘贴多次?

有什么想法吗,在我编写自己的函数之前。

11个回答

22

您可以使用键盘宏来实现此操作: -

C-a C-k C-x ( C-y C-j C-x ) C-u 9 C-x e

说明:

  • C-a:跳转到行首
  • C-k:删除整行
  • C-x(:开始记录键盘宏
  • C-y:粘贴刚才删除的整行
  • C-j:移动到下一行
  • C-x):停止记录键盘宏
  • C-u 9:重复执行9次
  • C-x e:执行键盘宏

4
注意自 Emacs 22.1 版本发布以来,您实际上可以使用 <C-S-backspace>,它会运行 kill-whole-line 命令,相当于 vi 中的 dd。因此,每当您发现自己在执行 C-a C-k C-k 时,可以直接使用 <C-S-backspace> - Deniz Dogan
以上代码可以正常运行,但是在 Emacs 25(可能早期版本也一样)中,你可以分别使用 F3F4 键来代替 C-x (C-x )请参阅 Emacs 手册以获取更多信息 - user12345
同时在你的init.el文件中加入(setq kill-whole-line t),这将使得当光标位于行首时,按下C-k会删除整行(包括换行符)。 - Aiden Cullo

11

复制:

如果你经常操作行,你可能希望在没有选择区域时,能够通过执行复制(kill-ring-save)和剪切(kill-region) 操作来操作行:

(defadvice kill-ring-save (before slickcopy activate compile)
  "When called interactively with no active region, copy a single line instead."
  (interactive
   (if mark-active (list (region-beginning) (region-end))
     (list (line-beginning-position)
           (line-beginning-position 2)))))
(defadvice kill-region (before slickcut 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)))))

然后你可以直接复制只带M-w的那一行。

粘贴:

通常情况下,前置参数只是多次执行一个动作,因此您期望C-u 10 C-y起作用,但在这种情况下,C-y使用其参数来确定要“yank”(粘贴)的kill-ring元素。我能想到的唯一解决办法是像kronoz所说的那样:使用C-x(C-y C-x)记录一个宏,然后让C-u的参数传递给kmacro-end-and-call-macro(即C-u 9 C-x e或甚至只是C-9 C-x e或M-9 C-x e)。

另一种方法: 您还可以保持在M-x viper-mode中并使用yy10p :)


1
ТѕЉт╗║У««Сй┐ућеEvilУђїСИЇТў»viper-mode; т«ЃтЁиТюЅУ«ИтцџviperТ▓АТюЅуџёVimтіЪУЃйсђѓ - Gordon Gustafson

11
您可能知道,但对于许多命令,“C-u 10”前缀就可以解决问题。但对于"C-y"粘贴命令,"C-u"被重新定义为“在kill环中回到这么多项目,并插入该项”。
我认为您可以使用带有C-u前缀命令的“将内容复制到寄存器中”和“插入寄存器”命令,但显然这也行不通。
此外,C-x z,“重复上一个命令”似乎对C-u免疫。
另一个想法是使用M-:获取一个Eval提示符并输入一些elisp代码。 我以为类似于(点次'10 'yank)的东西可以做到这一点,但似乎不行。
因此,除了编写自己的小函数之外,使用C-u宏似乎确实是您可以做的最好的事情。
如果我有投票权,我会投kronoz的答案。

我支持使用C-u(最小字符限制欺骗)。 - ychaouche

7
在这个例子中,您不需要同时使用C-x)和C-x e。您可以直接将重复参数传递给C-x),这样可以在一步中停止记录并重复宏。或者您可以跳过C-x)并直接进入C-x e,因为C-x e将在执行重复之前结束记录。选择哪种方式取决于您喜欢的重复计数方式。对于C-x),您可以说出您想要的总重复次数(在本例中为10)。对于C-x e,您需要说出剩余的重复次数(即9)。
C-a C-k C-k也会删除尾随换行符,因此您不必自己放回它。它比使用标记更快,并且不需要您更改任何变量。更好的是(除非您在终端中),您可以使用C-S-Backspace*来杀死整行,而不管您在哪里。
在Emacs 22及更高版本中,默认情况下F3启动宏,F4结束/重复宏。您只需按F3开始录制,完成后按F4,再次按F4即可重复宏。(F4还带有一个参数。)
将所有这些组合起来,以获得当前行的10个副本:
C-S-Backspace:删除此行 F3:开始宏 C-y:插入该行 C-1 C-0 F4:使其重复10次
不像y y 10 p那样简短,但非常接近。 :)

3

这是我从OS/2版本的Emacs中提取的一个函数。(是的,我已经使用Emacs有一段时间了。)

;; Author: Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de>
(defun emx-dup-line (arg)
  "Duplicate current line.
Set mark to the beginning of the new line.
With argument, do this that many times."
  (interactive "*p")
  (setq last-command 'identity) ; Don't append to kill ring
  (let ((s (point)))
    (beginning-of-line)
    (let ((b (point)))
      (forward-line)
      (if (not (eq (preceding-char) ?\n)) (insert ?\n))
      (copy-region-as-kill b (point))
    (while (> arg 0)
      (yank)
      (setq arg (1- arg)))
    (goto-char s))))

我将其绑定到了F9 d:

(global-set-key [f9 ?d]    'emx-dup-line)

然后我会使用 C-u 10 F9 d 来将一行复制十次。

2
我所知道的重复任意命令的方法是使用键盘宏的“按参数重复”功能。
C-a C-space down M-w C-x ( C-y C-x ) C-9 C-x e 以下是各个命令的说明:
- C-a:光标移到行首 - C-space:设置标记 - down:移动到下一行的开头 - M-w:复制区域 - C-x (:开始录制键盘宏 - C-y:粘贴刚才复制的行 - C-x ):结束录制键盘宏 - C-9 C-x e:执行键盘宏九次。
这种方法与vim相比较弱。但这只是因为vim在这方面非常高效。
如果你真的想要类似vi的模态交互,可以使用其中之一的vi仿真模式,例如viper-mode。请查看在线emacs手册中的“仿真”部分。

1
呵呵,相比于要按C-y十次,这只需要8个按键。我保证我可以比输入所有那些按键更快地按下C-y十次。 - Baxissimo

0

首先你需要在你的 .emacs 文件中添加这个按键绑定:

;; yank n times
(global-set-key "\C-y" (lambda (n) (interactive "*p") (dotimes (i n) (clipboard-yank))))

然后你可以这样做:

C-a C-SPC C-n M-w C-u 10 C-y

C-a C-SPC C-n M-w - 选择整行
C-u 10 C-y - 重复执行“clipboard-yank” 10次


0

基于Baxissimo的回答,我定义了这个:

(defun yank-n-times (arg)
  "yank prefix-arg number of times. Not safe in any way."
  (interactive "*p")
  (dotimes 'arg (yank)))

将其设置为某个键,使用前缀参数调用它,然后开始操作。 < p > < strong > 编辑 (还修改了上面的交互式调用以减少糟糕程度) 或者,以下是一种可以在某种程度上替代yank-pop的版本:
(defun yank-n-times (&optional arg)
  "yank prefix-arg number of times. Call yank-pop if last command was yank."
  (interactive "*p")
  (if (or (string= last-command "yank")
      (string= last-command "yank-pop"))
      (yank-pop arg)
    (if (> arg 1)
    (dotimes 'arg (yank))
      (message "Previous arg was not a yank, and called without a prefix."))))

这个消息有点虚假,但是你无论如何都不应该在没有大于1的前缀的情况下调用它。

不确定这是否是一个好主意,但我用这个替换了M-y,我会看看效果如何。


0

你需要删除这一行:C-a C-k,然后使用C-y或者?。


1
额...问题是如何做十次,而不是一次。 - Baxissimo

0

我不知道有没有直接的等价物(C-y 10次是我所知道的最好的方法),但你可能会对Viper感兴趣,它是一个针对emacs的vi仿真包。它是标准emacs发行版的一部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接