vim-users.jp

Hack #136: Pythonインタフェースを使う(2)

Posted at 2010/04/02
このエントリーをはてなブックマークに追加

前回はPythonインタフェースの基本を紹介しましたが、今回はもう少し突っ込んだ内容について紹介しようかと思います。

変数のコンテキスト

VimScriptからPythonを起動するとき、Pythonは呼ばれたVimScriptのコンテキストで実行されます。なので、以下の例のようにしてVimScriptとPython間で変数をやりとりすることができます。

" VimScript
let s:hoge = "s:hoge"

function Hoge(hoge)
    let hoge = "l:hoge"
    python <<EOM
print vim.eval('s:hoge') # s:hogeと表示
print vim.eval('a:hoge') # a:hogeと表示
print vim.eval('hoge')   # l:hogeと表示

vim.command('let s:hoge = "s:fuga"')
vim.command('let hoge = "l:fuga"')
EOM
    return hoge
endfunction

echo Hoge('a:hoge') " l:fugaと表示
echo s:hoge         " s:fugaと表示

注意点としては、前回vim.eval()のところでも述べたようにVimScriptの内容は全て文字列になるので数値で欲しい場合は、Python側でint(vim.eval("line('.')"))などとキャストする必要があるところです。他にもPythonにはboolean型がありますがVimScriptにはないなど微妙に落とし穴があるので、Python側のif文などでVimScriptの値を参照する際は気を付ける必要があります。また、:pyfileで読み込んだ外部ファイルの中でもこのコンテキストの扱いは有効です。例えば以下の通りです。

" VimScript
pyfile hoge.py
let s:fuga = 's:fuga'
python hoge("hoge")
" hoge.pyとする
def hoge(str):
    print vim.eval('s:fuga') + str # s:fugahogeと表示

また:pythonコマンドで生成したPythonの変数は全てグローバル変数となり、Vimの起動から終了まで全て同じコンテキストとなります。

" VimScript
python <<EOM
hoge = "hoge"
EOM

python <<EOM
print hoge # hogeと表示される
EOM

ユニコード文字の扱い

Pythonはスクリプト自体のエンコードを指定する方法としてマジックコメントを使うことができます。これは、スクリプトファイルの1行目か2行目に、coding:utf-8coding=utf-8などのように/coding[:=]文字コード名/で表される表現があればエンコードとして認識されるというものです。PEP 0263には.pyファイルをVimで編集する場合は、Vimのモードラインとしても有効になるように以下のように書く例が掲載されています。

# vim:set fileencoding=utf-8:

しかしモードラインで'fileencoding'は指定すべきでないので単に、

# coding=utf-8

などと書くべきです。VimScript内の:pythonコマンドではヒアドキュメント風の書き方を使った場合にだけこのマジックコメントを使うことができます。また、マジックコメントは各コマンドごとに書く必要があります。

" utf-8で保存されたVimScript、'encoding'がutf-8の環境
python <<EOM
print u"あいうえお".encode('utf-8') # スクリプトがasciiで書かれていると解釈され文字化けする
EOM

python <<EOM
# coding=utf-8
print u"あいうえお".encode('utf-8') # スクリプトがutf-8で書かれていると解釈されて文字化けしない
EOM

python <<EOM
print u"あいうえお".encode('utf-8') # 前のブロックのマジックコメントは反映されず文字化けする
EOM

ということなので、マルチバイト文字をやりとりする必要がある場合は基本的に:pythonコマンドで一行でスクリプトを渡す形式を使うことはできず、ヒアドキュメント風の使い方をすることになります。また、より汎用的にするには以下のように書くと良いでしょう。

" utf-8で保存されたVimScript、'encoding'は不明
python <<EOM
# coding=utf-8
VIM_ENCODING = vim.eval('&encoding')
print u"あいうえお".encode(VIM_ENCODING)
EOM

Vimから入力を受け取ってPythonに渡すときも同様にしてdecodeすれば文字化けせずにユニコード文字列を渡すことができます。

Pythonのimport

例えば、Pythonインタフェースを作ったプラグインを作っていて、Python部分が長くなるので外部に.pyファイルとして出しておきたい場合を考えます。そんなときは、通常は:pyfileを使えば良いのですが、これはグローバル空間でファイルの中身を実行するので、from module import *したときと同様に外部ファイルの関数や変数を全てグローバル空間に展開してしまいます。これを避けるための方法を考えてみます。

 " pytest.py
def func():
    print "hoge"
 " VimScript (:pyfileを使った例)
pyfile pytest.py
python <<EOM
func() # hogeと表示される
EOM
 " VimScript(:pyfileを使わない例)
let path = expand('%:p:h')
python <<EOM
import vim, sys
sys.path.append(vim.eval('path'))

import pytest # この.vimファイルと同じディレクトリにpytest.pyを置いておく
pytest.func() # hogeと表示される
EOM

このように、VimScript側でスクリプトの置いてあるディレクトリを取得し、sys.pathにパスを追加しておくことで、所望の.pyファイルをimportすることができます。

今回は以上です。前回と今回で説明した内容を理解すれば、Pythonインタフェースを利用したpluginも自在に書けるようになると思います。

tsukkee

もどる
blog comments powered by Disqus