2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

vimscriptからpythonするのを補助するpycallを作る

Last updated at Posted at 2019-04-23

ええと、 vimpython を書く記事ではありません。

vimscriptpy3 もしくは 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}")

変数名を固定すれば vimpython でやりとりできそうではある。

vim.bindevalnvim には無かったのでスルー。

python関数を呼び出すラッパー関数を作る

Pythonでvim pluginを書く

を見て関数を経由することで引数名を固定する方法を知る。

# 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

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?