Vim script で namespace る

この記事は Vim Advent Calendar 2012 279日目の記事になります。


さて、Vim script の autoload 関数を使用(定義)する場合、次のような名前空間ディレクトリパス)を # で区切って使用します。

call unite#custom#default_action('directory' , 'tabvimfiler')
call unite#custom#default_action('qfixhowm' , 'tabopen')
call unite#custom#source('qfixhowm', 'sorters', ['sorter_qfixhowm_updatetime', 'sorter_reverse'])
call unite#custom#source('quickfix', 'converters', 'converter_quickfix_highlight')
call unite#custom#source('location_list', 'converters', 'converter_quickfix_highlight')


これは他のプラグインと関数名を重複してしまうのを抑制する事ができるので便利なのですが、関数名が長くなってしまいます。
こんな時に C++ の namespace のような機能があれば…っていう事で簡単に書いてみました。

[ソース]

function! s:function()
    let tmpfile = tempname()
    let tmp = &verbosefile
    let &verbosefile = tmpfile
    try
        redir => flist
        silent function
        redir END
    finally
        call delete(tmpfile)
        let &verbosefile = tmp
    endtry
    return split(flist, "\n")
endfunction


function! Namespace(target, using_sharp)
    let target = a:target . "#"
    let result = {}
    for name in map(filter(s:function(), 'v:val =~ target'), "matchstr(v:val, '.* \\zs.*\\ze(')")
        if a:using_sharp
            let result[substitute(substitute(name, target, "", ""), '#', '_', "g")] = function(name)
        else
            let result[substitute(name, target, "", "")] = function(name)
        endif
    endfor
    return result
endfunction


command! -nargs=* -bang
\   Namespace
\   execute 'let ' . [<f-args>][0] . ' = Namespace([<f-args>][1], <bang>0)'


function! s:main()
    " namespace なし
    call unite#custom#default_action('directory' , 'tabvimfiler')
    call unite#custom#default_action('qfixhowm' , 'tabopen')
    call unite#custom#source('qfixhowm', 'sorters', ['sorter_qfixhowm_updatetime', 'sorter_reverse'])
    call unite#custom#source('quickfix', 'converters', 'converter_quickfix_highlight')
    call unite#custom#source('location_list', 'converters', 'converter_quickfix_highlight')

    " namespace あり
    Namespace u unite#custom
    call u.default_action('directory' , 'tabvimfiler')
    call u.default_action('qfixhowm' , 'tabopen')
    call u.source('qfixhowm', 'sorters', ['sorter_qfixhowm_updatetime', 'sorter_reverse'])
    call u.source('quickfix', 'converters', 'converter_quickfix_highlight')
    call u.source('location_list', 'converters', 'converter_quickfix_highlight')
endfunction
call s:main()


:Namespace に展開する変数名と関数のプレフィックスを渡して、その変数にプレフィックス以下の関数を展開します。
ただし、# は変数名として使えなかったので _ に置き換えられています。


[注意1]

ぶっちゃけ処理速度が遅いです。
なのでどうしても必要でない場合以外は使用しないほうが無難です。

[注意2]

既に読み込まれた autoload 関数にしか使用できません。
なので使用するタイミングによっては関数が呼び出せない事があります。

[まとめ]

勢いでつくってみたんですが微妙な感じ。
コードはスッキリとするんですが多用すると遅くなってしまうのがネック…。
使うとしたらスクリプトローカルに展開するとかかなぁ。
それなら1度しか呼ばれないのでパフォーマンスもそこまで気にならないかもしれない。