unite-autojumpをつくった

Posted on | 1088 words | ~3mins
vim

この記事は Vim Advent Calendar 2013 46 日目の記事になります. # 46 日目とは

私事ですが,諸般の事情によりエディタを Sublime Text から Vim に変えました. Vim を使い始めて数ヶ月,そろそろプラグインでも作ってみたいなーと思っていたところ,昨年の 12 月に Vim プラグイン読書会なるものが Lingr の Vim 部屋にて行われました.

参考: Vim プラグイン読書会を行いました - C++でゲームプログラミング

これは!と思って参加したのですが,そういえば普段お世話になっている unite.vim の拡張方法とか理解してないよなーってなりました. そこで勉強がてら Vim から unite.vim のインターフェースを通して autojump を使う的な簡単プラグインを作ってみました.

zoncoen/unite-autojump - Github

autojump は,cdで移動したディレクトリを記録して,カレントディレクトリに関係なく過去に移動したディレクトリに移動できるコマンドです. 導入などは以下参照.

ライフチェンジングな percol と autojump の紹介 - 404 Engineer Logs

今回は普段 Terminal 上で使い倒してるautojumpを Vim から使えるようにしてみました.

導入

NeoBundle で簡単にインストール.

NeoBundle 'zoncoen/unite-autojump'

当然ですが unite.vim と autojump が必要です.

使い方

Vim 上で以下のコマンドを実行すると,unite.vim のインターフェースで autojump ライクな機能が使えます.

:Unite autojump

.vimrcに以下のように書いておけば,:jで呼び出せて便利(かもしれない).

nnoremap :j :<C-u>Unite autojump<CR>

簡単な解説

unite source と unite action を追加する簡単なプラグインです. autojump は過去に移動したディレクトリ履歴と各ディレクトリの重みがautojump --statで取得できるので,その結果を unite.vim に渡しています.

let s:autojump_command = 'autojump -s'

let s:unite_source = {
\ 'name': 'autojump',
\ 'description': 'candidates from autojump database',
\ 'default_action' : 'cd_autojump',
\ }

function! s:unite_source.gather_candidates(args, context)
let l:directories = reverse(split(unite#util#system(s:autojump_command),"\n"))[7:]
return map(directories,
\ '{
\ "word": split(v:val, "\t")[1],
\ "source": "autojump",
\ "kind": "cdable",
\ "action\_\_directory": split(v:val, "\t")[1],
\ }')
endfunction

function! unite#sources#autojump#define()
return exists('s:autojump_command') ? s:unite_source : []
endfunction

また,cdしたらその結果をautojump --addで autojump のデータベースに反映するcd_autojumpという unite action を定義しています.

let s:autojump_add_command = 'autojump -a %s'

let s:action = {
\ 'description': 'change current working directory with adding path to autojump database',
\ 'is_selectable': 0,
\ }

function! s:action.func(candidate)
if a:candidate.action**directory != ''
execute g:unite_kind_cdable_cd_command a:candidate.action**directory
echo a:candidate.action**directory
call unite#util#system(printf('autojump -a %s', a:candidate.action**directory))
endif
endfunction

call unite#custom#action('cdable', 'cd_autojump', s:action)

TODO

Terminal 上でのcdコマンドのように,Vim 上での:cdでも移動先のパスを autojump のデータベースに反映できたらなぁと思ってます. :cdに hook して処理を行うことができればよさそう( autocmd のオレオレ event を作る?). Vim 力高い方アドバイスお願いします :-)

まとめ

初 Vim プラグイン作成でしたが,autojump に便利オプションがあったため割と簡単にできてしまいました. unite source や unite action の作り方は,unite.vim の:helpや ujihisa さんの unite-locate を参考にさせていただきました.

あと余談ですが,vim script のテストに関して現時点でのベストプラクティスとかはあるんでしょうか? テストフレームワークがたくさんあって悩ましい…