はじめに
この記事には Vim ユーザにとって便利なことはあまり書かれていない気がします。
Vim script を記述する際に面白い感じのコードを書いてみて、放置することに決めたので供養するための記事です。
やったこと
オブジェクト指向 + イベント駆動でバッファを更新するスクリプトを書いてみた。
オブジェクト指向っぽさ
下記のコードを書いてインスタンスを生成して利用します。
これは割と有名な書き方な気がします。
function! your#namespace#new()
return s:Prototype.new()
endfunction
let s:Prototype = {}
function! s:Prototype.new()
return extend(deepcopy(s:Prototype), {
\ 'flag': v:false
\ })
endfunction
function! s:Prototype.toggle()
let self.flag = !self.flag
endfunction
イベント駆動っぽさ
Vim にはビルトインでイベントを発火する仕組みがあります。(autocmd と呼ぶ)
しかし、基本的にグローバルな領域で発火されるので「特定インスタンスのメソッドをコールバックで呼ぶ」というののやり方がやりにくいです。(と思っているが、簡単な方法があるのかも)
自分はいいやり方がわからなかったので、下記のようなコードを書いてインスタンスとコールバック関数を紐づけてみました。(今回はバッファに紐づくインスタンスという形を取ってみました。)
function! your#namespace#new()
return s:Prototype.new()
endfunction
let s:Prototype = {}
function! s:Prototype.new()
let instance = extend(deepcopy(s:Prototype), {
\ 'bufnr': -1
\ })
" buffer を作成して、bufnr をインスタンスに紐付ける
badd prototype
let instance.bufnr = bufnr('$')
" 管理バッファで発生したイベントにインスタンスのコールバックを登録する
augroup printf('prototype_%s', self.bufnr)
autocmd!
call self.bind_autocmd('BufWinEnter', function(self.on_buf_win_enter))
call self.bind_autocmd('BufWinLeave', function(self.on_buf_win_leave))
augroup END
return instance
endfunction
function! s:Prototype.on_buf_win_enter()
echomsg 'on_buf_win_enter'
endfunction
function! s:Prototype.on_buf_win_leave()
echomsg 'on_buf_win_leave'
endfunction
function! s:Prototype.bind_autocmd(event, func)
call setbufvar(self.bufnr, printf('prototype_%s', a:event), a:func)
execute printf('autocmd! %s <buffer=%s> call getbufvar(%s, "prototype_%s")()',
\ a:event,
\ self.bufnr,
\ self.bufnr,
\ a:event)
endfunction
終わりに
なにか denite.nvim のようなピッカーを書いてみようかなとお勉強がてらコードを書いてみていて、面白い書き方になってきたので記事にしてみました。
コードはここにあります。
どう考えてもフィルタ速度が問題になりそうだし、denite.nvim 規模まで育てるのは無理だ。と悟ったので放置することに決め込んで記事を書いて供養とすることにしました。