代码之家  ›  专栏  ›  技术社区  ›  UncleZeiv

在寄存器中存储多个命令时,如何处理换行符?

  •  1
  • UncleZeiv  · 技术社区  · 14 年前

    我有一个文件,在其中存储VIM命令的片段。当我需要一个片段时,我猛拉它,然后用 @" . 代码段存储为脚本,每个命令一行,如下所示:

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

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

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

    有什么选择会影响 @ 执行吗?我很肯定它早就开始工作了…

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


    其他信息:

    另一个症状是:当我猛拉一个片段时,如果我用 @ 正如我刚才解释的,它停在第一行。但如果我用 :@ 它起作用了。但是帮助文件似乎并不意味着两个命令处理寄存器内容的方式有任何不同…

    2 回复  |  直到 14 年前
        1
  •  2
  •   Bill Odom    14 年前

    我不认为问题是 ^M VS ^J . VIM宏将其中一个视为记录的宏的有效行尾字符。我认为问题是额外的换行。

    在您的示例中,后面至少有一个伪换行符 2j 除非在复制代码片段时特别小心,否则后面可能还有另一个 10k 也。这些多余的换行符像是压力 <Enter> 在正常模式下——它们将光标向下移动一行。

    以下是我认为您希望代码片段的样子:

    :s/foo/bar/g
    2j:s/1/2/g
    10k
    

    (即使这有点误导——你还是要小心不要在 10K )

    为什么这些额外的换行会产生如此大的差异?嗯,首先,它们使你至少偏离你期望的位置一行,这会抛出你想在特定行上做的任何事情(比如执行 :s// 命令)。

    然而,更重要的是,我认为在您的示例中发生的事情是,如果宏试图使用 <进入& 在缓冲区的最后一行。(我猜Vim认为这是一个错误,任何错误都会导致宏停止运行。)

    下面是一个例子。假设您已将此代码段存储在寄存器x中:

    4j
    :echo "Done"
    

    (注意后面的换行符 4j )

    此外,假设在缓冲区中有以下五行(并且只有这五行):

    line 1
    line 2
    line 3
    line 4
    line 5
    

    如果你现在按 @x line 1 , the :echo "Done" 从不执行。VIM将光标向下移动4行至 line 5 ,然后由于有多余的换行符,尝试向下移动一行,但不能。宏在该点停止执行,然后 :echo 命令有机会运行。

    但是,如果将X寄存器更改为:

    4j:echo "Done"
    

    所以,为了回到你原来的例子,我敢打赌接下来会发生什么 2J 试图将光标移动到无法移动的位置,这会导致宏停止。屏幕的底线包含最后执行的命令( :s/foo/bar/g ,这使得它看起来像是Vim在等你按回车键。

    最后,我强烈建议使用另一种方法来存储和执行VIM命令序列。您使用的技术对于简单的案例来说是可以接受的,但是它很脆弱,而且不能很好地扩展。Vim有一个完整的脚本语言,其中包括函数和定制命令,它可以用来做你现在正在做的所有事情,但是以一种更健壮的方式。VIM脚本是一个大主题,但我将从这里开始:

    :help script
    

    请务必阅读 :normal 命令,用于执行正常模式命令(如 2J 10K )在脚本中。

    祝你好运!

        2
  •  2
  •   UncleZeiv    14 年前

    我终于找到了罪犯。不知怎么的,我有一个命令映射 <C-J> 在我的.vimrc文件中。使用默认值读取时 cpoptions ,这变成了一个映射 <NL> .

    我是怎么发现的:我注意到当Vim -u ~/.vimrc 它确实会执行扬起的代码片段。我生成了一个包含和不包含该命令行选项的会话文件,并对它们进行了比较。这样我发现 蜂拥 以前读取相同的.vimrc文件,因此在一种情况下,映射确实打开了 <C-J> ,在另一个中,它被转换为上的映射 <NL & GT; !

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

    推荐文章