個人的にもう前時代感あふれるcmd.exeなんて使いたくないPowershellが好きなのでvimでもset shell=powershell
しているんですけど、どうしても一部機能でトラブルが起きがちで、今回はdiffがどうしても動かなかったのでなんとかした話です。
結果が見たいわ!その子のソースを見せてちょうだい!
" diff関連if has ('win32')set diffexpr=MyDiff()endiffunction! MyDiff()letopt=""if&diffopt =~"icase"letopt=opt."-i "endifif&diffopt =~"iwhite"letopt=opt."-b "endifsilent execute '!C:\path\to\diff.exe -a --binary '.opt.v:fname_in .' '.v:fname_new .'" > "'.v:fname_out
endfunction
どうしてこんなことになってしまったんだ…
問題はおそらく2つに絞られます。
- Powershellがdiff=>Compare-Objectへのエイリアスを既に張っている
- Vimで
set shell=Powershell
した際にリダイレクトとquoteの関係がおかしい
屋上に行こうぜ
まず前者に関しては、Powershellのエイリアスを消すとか、苦情のメールを入れるなどでも対応できるかと思われますが、「あるものはできるだけ残す」という個人的なポリシーと、結局vimrc書けば済むとわかったのでそちらで解決します。幸い、ヘルプにサンプル関数があるので1、そのまま持ってきてそれから考えます。
set diffexpr=MyDiff()function MyDiff()letopt=""if&diffopt =~"icase"letopt=opt."-i "endifif&diffopt =~"iwhite"letopt=opt."-b "endifsilent execute "!diff -a --binary ".opt.v:fname_in ." ".v:fname_new . \" > ".v:fname_out
endfunction
あとはこれの!diff
の部分だけ使えるdiffのバイナリに変えれば解決するんですけど…
どぼぢでごんなごどずるのぉぉぉ!?
VimでPowershellを使う場合、シェル周りの設定は大体こうなるのが普通なんだそうなのでそのままこれを使っています…
if has('win32')setshell=powershell
set shellcmdflag=-cset shellquote=\"
set shellxquote=endif
これでシェルを使ってリダイレクト結果を拾うコマンドではpowershell -c "foo" > bar
となって、一時ファイルもしっかり拾えるように…少なくともqiitaCtlのときは問題ないので、拾えるようになってるはずです。正直わからん。おしえてVimmer!
さておき、じゃあこのスクリプトでdiff.exeだけ書き換えてやってみると、うまくいかないんだなこれが。vimrunのウィンドウがある短い時間で見てみたんですけど…
Powershell -c "C:\path\to\diff.exe diff1.tmp diff2.tmp > out.tmp"
ファイル名はともかくだいたいこうなります…え、shellquoteは…?えぇー…
わたしこれ嫌い!
冷静に考えたら関数内でリダイレクト処理書いちゃってるのでこうなるのが当然なんですよね…しょうがないので嫌いな類の解決方法で強引に乗り切ったのが最初のソースになります。要はシェルに送る文字列の中で強引にquoteを切って解決しました。エレガントじゃないなぁ…
おしえてVimmer!
実際コレどうなんです?なんかもっとエレガントな解決方法ある気がしてならないんですよ。某名無しさん曰く、まだ危ないエイリアスがあるらしいので、シェル起動時に環境変数放り込んでPowershell側のprofileで予めエイリアス切る条件分岐を仕込むとか、そもそもshellquote
の設定とdiffexpr
の設定で気がついてないところがあって、実は上手くやればdiffexpr
だけでなんとかなるとか…正直Vimの設定群を追いかけきれてないのでこの方法に自信がないです。
編集中に気がついたvim操作関係のこと
- 毎度
<C-r>+
をして酷い目に遭うので<C-g>u
する癖をちゃんとつけること。
:h diff-diffexpr
を参照のこと ↩