Hack #124: Vimで非同期実行を行う
Posted at 2010/02/13ツイート
VimがEmacsと比較して一番劣っている機能として、コマンドの非同期実行があげられます。ここでは現状のコマンド実行の問題点とEmacsとの比較、その解決方法について議論を行います。
Vimのコマンド実行の欠点
Vimはsystem()
や:read
を用いて外部コマンドを実行し、その結果を得ることができます。これは非常に便利なのですが、Vimが起動した外部コマンドの終了を待ち合わせるため、Vimが停止してしまうという欠点があります。これは特にquickrunや:make
を実行しているときに問題となります。プログラムをバックグラウンドで実行すれば、終了を待ち合わせずにすみますが、それでは結果がとれません。さらにWindows上のGVimの場合、外部コマンドを実行するたびにDOS窓が開いて煩わしいです。
処理内容がシェルに依存するという欠点もあります。たとえば、Windowsでプログラムを起動するためには適切にエスケープしなければいけません。
Emacsとの比較
対するEmacsはどうでしょう。Emacsでは、start-process
関数を用いてプロセスを生成することにより、コマンドを非同期的に実行できます。
comint-modeでもこれを用いてインタプリタを起動し、非同期で通信しています。
ただし、Emacsにはマルチスレッド関数がありません。全ての処理はシングルスレッドです。
外部インタフェースの欠点
RubyやPerl, Pythonといった外部インタフェースを用いるという解決策もあります。 しかし、外部インタフェースは通常のVimScriptとは文法が異なるため、連携が非常にややこしいです。時折フリーズしたり、エラーが起こったときにデバッグしづらいという欠点もあります。さらに、すべての環境で使えるわけでもありません。インストールしているRubyやPerl, Pythonのバージョンにも依存するなど、 非同期に通信するためだけに外部インタフェースを用いるのは大げさすぎます。 ただし外部インタフェース内ではマルチスレッドが使えるので、真の非同期通信をするためには、外部インタフェースを用いるほかありません。
vimprocについて
外部ライブラリであるvimprocを用いて外部コマンドと通信すれば、上記に挙げたほとんどの欠点が解消されます。 vimprocとはYukihiro Nakadairaさんが開発している、優れた非同期実行ライブラリです。私が改良したものをgithub上で開発しています。 http://github.com/Shougo/vimproc/tree/master ソースからコンパイルしてVimのautoloadディレクトリに、「proc.soまたはproc.dll」と「vimproc.vim」をコピーすれば準備完了です。
ここでは、vimprocで実装されているvimproc#system
関数を紹介します。これは、標準のsystem
関数を置き換えることができます。
ただしシェルを起動しないので、シェルの内部コマンドは動作しません。パイプやリダイレクトも動かないので注意してください。
パイプやリダイレクトについては、今後実装予定です。
let l:result = vimproc#system('ls')
vimprocを駆使すれば非同期実行をエミュレーションできますが、スレッドの存在しないVimでは使い方がとてもややこしいので、ここでは説明を省略します。
興味がある場合にはvimprocのtestディレクトリにあるサンプルスクリプトを参照してください。
ネットワーク通信もできるので、Twit.vimみたいなプログラムも簡単に作成できます。
いずれはcomint-modeのように、インタプリタ実行機能を統合させたいと思っています。
ちなみにVimScriptでのシェル実装であるvimshellでも、vimprocを用いて非同期実行を行っています。
その他の非同期実行ライブラリ
その他のライブラリとして、vimprocやvimshellをもとにNico Raffatoさんが製作しているConqueというプラグインがあり、とても精力的に開発されています。Emacsのansi-term.elを目標にしているようで、動作が散漫なのが欠点ですが、多機能のようなので使用してみるといいかもしれません。
CursorHold
イベントの落とし穴
しかも、Vimには指定された時間が経過したら関数を呼び出すタイマー機能がありません。
CursorHoldI
やCursorHold
イベントで代用するという手がありますが、これにはイベントごとに時間を設定できない、
ポップアップが表示されているときは呼ばれない、カーソルが動くまで呼ばれないといった欠点があります。
この欠点は本質的に回避不能です。Vim本体にタイマー実行機能が搭載されるのを待つしかありません。
clientserver機能を使う
Vimのclientserver機能を用いると、処理が完了した際に機能を呼び出すコールバック機能を実装することが可能です。
ただし、X環境が必要になります。Windows上でも使用できますが、あらかじめ別のVimを用意しておく必要があります。詳しくは:help clientserver
を参照してください。
もどる
blog comments powered by Disqus