1

我有一个存储 vim 命令片段的文件。当我需要一个片段时,我将其拉出,然后使用@". 片段存储为脚本,每个命令一行,如下所示:

:s/foo/bar/g
:echo "hello"
:s/1/2/g

编辑:我从示例中删除了正常模式命令,因为它们不是问题的一部分。

现在这个过程不再起作用了:在执行代码片段时,它只是停在第一行,就好像在等待换行一样。

是否有影响@执行方式的选项?我很确定它在一段时间前工作过......

用 ^M 字符替换换行符是可行的,但会使文件更难处理。


附加信息:

这是另一个症状:当我拉出一个片段时,如果我用它执行它,@"就像我刚才解释的那样,它会停在第一行。但是如果我用它执行它就:@可以了。但是帮助文件似乎并没有暗示这两个命令如何处理寄存器内容的任何区别......

4

2 回答 2

2

我认为问题不在于^Mvs. ^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

如果您现在按下@xline 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

祝你好运!

于 2010-04-29T21:30:02.843 回答
2

我终于找到了罪魁祸首。<C-J>不知何故,我的 .vimrc 文件中有一个命令映射。当使用默认读取时cpoptions,这变成了一个映射<NL>

我是如何发现的:我注意到当用 启动 vim 时-u ~/.vimrc,它确实会执行 yanked 片段。我生成了一个带有和不带有该命令行选项的会话文件,并对它们进行了比较。通过这种方式,我发现一组不同的cpoptionswhere 用于读取相同的 .vimrc 文件,因此在一种情况下映射确实是 on <C-J>,在另一种情况下它被转换为映射 on <NL>

如果有人有类似的问题,我建议仔细查看当前设置的命令映射,带有:cmap.

于 2010-05-04T11:48:17.950 回答