lazy_importとインテリセンス(続き)

15日に書いた記事( lazy_importとインテリセンス - wonderful_pandaの日記 )の記事について、ありがたいことにVimに詳しい方々から色々と突っ込みをいただきました。
pythoncomplete.vimの改善(lazy_importの解釈) · Issue #110 · vim-jp/issues · GitHub

その中で、「Pythonなんだからpythoncomplete.vimを直接さわらなくてもいけるんじゃないの」という指摘がありまして、とりいそぎやってみました。
pythoncomplete.vimでlazy_importでインポートしたモジュールも補完できるようにする · GitHub

:python <<EOS
# coding=utf8
import re
from types import MethodType

# lazy_importブロックを検出するための正規表現(適当)
re_lazy_import = re.compile(
ur'''^lazy_import\s*\(globals\(\)\s*,\s*("""|\'\'\') # lazy_import(globals(), """
(?P<contents>[^"\']*)                           # inside here document
\1\s*\)                                         # """)
''', re.M|re.X)

# 各行のインデントを検出するための正規表現
re_indent = re.compile(ur'^[ \t]+', re.M)

class PyCmpPatchForBzr(object):
    """
    lazy_importでインポートされたモジュールの補完をpythoncompleteで行うための
    モンキーパッチ
    """
    
    def strip_lazyimport(self, source):
        """ソース内のlazy_importを通常のimportに置換する"""
        def unindent(text):
            return re_indent.sub('', text)
        return re_lazy_import.sub(
	            lambda m:unindent(m.group('contents')), source)

    def apply(self):
        """モンキーパッチ適用"""
        if hasattr(Completer, 'evalsource_orig'):
            return
        Completer.evalsource_orig = Completer.evalsource
        def evalsource(cmpl, text, line):
            cmpl.evalsource_orig(self.strip_lazyimport(text), line)

        Completer.evalsource = MethodType(evalsource, None, Completer)

    def restore(self):
        """モンキーパッチ解除"""
        if not hasattr(Completer, 'evalsource_orig'):
            return
        Completer.evalsource = Completer.evalsource_orig
        delattr(Completer, 'evalsource_orig')

pycmp_patch_for_bzr = PyCmpPatchForBzr()

EOS

" lazy_importの補完をpythoncompleteで有効にする
function! pycmp_for_bazaar#apply()
    :python <<EOS
pycmp_patch_for_bzr.apply()
EOS
endfunction

" lazy_importの補完をpythoncompleteで無効にする
function! pycmp_for_bazaar#restore()
    :python <<EOS
pycmp_patch_for_bzr.restore()
EOS
endfunction

このファイルをVimに読み込んだ後、

  • :call pycmp_for_bazaar#apply() で機能を有効にして、
  • :call pycmp_for_bazaar#restore() で元に戻すことができます。

もう一工夫すればもっと汎用的にできそうですね。