Vim: 记录通过映射进入插入模式的宏

Vim: record macro entering insert mode via mapping

我正在尝试重新映射 i/c/o/a 和朋友们总是录制宏。但是实际上让我进入插入模式的按键没有被记录下来(下面解释)。

例如,如果我们有:

nnoremap i qzi
inoremap <esc> <esc>q

理想情况下,这意味着当我进入插入模式 (i) 时,我也开始记录以注册 z。当我离开 (<esc>) 时,我们停止录制。所以寄存器 z 应该有重复我在插入模式下所做的事情所需的整个序列。

但是如果我尝试在插入模式下输入(例如 ihelloworld<esc>)然后检查 :registers a,我会得到

---Registers---
"z   helloworld^[

请注意如何不包含 i 命令——只有我在插入模式下键入的内容。

为什么会这样?我该怎么做才能解决这个问题?

我还注意到,如果我只是正常键入 qzihelloworld<esc>z 寄存器确实包含 ihelloworld<esc>(带有 i)。

对于那些感兴趣的人,我正在尝试这样做,因为某些操作会中断 'repeat last command (the period key .)'。例如,如果您在插入模式下使用 <c-o> 或四处移动,. 只会重复插入模式的最后一段。特别是,我正在尝试为自动关闭插件找到解决方法

@Carpetsmoker 解释了为什么它没有被记录:

来自 :help q

The 'q' command is disabled while executing a register, and it doesn't work inside a mapping and :normal.

这就解释了为什么它不起作用......


解决方法:

由于映射中的命令(例如,i)没有被记录下来,解决方法是在退出插入模式时将其添加到记录缓冲区中。

为了区分iao等,可以将命令存储在变量中,然后在前面加上that 到录制的宏:

nnoremap i :let b:mode="i"<cr>qzi
nnoremap a :let b:mode="a"<cr>qza
nnoremap o :let b:mode="o"<cr>qzo

inoremap <Esc> <Esc>q :let @z=":normal! ".b:mode.@z<CR>    

简单地将 i(等)添加到宏前是行不通的(对我来说),因为它会触发 i 的映射。用 normal! 调用它可以解决这个问题。

另一种选择是修改宏以使用 startinsert(结合适当的动作来模拟 iao 等)通过像这样添加宏

:let @z=":startinsert^M".@z 

警告: 你想要这个的理由:

For example, if you use <c-o> or move around while insert-mode, . will only repeat the last segment of your insert mode.

(我的重点) 需要警告 "moving around"(带方向键)不起作用(至少在我的快速测试)没有额外的黑客攻击,因为箭头键发送 <esc> ... 序列,触发 <esc> 的记录映射结束。 c-o 会起作用,因此您 可以 移动(缓慢地),例如<c-o> h(向左移动)。

另一个问题 是,如果你有换行符,将它作为宏重播是行不通的(至少对于这个解决方案,可能是由于使用了 normal!)等,在录制的宏中。一个解决方案是 execute 缓冲区而不是将其作为宏重播。也就是说,:exe @z 而不是 @z 例如映射

nnoremap <space>z :execute @z<cr>