4

我已经在我的 .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

当 vim 尝试加载文件时,这会导致 bash 抱怨:

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

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

4

2 回答 2

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>语句中间的A:if并不表示“Enter如果条件为真,则在此时执行命令时按”;它的意思是“Enter在输入命令的过程中按这里:if”,这显然不是你想要的。

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

  1. 您有时想要运行一个 shell 命令。
  2. 该 shell 命令需要在一个内部:if执行“有时”位,因此有一个:endif跟随它。
  3. After a literal ! everything following is passed to the shell, including | characters which normally signify the start of another Vim command. That's reasonable, because | is a perfectly good character to use in shell commands. So we need some way of containing the shell command. :exe can do this; it executes the supplied string as a command — and its argument, being a string, has a defined end. So the general form is :if condition | exe "!shell command" | endif.
  4. Your shell command has an expression in it. Using :exe makes this easy, since you can simply concatenate the string constant parts of the command with the result of the expression. So the command becomes :exe "!p4 revert" . expand("%:p") — try that out on its own on a file, and check it does what you want before going any further.
  5. Putting that inside the condition gives you :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | exe "!p4 revert" . expand("%:p") | edit | endif — again try that out before defining the mapping.
  6. Once you have that working, define the mapping. A literal | does end a mapping and signify the start of the next Vim command. In your original the mapping definition only went to the end of the condition (check it with :map <F8> after loading a file) and the !p4 part was being run immediately, on the Vim file that defines the mapping! You need to change each | in your command into <Bar>, similarly to how each press of Enter in your command needs writing as <CR>. That gives you the mapping above. Try it by typing it at the command line first, then do :map <F8> again to check it's what you think it is. And only then try pressing F8.
  7. If that works, put the mapping in your .vimrc.
于 2013-01-11T00:11:34.917 回答
3

使用管道将多个 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

您可以在宏中使用:callor命令访问它。:echo

于 2013-01-10T22:31:01.487 回答