【问题标题】:vim: map command with confirmation to keyvim:带有确认键的映射命令
【发布时间】:2013-01-10 22:13:24
【问题描述】:

我在我的 .vimrc 中为我正在使用的版本控制系统 (Perforce) 编写了一些宏(请不要建议 vim 的 perforce 插件,我试过了,但我不喜欢它)。除了revert 宏,它们都工作正常,它由于确认提示而中断(我需要它,所以我不会不小心把我的更改拿掉)。目前看起来是这样的:

map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | !p4 revert <C-R>=expand("%:p")<CR><CR><CR>:edit<CR> | endif

这会导致 bash 在 vi​​m 尝试加载文件时报错:

bin/bash: -c: line 0: syntax error near unexpected token `('

查看 bash 看到的缓冲区,错误似乎是 vim 在第一个管道之后发送所有内容,而不仅仅是用于 bash 的部分。我尝试了一些替代方案,但似乎无法使其发挥作用。当我删除管道和 endif(使用简写 if)时,我已经让它正确显示确认对话框,但是在用户给出响应后 vim 会抱怨。

【问题讨论】:

    标签: vim


    【解决方案1】:

    我认为你想要一些类似的东西:

    :map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 <Bar> exe "!p4 revert" . expand("%:p") <Bar> edit <Bar> endif<CR><CR>
    

    请记住,:map 是一个愚蠢的击键序列:您将F8 映射到的必须是一个如果键入就可以工作的击键序列。在:if 语句中间的&lt;CR&gt; 并不意味着“如果条件为真,则在此时执行命令时按Enter”;它的意思是“在输入:if 命令的过程中在此处按Enter”,这显然不是您想要的。

    从内到外,一次次地构建它:

    1. 有时您想运行一个 shell 命令。
    2. 该 shell 命令需要位于 :if 中才能执行“有时”位,因此需要在其后添加 :endif
    3. 在文字! 之后的所有内容都传递给shell,包括| 通常表示另一个Vim 命令开始的字符。这是合理的,因为| 是一个非常适合在 shell 命令中使用的字符。所以我们需要某种方式来包含 shell 命令。 :exe 可以这样做;它将提供的字符串作为命令执行——它的参数,作为一个字符串,有一个定义的结束。所以一般形式是:if condition | exe "!shell command" | endif
    4. 您的 shell 命令中有一个表达式。使用:exe 使这很容易,因为您可以简单地将命令的字符串常量部分与表达式的结果连接起来。所以命令变成了:exe "!p4 revert" . expand("%:p")——在文件上自己尝试一下,在继续之前检查它是否符合你的要求。
    5. 将其放入条件中会得到:if confirm('Revert to original?', "&amp;Yes\n&amp;No", 1)==1 | exe "!p4 revert" . expand("%:p") | edit | endif — 在定义映射之前再次尝试。
    6. 完成该工作后,定义映射。文字 | 确实结束了映射并表示下一个 Vim 命令的开始。在您的原始文件中,映射定义只到了条件的末尾(在加载文件后使用:map &lt;F8&gt; 检查它)并且!p4 部分正在立即运行,在定义映射的 Vim 文件上!您需要将命令中的每个| 更改为&lt;Bar&gt;,类似于在命令中每次按下Enter 需要写为&lt;CR&gt;。这给了你上面的映射。首先在命令行中输入,然后再次输入:map &lt;F8&gt; 以检查它是否是您的想法。然后才尝试按F8
    7. 如果可行,请将映射放入您的 .vimrc

    【讨论】:

    • 谢谢,很遗憾我只能接受一个答案,但我也赞成你的答案。
    【解决方案2】:

    使用管道将多个 vim 命令串在一起并没有特别明确的定义,并且有许多怪癖。至关重要的是,(请参阅:help :bar)它不能在诸如 shell 命令:! 之类的命令之后使用,该命令将| 字符视为其参数。

    您可能会发现使用system() 函数更容易。

    例如

    :echo system("p4 revert " . shellescape(expand("%:p")))
    

    shellescape() 包装器在文件名中有空格或引号之类的字符时非常有用(或者巧妙地将其命名为 ; rm -rf ~(不要在家里尝试这个!))。

    为了创建更具可读性/可维护性的代码,您可能希望将代码移动到函数中:

    function Revert()
        if confirm('Revert to original?', "&Yes\n&No", 1)==1
            return system("p4 revert " . shellescape(expand("%:p")))
        endif
    endfunction
    

    您可以通过在宏中使用:call:echo 命令来访问。

    【讨论】:

    • 解决方案中有一个小错误,命令需要“p4 revert”,而不是“p4”,但总体而言格式有效。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 2016-04-21
    • 1970-01-01
    • 2012-01-13
    相关资源
    最近更新 更多