▼ 2012/01/30(月) VimScriptの練習に編集中ファイルのSVNブランチ名を取得してみた
Vim | 7.3 |
---|---|
SVN | 1.6.16 |
目次
ソースコード: https://github.com/fumiz/vim/blob/master/svn-branch-test.vim
使い方:
1. .vim/pluginに入れる
2. .vimrcでステータスラインの設定を変更
set statusline=%n\:%y%F\\|%{(&fenc!=''?&fenc:&enc).'\|'.&ff.'\|'}%m%r%=<%l/%L:%p%%>(%{g:get_current_svn_branch_name()})3. ブランチ名がステータスラインに表示されている
ブランチの置き場所が特別な場合は.vimrcで次のような感じで正規表現を設定します。
let g:svn_branch_test_extract_regex = '\/branches\/[^\/]\+\/\([^\/]\+\)'

■ 原理
ブランチ名を取得する方法として、SVNの管理ファイルを見に行くやり方と、svn infoコマンドの結果から取り出すやり方の2種類がありますが、なんとなく外部コマンドを使いたくなかったのでSVNの管理ファイルを見に行くやり方を採用しました。SVNは管理下にあるディレクトリに.svnディレクトリを作成し、次のように管理情報を格納します
. ├── .svn │ ├── all-wcprops │ ├── entries │ ├── prop-base │ ├── props │ ├── text-base │ └── tmp ├── LICENSE ├── Makefile ├── applicationこの、.svn/entriesというファイルにリポジトリのURLと現在のファイルの位置が記されています
dir 1396 http://svn.sourceforge.jp/svnroot/bathyscaphe/bathyscaphe/branches/v111-BASED-BRANCH http://svn.sourceforge.jp/svnroot/bathyscaphe(例はSourceForgeのBathyScaphe)
そこで、
1. 編集中のファイルの存在するディレクトリ下に.svn/entriesファイルが存在するかチェック
2. 存在するなら.svn/entriesファイルから正規表現でブランチ名を取得
という流れでブランチ名を取得することにします。
ちなみに、SVNはブランチを置く場所が慣例的に/branchesになっているものの、実際は割とフリーダムになっています。
例えば、上のBathyScapheの例では
/bathyscaphe/branches/ブランチ名となっていますし、大人数で一つのリポジトリを共有している場合は次のように
branchesの下に階層を深く掘ってブランチを作っている場合もあります。
/branches/ユーザ名/プロジェクト名/ブランチ名どの場合でも通用する一つの正規表現を作ることは難しいので、.vimrcで自分の環境にあわせて正規表現を編集できるようにすることにします。
■ スクリプト本体
github:svn-branch-test.vim" extract branch name from .svn/entries " 1. .vim/pluginに入れる " 2. :ShowBranch " 3. g:svn_branch_test_extract_regexに指定した正規表現でブランチ名を取り出し表示 " " 正規表現の適用対象は.svn/entriesの5行目と6行目から取り出した " SVNチェックアウト対象のルートからのパス " " デフォルトの正規表現は/branches/ブランチ名/*を想定 " " .vimrcに次のように埋め込むことで編集中バッファに対応したブランチ名をステータスラインに表示する " set statusline=%n\:%y%F\\|%{(&fenc!=''?&fenc:&enc).'\|'.&ff.'\|'}%m%r%=<%l/%L:%p%%>(%{g:get_current_svn_branch_name()}) " " 参考にしたコード: " http://coderepos.org/share/browser/dotfiles/vim/kana/dot.vimrc?rev=7152 " http://www.vim.org/scripts/script.php?script_id=1234 " 二重読み込み防止 if exists('g:loaded_svn_branch_test') finish endif let g:loaded_svn_branch_test = 1 " 設定の定義(.vimrcで変更できる) if !exists('g:svn_branch_test_extract_regex') let g:svn_branch_test_extract_regex = '\/branches\/\([^\/]\+\)' endif " コマンドの定義 command! ShowBranch call s:show_branch() " コマンドの本体 function! s:show_branch() echo g:get_current_svn_branch_name() endfunction " カレントディレクトリのSVNブランチ名を取得 function! g:get_current_svn_branch_name() return s:svn_branch_name(expand('%:p:h')) endfunction " 指定したディレクトリのSVNブランチ名を返す(キャッシュ対応) let s:_svn_branch_name_cache = {} function! s:svn_branch_name(dir) let cache_entry = get(s:_svn_branch_name_cache, a:dir, 0) if cache_entry is 0 unlet cache_entry let cache_entry = s:_svn_branch_name(a:dir) let s:_svn_branch_name_cache[a:dir] = cache_entry endif return cache_entry endfunction " 指定したディレクトリのSVNブランチ名を返す function! s:_svn_branch_name(dir) let head_file = s:_svn_branch_name_key_file_path(a:dir) return s:_svn_branch_name_extract(head_file) endfunction " 指定したディレクトリの.svn/entriesファイルパスを返す function! s:_svn_branch_name_key_file_path(dir) return a:dir . '/.svn/entries' endfunction " .svn/entriesからブランチ名を抽出 function! s:_svn_branch_name_extract(entries_path) if !filereadable(a:entries_path) return '' endif let branch_line = s:_svn_branch_name_read(a:entries_path) let branch_name = matchlist(branch_line, g:svn_branch_test_extract_regex)[1] return branch_name endfunction " .svn/entriesからSVNのルート以下のパスを取得 function! s:_svn_branch_name_read(entries_path) let lines = readfile(a:entries_path, '', 6) if len(lines) != 6 return '' endif " SVNのルートを取り出す。次のような文字列が格納されていることを想定している " branch_line->svn://svnroot/branches/mybranch/pa/th/to/module " root_path ->svn://svnroot let branch_line = lines[4] let root_path = lines[5] return branch_line[len(root_path):len(branch_line)-1] endfunctionグローバルスコープの関数を定義して、
" カレントディレクトリのSVNブランチ名を取得 function! g:get_current_svn_branch_name() return s:svn_branch_name(expand('%:p:h')) endfunctionステータスラインから呼び出すことで、ステータスラインに情報を表示できるようです
set statusline=%n\:%y%F\\|%{(&fenc!=''?&fenc:&enc).'\|'.&ff.'\|'}%m%r%=<%l/%L:%p%%>(%{g:get_current_svn_branch_name()})
■ 自分用Vimプラグインの作り方
1. hogehoge.vimファイルにスクリプトを書く2. .vim/pluginに放り込む
スクリプトの中身は次のような枠組みになりそうです。
github:hello.vim
" 二重読み込み防止 if exists('g:loaded_hello') finish endif let g:loaded_hello = 1 " .vimrcで変更できる設定の定義 " この場合g:hello_stringという変数が.vimrcで定義れていない場合に " デフォルト値として'VimScript'を使うことになっている if !exists('g:hello_string') let g:hello_string = 'VimScript' endif " コマンドの定義(ユーザ定義のコマンドは大文字で始まる必要があるらしい) command! ShowHello call s:show_hello() " コマンドの本体 function! s:show_hello() echo "hello " . g:hello_string . "!" endfunction
■ おわりに
スクリプトを配布するなら、autoloadという機構で外部から関数をロードしやすいようにしたり、ドキュメントを付けたりといった配慮があると良いようですが、私自身がまだあまり理解できていないので今回はあくまで自分用に使うなら、という前提です。Vimはだいたいの環境で使えて軽量なので使いやすいエディタですよね。VimScriptを自分で書ければ環境固有の面倒な処理を簡単に解決できたりしそうです。凝ったことをしないのなら難しくなかったので試してみることをオススメします。
参考にしたページ
▼ コメント(0件)
- TB-URL http://mitc.s279.xrea.com/adiary.cgi/0107/tb/