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
)没有被记录下来,解决方法是在退出插入模式时将其添加到记录缓冲区中。
为了区分i
、a
、o
等,可以将命令存储在变量中,然后在前面加上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
(结合适当的动作来模拟 i
、a
、o
等)通过像这样添加宏
: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>
我正在尝试重新映射 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
)没有被记录下来,解决方法是在退出插入模式时将其添加到记录缓冲区中。
为了区分i
、a
、o
等,可以将命令存储在变量中,然后在前面加上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
(结合适当的动作来模拟 i
、a
、o
等)通过像这样添加宏
: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>