やりたいこと
vimのプラグイン作りたい
でもvimscriptわからん!!
Pythonで書きたい!!!!
つくるもの
MyNameIs <name>
と入力すると、Hello <name>
と表示される実装はpythonに逃がして、vimscriptはpythonラッパーのような形で使う
VimScriptでのPython
よく使うのは、python
と pyfile
pythonとpyfileは本質的には同じで、ソースが直書きされているかファイルに分離されているかの違い。たとえば、次の2つのコードは同じ
python:
pythonprint('Hello')
pyfile
pyfile hello.py
print('Hello')
pythonと書いたらその行は既にPythonの世界であることに注意する。次のように書いて随分と悩んだ。
function! hello#hello(name)pythonhello(a:name)
endfuncion
これが間違いであることは、次のように書き換えてみるとわかりやすい
function! hello#hello(name)python<< endpytohnhello(a:name)
endpython
endfuncion
また、pydo
ものもある。pydo <body>
と書くと、
def_vim_pydo(line,linenr):<body>
という関数が作られ、選択範囲に対して1行ごとに、lineに行の内容が、linenrに行番号が渡されて呼び出される。値を返すとその値で行が置換されるが、関数なので当然returnと書かなければいけない。なのでちょっと長くなってダサい。こういうのはrubyのほうが綺麗に書けそう。
例えば、下のコードを実行すれば選択範囲の行頭に行番号が挿入される
pydo return str(linenr)+ line
実装
ディレクトリ構成
plugin/
hello.vim
autoload/
hello.vim
src/
hello.py
hello.py
vimとか気にせずに、関数を作る
defhello(name):print('Hello {0}'.format(name))
autoload/hello.vim
ここが肝
やることは3つ。
- 作ったpythonスクリプトを読み込む。
- pythonないでvimをインポートする
- pluginから呼び出される関数を作り、関数内でpythonの関数を叩く
まず、作ったpythonスクリプトを読み込む。スクリプトのパスの取得方法に注意。
pyfile<sfile>:h:h/src/hello.py
次に、vimをインポートする。これをやらないと値のやり取りができない。
pythonimportvim
最後に、plugin側から呼び出される関数を作り、関数内でpythonの関数を叩く。pythonと欠いた行は既にpythonの世界なので、vimモジュールを通して引数を渡す。
function! hello#hello(name)pythonhello(vim.eval('a:name'))endfunction
plugin/hello.vim
ここは普通のプラグインとなにも変わらず。autoloadに記述した関数と、コマンドの橋渡し
command!-nargs=1 MyNameIs call hello#hello(<f-args>)
完成形
defhello(name):print('Hello {0}'.format(name))
lets:save_cpo =&cposetcpo&vimpyfile<sfile>:h:h/httpstatus.pypythonimportvimfunction! hello#hello(name)pythonhello(vim.eval('a:name'))endfunctionlet&cpo=s:save_cpo
unlet s:save_cpo
if exists("g:loaded_hello")finishendifletg:loaded_hello =1lets:save_cpo =&cposetcpo&vim
command!-nargs=1 MyNameIs call hello#hello(<f-args>)let&cpo=s:save_cpo
unlet s:save_cpo
参考
その他
実際に作ったのはhttpstatus.vimというプラグイン。VimからHTTPステータスコードがどんな意味だったか確認できる。テキストはPythonのBaseHTTPServer.BaseHTTPRequestHandler.responses
を使用している。
意気揚々と作ってしまったが、どうやらmattnさんが既に作っていたらしい。さらに、今回作ったものよりも高機能っぽい(ステータスコードだけじゃなくてメッセージでも調べられる)けど、どうせ私はステータスコードからしか調べないので十分なのでした。