4

私が使用しているバージョン管理システム (Perforce) の .vimrc にいくつかのマクロを作成しました (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が文句を言います。

4

2 に答える 2

4

I think you want something along these lines:

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

Remember that :map is a dumb sequence of keystrokes: what you're mapping F8 to has to be a sequence of keystrokes that would work if typed. A <CR> in the middle of the :if statement doesn't mean ‘and press Enter when executing the command at this point if the condition is true’; it means ‘press Enter here when in the middle of typing in the :if command’, which obviously isn't what you want.

Building it up a piece at time, from the inside out:

  1. There's a shell command you sometimes want to run.
  2. That shell command needs to be inside an :if to do the ‘sometimes’ bit, and so have an :endif following it.
  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シェル コマンドのようなコマンドの後に使用することはできません。:!|

関数を使用する方が簡単かもしれません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マクロでor:echoコマンドを使用してアクセスします。

于 2013-01-10T22:31:01.487 に答える