我认为问题不在于^M
vs. ^J
. Vim 宏会将其中任何一个视为记录的宏的有效行尾字符。我认为问题在于额外的换行符。
在您的示例中, 之后至少有一个虚假的换行符2j
,除非您在复制代码段时特别小心,否则后面可能还有另一个10k
。这些额外的换行符就像<Enter>
在普通模式下按下一样——它们将光标向下移动一行。
这是我认为您希望片段看起来像的样子:
:s/foo/bar/g
2j:s/1/2/g
10k
(即使这有点误导 - 你仍然必须小心不要在 . 之后复制换行符10k
。)
为什么这些额外的换行符会产生如此大的差异?好吧,一方面,它们会导致您与您期望的位置至少相差一行,这会导致您在特定行上想要做的任何事情(比如执行:s//
命令)。
然而,更重要的是——这就是我认为在你的例子中发生的事情——如果宏试图<Enter>
在缓冲区的最后一行使用,Vim 会停止宏播放。(我猜 Vim 认为这是一个错误,任何错误都会导致宏停止运行。)
这是一个例子。假设您已将此代码段存储在寄存器 x 中:
4j
:echo "Done"
(注意后面的换行符4j
。)
此外,假设缓冲区中有以下五行(并且只有这五行):
line 1
line 2
line 3
line 4
line 5
如果您现在按下@x
,line 1
则:echo "Done"
永远不会执行。Vim 将光标向下移动 4 行到line 5
,然后由于额外的换行符而尝试再向下移动一行,但它不能。:echo
在命令有机会运行之前,宏会在该点停止执行。
但是,如果您将 x 寄存器更改为:
4j:echo "Done"
所以回到你原来的例子,我敢打赌,发生的事情是额外的换行符2j
试图将你的光标移动到它不能去的地方,这会导致宏停止。屏幕的最后一行包含最后执行的命令 ( :s/foo/bar/g
),这使得 Vim 看起来像是在等待您按下 Return 键。
最后,我强烈推荐使用另一种方法来存储和执行 Vim 命令序列。您使用的技术对于简单的情况是可以容忍的,但它很脆弱并且不能很好地扩展。Vim 有一个完整的脚本语言,包括函数和自定义命令,它可以用来做你现在正在做的所有事情,但是以更健壮的方式。Vim 脚本是一个很大的话题,但我将从这里开始:
:help script
请务必阅读有关该命令的信息,该命令可让您在脚本中:normal
执行普通模式命令(如2j
和)。10k
祝你好运!