我在我的.vimrc中为我正在使用的版本控制系统编写了一些宏(Perforce)(请不要为vim建议perforce插件,我试过它,我不喜欢它)。它们都可以正常工作,除了恢复宏,它由于确认提示而中断(我需要这样做,所以我不会意外地指责我的变化)。它目前看起来像这样:
map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | !p4 revert <C-R>=expand("%:p")<CR><CR><CR>:edit<CR> | endif
当vim尝试加载文件时,这会导致bash抱怨:
bin/bash: -c: line 0: syntax error near unexpected token `('
看看缓冲区bash看到的,看起来错误是vim在第一个管道之后发送了所有内容,而不仅仅是用于bash的部分。我尝试了一些替代方案,但我似乎无法使其工作。当我删除管道和endif(使用简写if)时,我已经让它正确显示确认对话框,但是在用户给出响应之后vim会抱怨。
答案 0 :(得分:4)
我认为你想要这些内容:
: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
的必须是一系列键击,如果键入的话。 <CR>
语句中间的:if
并不意味着'如果条件为真,则在此时执行命令时按Enter
';这意味着在键入Enter
命令的过程中“按:if
,这显然不是你想要的。
从内到外建立一块:
:if
内部来执行'有时'位,所以跟随它有:endif
。!
后面的所有内容都传递给shell,包括通常表示另一个Vim命令开始的|
个字符。这是合理的,因为|
是在shell命令中使用的非常好的字符。所以我们需要一些包含shell命令的方法。 :exe
可以做到这一点;它将提供的字符串作为命令执行 - 其参数(作为字符串)具有已定义的结尾。所以一般形式是:if condition | exe "!shell command" | endif
。:exe
可以简化这一过程,因为您可以简单地将命令的字符串常量部分与表达式的结果连接起来。因此命令变为:exe "!p4 revert" . expand("%:p")
- 在文件上自行尝试,并在继续之前检查它是否符合要求。:if confirm('Revert to original?', "&Yes\n&No", 1)==1 | exe "!p4 revert" . expand("%:p") | edit | endif
- 在定义映射之前再试一次。|
确实结束了映射并表示下一个Vim命令的开始。在您的原始映射定义中,仅在条件结束时(在加载文件后使用:map <F8>
检查)并且在定义映射的Vim文件上立即运行!p4
部分!您需要将命令中的每个|
更改为<Bar>
,类似于命令中每次按Enter
的方式都需要写为<CR>
。这为您提供了上面的映射。首先在命令行输入它,然后再次:map <F8>
检查它是否符合您的想法。然后尝试按F8
。答案 1 :(得分:3)
使用管道将多个vim命令串在一起并不是特别明确,并且存在许多偏心。重要的是,(参见:help :bar
)在shell命令:!
之类的命令之后不能使用它,它会将|
个字符视为其参数。
您可能会发现使用system()
功能更容易。
E.G。
: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
命令进行访问。