【Vim Advent Calendar 2012】Vim プラグインを github で公開するまで【1日目】

Vim Advent Calendar 2012 1日目の記事になります。

[宣伝]

毎週土曜日 23時から vimrc 読書会を開催しています。
次回は 12月1日(今日!!)の 23時から行います。
内容はだいぶ緩い感じなので、気になる方は覗いてみるといいと思います。
Vim で分からないことを質問するいい機会でもあるので( thinca さんが答えてくれる!)お待ちしていますー!!

概要

さて、今回はわたしが実際にプラグインを作成するときの注意点や流れなんかを簡単にまとめてみたいと思います。
github で公開』と書いてありますが、git 成分は少なめです。

予め用意しておくといいもの


git は最低限 push commit が操作出来れば問題ないかと思います。
neobundle はプラグインの管理が簡単なので使用しています。
neocomplcache/neosnippet も Vimスクリプトを書く上で役に立つので入れておくと捗ります。

どんなプラグインを作るか

どんなプラグインを作るのか、という事ですがわたしはプラグインをつくりはじめる前に簡単な実装を先に書いてしまう事が多いです。
その後に Vimプラグインとして移植するような感じですね。
それを踏まえた上で今回は次のような Vimスクリプトプラグイン化してみようかと思います。

let s:verbosefiles = []

function! g:verbosefile_push(file)
    call add(s:verbosefiles, &verbosefile)
    let &verbosefile = a:file
    return a:file
endfunction


function! g:verbosefile_pop()
    let &verbosefile = get(s:verbosefiles, -1)
    call remove(s:verbosefiles, -1)
endfunction

command! QuickRunVimScriptSilentBegin
\   call g:verbosefile_push(tempname())

command! QuickRunVimScriptSilentEnd
\   call g:verbosefile_pop()


" 使い方
" temp ファイルへと出力する
let temp = tempname()
call g:verbosefile_push(temp)

echo "homu"
echo "mado"

call g:verbosefile_pop()

echo readfile(temp)
" => ['', 'homu', 'mado']


verbosefile を操作するプラグインですね。
指定した範囲の出力を特定のファイルへと出力します。
具体的な使い方は以前書いたプログの記事を参考にしてみてください。


さて、今回はこの Vimスクリプトプラグイン化してみたいと思います。

プラグインの名前を決める

何はともあれプラグイン名を決めましょう。
ここで決めた名前は次のような箇所で関係してきます。


autoload やコマンド等は実際にプラグインとして使用する場合に影響してきますね。
例えば autoload/hoge.vim という名前にした場合、hoge#func() のような形で関数へとアクセスします。
なので autoload で定義されている関数を多用する場合はプラグイン名が短いほうが使いやすいでしょう。
実際にわたしが作成した reti.vim は autoload の関数を多用するので短い名前にしています。
その上で、わたしは次のようなことに注意して名前を決めています。

  • 既存のプラグイン名と被らないようにする
  • (なるべく)後続のプラグイン名を被らないようにする
  • autoload の関数を多用するのであればプラグイン名を短くする
  • モチベーションが上がるような名前を付ける


Vim で同じ名前のプラグインがある場合、基本的にその名前は避けるべきです。
わたしの場合は、既存のプラグイン名はもちろん、誰かが作りそうな名前も避けるようにしていますね。
なのでプラグインの機能に直接関係ないようなユニークな名前を付ける事が多いです。
(例 reti.vim、chaiend.vim


まぁ実際のところ名前から来るモチベーションが大きいので『これだ!』というような名前であればなんでもいいかと思います_(:3 」∠)_
がんばってカッコイイ名前をつけましょう!!


と、いうことで今回作成する Vimプラグインは『budou .vim』という名前を付けたいと思います(適当。

提供する機能を考える

実際にプラグインを書く前にプラグインが何を提供するのかをちょっとまとめてみます。
プラグインとして提供される機能の多くは、


などがあります。
今回、プラグイン側で実装する機能は、

  • verbosefile_push/verbosefile_pop 関数
  • QuickRunVimScriptSilentBegin/QuickRunVimScriptSilentEnd コマンド


にしたいと思います。

プラグインを書く上での注意点

その前に Vimプラグインを作る上での注意点をいくつか。

  • コマンドやグローバル変数名にはプラグイン名をプレフィックスを付ける
  • plugin/*.vim にはなるべく処理を書かない
    • 起動時間に影響しないようにするため
  • 破壊的な変更は避ける
    • set ではなく setlocal を付ける
    • キーマッピングする場合は を意識する
      • グローバルなキーマッピングは基本的に避ける
      • どうしても行いたい場合はオプションで無効にできるようにする


Vim は割と簡単に既存の設定を書き換えることが出来るので、set やキーマッピングする場合は注意が必要です。
また plugin/*.vim にはなるべくコードは書かないほうがよいです。
これは、plugin にコードを書いてしまうと Vim の起動時に Vimスクリプトが読み込まれてしまい、起動時間に影響してしまうからです。
なので基本的には autoload に処理を記述して、それを plugin から呼び出すような形がベターかと思います。
ここら辺の詳しい話は mattn さんの記事や既存の Vimプラグインなんかが参考になるかと思います。

プラグインを作成

と、いう事でやっとプラグインの作成です。
今回は下記のようなファイルを作成しました。

[D:/vim/plugins/vim-budou/autoload/budou.vim]

scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim

let s:verbosefiles = []

function! budou#verbosefile_push(file)
    call add(s:verbosefiles, &verbosefile)
    let &verbosefile = a:file
    return a:file
endfunction

function! budou#verbosefile_pop()
    let &verbosefile = get(s:verbosefiles, -1)
    call remove(s:verbosefiles, -1)
endfunction

function! budou#reset()
    let s:verbosefiles = []
endfunction

let &cpo = s:save_cpo
unlet s:save_cpo

[D:/vim/plugins/vim-budou/plugin/budou.vim]

if exists('g:loaded_budou')
  finish
endif
let g:loaded_budou = 1

let s:save_cpo = &cpo
set cpo&vim


command! BudouSilentBegin
\    call budou#verbosefile_push(tempname())

command! BudouSilentEnd
\    call budou#verbosefile_pop()


let &cpo = s:save_cpo
unlet s:save_cpo


plugin/budou.vim で定義してあるコマンドが autoload の関数を呼び出しているだけ、ということが分かりますね。
これで、コマンドか関数が呼び出されるまで実際の処理が読み込まれないので Vimの起動時間の短縮に繋がります。
コマンド名はプレフィックスを付けると名前が長くなりそうだったので適当に短くしました。
あと reset 関数も追加。


ディレクトリ構成に関してですが、わたしの場合 D:/vim/plugins が各プラグインを保存しているディレクトリになり、その下に vim-budouプラグイン名であり githubリポジトリ名)を作成しています。
(余談ですが、わたしがプラグインを作成する場合 vim-{プラグイン名}のようなリポジトリ名をつけます。


次にプラグインの読み込みですが、わたしは neobundle を使用しているので下記のような設定を追加して、プラグインの読み込みを行っています。

NeoBundle "vim-budou", {
\        "base" : "D:/vim/plugins",
\        "type" : "nosync"
\    }


これで、neobundle を使用して budou.vim が読み込まれます。
実際のディレクトリ構成は github に上がっているものを参照してみて下さい。

githubリポジトリを作成

ここから github 周りの操作になります。
github のトップページからリポジトリの作成を行います。


次に必要なデータを入力して [Create repository] で githubリポジトリを作成します。


その後にコマンドから push する手順が表示されるのであとはその通りに行うだけです。
(git commit する時に作成したプラグインのファイルを commit するのを忘れないように


git push した後にちゃんと github に反映されているか確認して終了です。

まとめ

ざっくりとですが流れをまとめてみました。
本当は doc や test なんかも書くべきなんですけど時間の都合上端折りました。ごめんなさい。
今回は割りと簡単な構造でしたが、Vimプラグインを書く上で分からない事が出てきた場合は既存の Vimプラグインを参考にしてみるのが一番の近道だと思います。
その点でも github だと手軽にソースを見ることが出来るので便利ですね。
この機会に自分の vimrc にある Vimスクリプトプラグイン化してみてはいかがでしょうか。
何事も慣れだと思うのでどんどん githubVimプラグインをつくっていけばいいと思います!

全体的な流れ

[次回予告]

明日の Vim Advent Calendar 2012 は、@kaoriya さんです。
親子丼食べたい。