Vim/Neovim中的宏

11 篇文章 0 订阅

Macros 宏


当你不想使用 Vim 脚本或映射,或者如果你还不知道如何更优雅地完成某些任务时,录制宏是执行一次性任务的好方法,它可以帮助快速完成任务。

在 Vim 中,单词 “macros” 可能是指:

  • 向寄存器中录制一系列命令(本技巧)。
  • 一个把一系列输入的键扩展为一个更长的序列的映射(参见 教程 )。
  • 使用 Vim 脚本编写的脚本(存储在以 .vim 为扩展名的文件中,参见 :help script )。

录制宏

每个寄存器都是由一个小写字母进行标识,即 a 至 z。

想要录制一个宏,输入:

q<letter><commands>q    " 译者:q<字母><命令序列>q

想要执行该宏<number>次(默认是一次),键入:

<number>@<letter>

所以,完整的处理过程看起来这样:

qd    开始录制,并把后面的命令记录到寄存器 d 中
...   你复杂的命令序列
q     停止录制
@d    执行该宏
@@    再次执行该宏

示例

先提供以下的数据:

one    first example
two    second example
three  third example
four   fourth example

假设你想要把这些数据转换成 Python 程序的一个字典,最终的结果如下:

data = {
    'one': 'first example',
    'two': 'second example',
    'three': 'third example',
    'four': 'forth example',
}

为了完成这个任务,可以在改变第一行的同时录制成一个宏。然后,回放该宏以实现改变其他行。当以上动作完成后,再手工输入初始的 data = { 和 最后的 } 的行。

以下演示录制一个合适宏的方法。

  • 把光标放在第一行上。

  • 键入 qdq 表示开始录制;d 就是这个寄存器名称,用于记录后面键入的键序列)。(备注:以下命令后小括号及其内容是注释)

  • 键入以下命令以改变第一个连续的空白成为 ': '

    :s/\s\+/': ' (然后点击回车)
    
  • 键入以下命令以实现在行首插入四个空格及 '

    I    ' (然后点击 Esc 键)
    
  • 键入以下命令以实现在行尾追加 ',

    A',(然后点击 Esc 键)
    
    • 键入以下命令使光标移动到行首,然后移到下一行:
    0j(或者按回车)
    
  • 键入 q 停止录制宏。

现在光标应该停在第二行上。键入 @d 会回放该宏一次。这应该会改变第二行,且光标会移动到第三行。键入 2@@ 以完成其他行。这个数字 2 表示后面动作执行两次,且 @@ 表示回放最后使用过的宏。如果不使用 2@@ ,你也可以键入 @d@@ 两次。

运行宏

使用以下映射,可以方便地执行录制在寄存器 q 中的宏:

:nnoremap <Space> @q
  • 通过键入 qq 开始录制击键。
  • q(如果处于插入insert模式,则先点击 Esc )结束录制。
  • 通过按空格键来回放该录制的一系列击键动作。

假设你有一个宏,它操作单行上的文本,那么你可以运行该宏一次,但是,对在可视模式下选择的每一行都有效:

  • 可视模式下选择一些行(例如,键入 vip 选择当前段落)。
  • 键入 :normal @q ,会在选择的每一行上运行寄存器中的 q 宏。

查看宏

你可以使用命令 :registers 来查看 Vim 中当前任意或全部寄存器中的内容。例如,使用 :reg 查看所有寄存器,或者 :reg a 只查看已经录制在寄存器 a 中的内容。键入 :reg abx 则会显示寄存器中 a, b 和 x 中的内容。

保存宏

保存宏以便今后使用,主要有两种方法:

最简单的方法是,如果你在非兼容模式下运行 Vim(如果你有 vimrc 文件,这是默认的),则默认就会出现这种情形。只需在你的 viminfo 选项中包含适当的文本,或者保留非兼容默认选项,Vim 就会自动地将所有寄存器写到一个文件中,并在下次启动时恢复它们。

每个寄存器的内容默认都会被保存起来,并且下一次你运行 Vim 时有效。例如,你可能录制一个宏到寄存器 a 中,然后使用 :q! 退出 Vim。当再次启动 Vim 时,你可以输入 @a 来运行寄存器中的宏 a

viminfo 选项可以禁用寄存器的自动保存特性。如果键入 :set vimifo? 显示的值包含(例如)<50s10 ,那么,在每个寄存器中将会保存最多 50 行和 10KB 内容。如果这两个项目都是零,则寄存器不会被保存。参见 :help 'viminfo'

第二种方法是,在 vimrc 中使用 let 命令来保存宏以备后用(尤其是,如果你认为可能无意中覆盖了这个宏,因此从 viminfo 文件中恢复出来错误的值)。

举一个非常简单的示例,假设你已经录制了一个宏到寄存器 a 中,而该宏的作用就是会跳转到行中第一个出现的字母 a 上,在常规模式下使用以下击键序列:

qa0faq

如果你想不管何时你启动 Vim,也不管你的viminfo 文件中包含什么,都想要恢复这个宏,则你需要编辑你的 vimrc 文件,且加入以下这行:

let @a='0fa'

假设你已经有了录制的宏,你可以容易地插入寄存器的内容,而不是再次键入它们。在输入上面这行时,在键入 let @a=' 后,简单地击键 Ctrl-R Ctrl-R a',就可以把寄存器 a 中的内容插入。两次 Ctrl-R 是想插入字面量的内容,而不是像键入时那样解释它们。

在上面示例中推荐使用单引号字符('),因为它们允许你键入的几乎都是字面内容,而在双引号(")中,你需要转义某些字母。例如,对比 '\1\2\3"abc"'"\\1\\2\\3\"abc\"" 。但是,如果寄存器必须包含单引号字母,则你得使用第二个单引号来转义它。例如,如果你想要寄存器包含 "Vim's quote handling is a little trichy" ,那么,你的键入 :let @a='"Vim''s quote handling is a little tritrichy"

然而,请注意,使用 :let 的方法对于任何以<CR><NL>(回车或换行)结尾的宏都不能正常工作。这是因为,正如在 :help :let-@ 中所记载的那样,Vim 在这些条件下把寄存器视为面向行的 (linewise) 。其原因是在处理复制或删除时,使通过 :let 设置的寄存器能以“正确的方式”进行,但是,它在处理录制的宏时,会遇到麻烦。可能的变通方法包含使用 setreg() 函数,或者添加 "no-op没有动作" 的命令到宏的结尾,例如,a<Esc> 。参见 vim_dev 中有关 unexpected behavior of the :let command 的细节的讨论。

宏中追加命令

如果你已经录制一个几乎正确的宏,但是你需要在该宏中添加很少的命令,那么,你可以容易地把这几个命令添加到已经存在的宏中,而不是再次录制所有的动作。只需使用大写字母来替代寄存器中的小写字母。

例如,如果你已经使用 qa...q 录制到寄存器 a 中,则你可以使用 qA...q 添加到这个宏中(而不是取代它)。

编辑宏

假设你已经录制一个宏在寄存器 a 中,且你想编辑这个宏。有几种方法可以实现它。

在命令行上可视模式

这个过程 上面 已经解释过了,但是,这里是这些步骤的总结:

  1. 键入 :let @a='
  2. 击键 Ctrl-R Ctrl-R a 插入当前寄存器 a 中的内容(击键 Ctrl-R 两次以精确地插入寄存器内容)。
  3. 根据需要编辑这些文本。
  4. 追加一个单引号(')完成该命令,按回车。
  5. 键入 reg a 查看寄存器中最新的值。
  6. 输入 @a 执行寄存器中 a 中的命令。

注意有关以 <CR><NL> 结尾的宏的警告。

以上步骤允许你在 Vim 的命令行上编辑宏。另一种方法是把宏保存到一个文件中,就像前面的示例中使用 let @a='0fa' 所演示那样,然后编辑该文件。

缓冲区中常规及插入模式

  1. 跳转到一个空行,或者打开一个新的缓冲区(:new)。
  2. 键入 "ap 粘贴该寄存器的内容。
  3. 进入插入模式,并根据需要进行文本编辑。
  4. Esx 返回常规模式。
  5. 键入 "ayy 复制修改过的宏到寄存器 a 中。
  6. 击键 dd ,从你正在编辑的文件中删除这些粘贴而来的寄存器内容。

另见

参考资料

  • :help registers
  • :help recording
  • :help :registers
  • :help ‘viminfo’
  • :help i_CTRL-R_CTRL-R

注释

在进行复杂编辑时,我通常会使用多个宏来结束编辑,而这些宏会调用其他宏。保存这样一个宏集的一个简洁方法是打开一个新文件,并将所有相应的寄存器粘贴到其中。然后将文件的第一行作为一个宏,而该宏会把其余的行加载到适当的寄存器中以便运行这些宏集。当你想恢复时,所有你需要做的就是打开这个文件,复制第一行,执行它,很快地!你的宏集已经加载,可随时使用。


以下是一个问答:

有没有可能为不同的作业设置不同的寄存器组,例如一组用于编辑 xsl 文件,其中包含各种 xsl:xxx 标签的快捷方式,另一组用于编辑 html、 xml、 sql 等?-- 匿名用户

不,这是不可能的。Vim 中的寄存器是跨越整个 Vim 实例的全局寄存器,不像映射、缩写等可以是缓冲区本地的。-- Fritzophrenic(talk)21:49, January 15, 2013 (UTC)

我应该说“如果没有一些脚本,是不可能的”。不过有 BufEnter 和 BufLeave 事件,还有 FileType 事件,它们可以与保存和恢复所需的每个命名寄存器相结合。我知道没有现存的能这样做的插件。–Fritzophrenic (talk) 21:51, January 15, 2013 (UTC)

当我编辑各种文件时,会使用 BufEnter 把 CTRL+/ 映射为用于注释所选行的命令。不同的文件类型需要不同的注释策略,因此我是用 BufEnter 来确定应该为每个文件使用哪个序列。

au BufEnter *.js :vmap ^_ :s/^/\/\// <Enter> :nohlsearch <Enter>
au BufEnter *.py :vmap ^_ :s/^/#/ <Enter> :nohlsearch <Enter>

– Michael S. Meeks 14:11, October 9, 2013 (UTC)

看起来使用 FileType 自动命令 和 buffer-local 映射可以做得更好。参见: help:map-<buffer> 。而该问题是关于录制到寄存器中的宏,而不是关于通过 :map 类型的命令映射的问题。-- Fritzophrenic (talk) 21:39, October 9, 2013 (UTC)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值