ええと、 vim
で python
を書く記事ではありません。
vimscript
の py3
もしくは py3file
で定義した python
関数を、 vimscript
から楽に呼び出せるようにする記事です。
作成中
https://github.com/ousttrue/vim-pycall
vimscript の py3 コマンド
例
:python print(sys.version)
短い python
文を投げっぱなしにして、副作用は python
側でがんばれーという感じですね。引数を渡すことも、結果をもらうこともできなくなくないか。
pydo
はわいの目的には合わないのでスルー。
引数を渡すためには明示的に sys.argv[] を使って設定してください。例:
:python sys.argv = ["foo", "bar"]
:pyfile myscript.py
・・・python側に最初から書いておけばいいのでは・・・
既存のコマンドラインのpythonスクリプトを無変更で呼び出すことを想定している?
python 側で vim モジュールを使うのだ
import vim
# pythonにvim変数を渡す
foo = vim.eval("g:foo")
# pythonからvim変数を変える
value = 1
vim.command(f"let g:ret = {value}")
変数名を固定すれば vim
と python
でやりとりできそうではある。
vim.bindeval
は nvim
には無かったのでスルー。
python関数を呼び出すラッパー関数を作る
を見て関数を経由することで引数名を固定する方法を知る。
# py3 か py3file で定義されたことにする
def hello(name):
print('Hello {0}'.format(name))
function! pycall_hello(name)
" python定義済みの関数呼び出し
py3 hello(vim.eval('a:name'))
endfunction
a:name
であって g:name
でないのが素敵。なるほど。
返り値の名前を python 関数の引数に追加しよう
# python側でprintするのをやめて let で vim側に値を渡す
def hello(name, ret_name):
vim.command(f"let {ret_name} = '{name}'")
function! pycall_hello(name)
" python定義済みの関数呼び出し
py3 hello(vim.eval('a:name', 'l:ret'))
if exists('l:ret')
return l:ret
endif
endfunction
返り値も同様に名前を固定。
g:ret
でなく l:ret
にできたので、vimscript
のグローバル変数が python
関数毎に必要になるということは無くなった。
任意のpython関数を呼び出せる汎用の呼び出し関数にする
python関数に2つの拡張が必要
- 関数名を受ける引数の追加
- vim関数の可変長引数をpythonに渡す
pythonの関数名を受けて間接的に関数を呼び出す py_dispatcher
を作った。
def py_dispatch(name, ret_name, args):
'''
name: python関数名
ret_name: 返り値を格納するvim変数名
args: 引数
'''
# dispatch function
value = globals()[name](*args)
if value:
# return to vim by let
value = to_vim(value)
command = f'let {ret_name} = {value}' # ここで ret_name に値をセットすることでvimに値を返す
try:
vim.command(command)
except vim.error as e:
print('error', command)
print('error', e)
function! PyCall(name, ...)
py3 py_dispatch(vim.eval('a:name'), 'l:ret', vim.eval('a:000'))
if exists('l:ret')
return l:ret
endif
endfunction
globalスコープの任意のpython関数を呼び出せるようになった。
使い方
# 他のところで定義
def hello2(hello1, hello2):
return f'hello {hello1} and {hello2}!'
hello
関数を探して、引数を渡して呼び出し、返り値を echo
する。
:echo PycCall('hello', 'hoge', 'fuga')
使ってみる
ToDo