我在我的.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会抱怨 .
2 回答
使用管道将多个vim命令串在一起并不是特别明确,并且存在许多偏心 . 关键的是,(参见:help :bar)它不能在像命令
:!
这样的命令之后使用,它将|
字符作为其参数 .您可能会发现使用system()函数更容易 .
例如 .
如果您在文件名中包含空格或引号等字符(或者巧妙地将其命名为
; rm -rf ~
(请勿在家中尝试此操作!)),shellescape()包装器非常有用 .为了创建更易读/可维护的代码,您可能希望将代码移动到一个函数中:
您可以在宏中使用
:call
或:echo
命令进行访问 .我想你想要这样的东西:
请记住,
:map
是一个愚蠢的击键序列:你要映射的是必须是一系列击键,如果键入的话 .:if
语句中间的<CR>
并不意味着“如果条件为真,则在此时执行命令时按Enter
”;这意味着在输入:if
命令的过程中“按Enter
”,这显然不是你想要的 .从内到外,随时将它构建成一块:
有时候你想运行一个shell命令 .
那个shell命令需要在
:if
里面做'有时'位,所以后面有一个:endif
.文字
!
后面的所有内容都传递给shell,包括通常表示另一个Vim命令开始的|
个字符 . 这是合理的,因为|
是一个在shell命令中使用的非常好的字符 . 所以我们需要一些包含shell命令的方法 .:exe
可以做到这一点;它将提供的字符串作为命令执行 - 其参数(作为字符串)具有已定义的结尾 . 所以一般形式是:if condition | exe "!shell command" | endif
.你的shell命令中有一个表达式 . 使用
: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>
检查)并且!p4
部分正在运行,定义映射的Vim文件!您需要将命令中的每个|
更改为<Bar>
,类似于在命令中每按一次Enter
需要将其写为<CR>
. 这为您提供了上面的映射 . 首先在命令行输入它,然后再次执行:map <F8>
以检查它是否符合您的想法 . 然后尝试按F8
.如果可行,请将映射放在.vimrc中 .