vimで非同期してみた

Vimはシングルスレッドである。何かが動いてる間は他のことはできない。
一方、vimには各種言語のインターフェースが付いてる。RubyPerlPythonからVimが操作できる。
で、これらの言語では大体スレッドが使える。ならば、これらの中でスレッド作ればVimでも非同期行けるんじゃね?ってのが今回のお話。
早速やってみた。Pythonはまともに触ったことないので変なところがあるかも知れない。突っ込み歓迎。
ちなみに試した環境は、Fedora 9 + Vim 7.2 + Python 2.5.1。

python << EOP
import vim
import thread
import time

def run():
  for i in range(10):
    time.sleep(1)
    vim.command("echo " + str(i))

thread.start_new_thread(run, ())
EOP

1秒ごとにechoするだけ。これを実行すると見事に1秒ごとにechoされる。もちろん、その間Vimは操作可能。コマンドラインモードに入っても問題なし。
調子に乗って試しにこんなことして見る。

function! g:async_command()
  return 'javac ' . expand('%') . ' && java ' . expand('%:t:r')
endfunction
function! g:async_callback(res)
  new
  set buftype=nofile
  call append(0, split(a:res, "\n"))
  wincmd p
  redraw
endfunction

command! RunAsync call s:async()

function! s:async()
python << EOP
import vim
import thread
import commands

def run():
  command = vim.eval("g:async_command()")
  result = commands.getoutput(command)
  vim.eval("g:async_callback('" + result + "')")

thread.start_new_thread(run, ())
EOP
endfunction

編集中のJavaファイルをコンパイルして実行して、結果を新しい窓に出す。実行中もVimの操作は可能。あくまでテストなのでエラーチェック全然してなかったり毎回出力バッファ開いたりと全体的に適当だが気にしてはいけない。
ここで使ってるcommandsモジュールはUnixオンリーなので、Windowsではこうする。

import vim
import thread
import nt as os

def run():
  command = vim.eval("g:async_command()")
  f = os.popen(command)
  result = f.read()
  f.close()
  vim.eval("g:async_callback('" + result + "')")

thread.start_new_thread(run, ())

import os ってやるとなぜか見つからないって言われた。インタプリタでは行けるんだけどなぁ。
flymakeやflydiffなんかで使うと便利そうです。欠点はif_pythonが必須ってことくらいか。応用範囲は広そう。
ちなみに、最初はPerlRubyでやったのだけどスレッドの後処理の当たりでエラー出てどうしようもなかったので慣れないPythonで試したらできたという落ちです。Perl,Rubyでできた方いたら教えてください。