reanimate.vim というプラグインをつくった
さて、今日はチョコの日ということで unite-valentine でもつくろうかと思ったんですが、アニメーションの実装がしんどかったので断念しました。
その代わりといってはなんですが、以前からつくっていた Vim の復元プラグインでもネタにしたいと思います。
(と、いうかこういう機会がないととズルズルと引っ張りそうなので…。
そんな感じで簡単な使い方とかを書いてみます。
まだ、つくっている途中なので破壊的な変更があったらごめんなさい。
unite-session なにそれおいしいの
[簡単な使い方]
" MySaveData という名前を付けて保存 :ReanimateSave MySaveData " 保存した MySaveData を復元 :ReanimateLoad MySaveData
このように名前をつけて保存し、名前を指定して復元を行います。
[保存/復元するデータ]
- session
- viminfo
- ウィンドウの位置とサイズ
保存/復元するデータですが session や viminfo は Vim に依存しているので、特にプラグイン側で特別な事を行なっているわけではありません。
別のいい方をすれば、session や viminfo で出来ないことは基本的に出来ない、と思ってもらった方がいいです。
[コマンド]
コマンド | 動作 |
---|---|
ReanimateSave {name} | {name} で保存。省略されれば最後に保存/復元した名前か g:reanimate_default_save_name が使用される |
ReanimateSaveInput | 名前を入力して保存 |
ReanimateLoad {name} | {name} で保存。省略されれば最後に保存/復元した名前か g:reanimate_default_save_name が使用される |
ReanimateLoadInput | 名前を入力して復元 |
ReanimateSaveCursorHold | autocmd CursorHold で呼び出す場合に使用するコマンド。基本的には ReanimateSave と等価 |
[オプション]
オプション名 | デフォルト値 | 説明 |
---|---|---|
g:reanimate_save_dir | "~/reanimate/save_dir" | 保存するディレクトリ |
g:reanimate_default_save_name | "latest" | デフォルトの保存名 |
g:reanimate_sessionoptions | &sessionoptions | sessionoptions |
g:reanimate_disables | [] | 保存・復元を無効にする機能 |
g:reanimate_disables には
"reanimate_session", "reanimate_viminfo", "reanimate_window"
の3つが設定できます。
[example]
" 保存先のディレクトリ let g:reanimate_save_dir = $VIM."/.vim/save_point" " :ReanimateSave<CR> " のように引数がない場合に使用される名前です let g:reanimate_default_save_name = "latest" " sessionoptions let g:reanimate_sessionoptions="curdir,folds,help,localoptions,slash,tabpages,winsize" " session と viminfo の処理をしない " reanimate_session " reanimate_viminfo " reanimate_window " の3つのいずれかをリストで設定します let g:reanimate_disables = ["reanimate_session", "reanimate_viminfo"]
[unite-reanimate]
unite.vim を使用して、保存されているデータを列挙して保存/復元を行うことが出来ます。
また、デフォルトでは、default-action には何も設定していないので、action から reanimate_save または、reanimate_load を選択するか、起動時の -default-action 引数に渡して使用します。
わたしは下記のようなコマンド呼び出しをマッピングして、保存/復元の選択を行っています。
" :Unite reanimate の呼び出し時に default-action を設定 " 保存 :Unite reanimate -default-action=reanimate_load " 復元 :Unite reanimate -default-action=reanimate_save
[使い方]
わたしが使っている使い方とか。
大まかにはこんな感じですね。
C++ や Vim script なんかの作業状況をサッと切り替えたり、プロジェクトごとに保存とかしています。
また、わたしは下記のような設定を行っています。
" 保存先のディレクトリ let g:reanimate_save_dir = $VIM."/.vim/save_point" " デフォルトの保存名 let g:reanimate_default_save_name = "latest" " sessionoptions let g:reanimate_sessionoptions="curdir,folds,globals,help,localoptions,slash,tabpages,winsize" " 無効にする機能があれば " let g:reanimate_disables = ["reanimate_session", "reanimate_viminfo", "reanimate_window"] " ステータスラインに現在の保存名を出力 function! Last_point() return reanimate#is_saved() ? reanimate#last_point() : "no save" endfunction set statusline=%=[%{Last_point()}\]\[%{(&fenc!=''?&fenc:&enc)}/%{&ff}]\[%03l,%03v] " オートコマンド augroup SavePoint autocmd! " 終了時に保存を行う autocmd VimLeavePre * ReanimateSave " バッファに書き込む時に一緒の保存する " autocmd BufWritePost * ReanimateSave " CursorHold 時には ReanimateSaveCursorHold を使用する " autocmd CursorHold * ReanimateSaveCursorHold " 自動的に復元する場合 " autocmd VimEnter * ReanimateLoad augroup END " ユーザ側で reanimate.vim のイベントに処理を hook する let s:event = { \ "name" : "user_event", \} function! s:event.load_pre(...) " 読み込み前に全てのバッファを保存 :wall " 復元前にタブを削除する :tabonly endfunction function! s:event.save_pre(...) " 保存前に args を削除する try :execute "argd *" catch endtry endfunction call reanimate#hook(s:event) unlet s:event
autocmd 等は上記を参考にして設定してみて下さい。
上記のようにユーザ側で reanimate.vim のイベントに処理を hook する事が出来るのですが、説明すると量が多くなるので今回は割愛します。
[vimrc_local.vim]
各データが保存されているディレクトリ(例えば g:reanimate_save_dir."/latest")に vimrc_local.vim というファイルを保存しておくことでデータの復元時に vimrc_local.vim の :source を行います。
例えば『このデータを復元する場合はこういう Vim の設定にしたい』という場合に便利です。
vimrc_local.vim についての詳細はこことかを参照して下さい。
[Q&A]
以下、自問自答。
- Q.新規で名前をつけて保存したい
- :ReanimateSaveInput もしくは :ReanimateSave {名前} で名前を付けて保存することが出来ます。
- Q.特定の保存/復元する機能を無効にしたい
- g:reanimate_disables に無効にする機能をリストで記述します。
- Q.unite-reanimate で選択しても何も起きない
- Q.復元時にカレントのタブ以外が残っている
let s:event = { \ "name" : "user_event", \} " 復元前のイベント処理を記述 function! s:event.load_pre(...) " 復元前にタブを削除する :tabonly endfunction call reanimate#hook(s:event) unlet s:event
- Q.ファイルが存在しないバッファを復元して欲しくない
- sessionoptions に buffers が設定されていると隠れバッファも保存されてしまいます。
- そういうバッファを復元してほしくない場合は、g:reanimate_sessionoptions または、sessionoptions から buffers の設定を取り除いて下さい。
" 例えばこんな設定 let g:reanimate_sessionoptions="curdir,folds,globals,help,localoptions,slash,tabpages,winsize"
- Q.保存先のディレクトリ設定したい
- g:reanimate_save_dir で設定することが出来ます。
- Q.ステータスラインに現在の保存名を出力したい
- 下記のような設定を行うことで出力することが出来ます。
" ステータスラインに現在の保存名を出力 function! Last_point() return reanimate#is_saved() ? reanimate#last_point() : "no save" endfunction set statusline=%=[%{Last_point()}\]\[%{(&fenc!=''?&fenc:&enc)}/%{&ff}]\[%03l,%03v]
- Q.autocmd CursorHold 時にデータを保存したい
- autocmd CursorHold 時に :ReanimateSave を使用すると不都合が出てくるので、ReanimateSaveCursorHold を使用する必要があります。
" CursorHold 時には ReanimateSaveCursorHold を使用する autocmd CursorHold * ReanimateSaveCursorHold
- Q.データを削除したい
- 現状は Vim から削除する方法はありません。
- g:reanimate_save_dir に保存されているデータディレクトリを直接削除して下さい。
- Q.名前を変更したい
- 現状は Vim から名前を変更する方法はありません。
- g:reanimate_save_dir に保存されているデータディレクトリ名を直接変更して下さい。
- Q.vimfiler や vimshell などのファイルが存在しないバッファも復元したい
- 現状は無理です。
- Q.終了時に自動的に保存して欲しい
- プラグイン側で autocmd の設定は行っていません。
- 下記のようにユーザ側で autocmd を設定する必要があります。
augroup SavePoint autocmd! " 終了時に保存を行う autocmd VimLeavePre * ReanimateSave " バッファに書き込む時に一緒の保存する " autocmd BufWritePost * ReanimateSave " CursorHold 時には ReanimateSaveCursorHold を使用する " autocmd CursorHold * ReanimateSaveCursorHold " 自動的に復元する場合 " autocmd VimEnter * ReanimateLoad augroup END
[今後実装するかも知れない機能]
- 保存データの削除
- 保存名の変更
- vimfiler や vimshell の復元
- データの履歴を保存/復元
- 一箇所に保存するのではなくて、個別のディレクトリを設定できるようにする
- 読み込みに失敗したときにでも強制的に復元する方法
- vimrc_local の作成等
- unite-reanimate の並び順を任意の値でソート
- 量が多くなってきた場合に備えて保存ディレクトリを階層構造にする
※あくまでも予定
と、こんな感じでざっくりと書いてみました。
つくった本人がいうのは当たり前ですが自分では、なかなかいい感じのプラグインに仕上がったと思っています。
特に vimrc_local.vim を活用することによって擬似プロジェクト管理を行うことも出来ます。
まぁ hook などの細かい部分はおいおいブログにでも書いていこうと思います。
うーむ、説明難しいですね。
やはりキャプチャした動画(と画像)が欲しい。
どうでもいいけど、Q&Aとかよくある質問的なものは他のプラグインの help とかにあってもいいんじゃないかと思わなくもない。
……あ、ちなみにわたしは今年2個のチョコを頂きましたよ!(うち1つはゲーマーズでもらってもう1つは…。