Vim で timer_stop() を使うときの注意

さて、最近(でもないけど) Vimtimer_start()timer_stop() という組み込みの timer 関数が追加されました。 これは一定時間ごとに処理を呼び出す事ができる関数群です。

function! Test(timer)
    echo 'Handler called'
endfunction
" 500ms ごとに Test() 関数を3回呼び出す
let timer = timer_start(500, 'Test', {'repeat': 3})

こんな感じでコールバック関数を指定して timer を実現することが出来ます。 また timer_stop() で任意の timer を中断することも出来ます。

[コールバック関数内で timer_stop() 出来ない]

さて、この timer を使用して次のようなことをしたいことがあると思います。

function! Test()
    let disp = { "value" : 0 }
    function! disp.call(...)
        echo self.value
        let self.value += 1

       " 5回呼び出されたら止める
        if self.value > 5
            call timer_stop(self.id)
        endif
    endfunction

   " 辞書関数をコールバックとして登録
    let disp.id = timer_start(500, disp.call, { "repeat" : -1 })
endfunction

しかし、コールバック関数内から自信を止めることが出来ないようで、これは意図した動作をしません。

[回避方法]

timer を止める timer を登録します。

function! Test()
    let disp = { "value" : 0 }
    function! disp.call(...)
        echo self.value
        let self.value += 1

       " 5回呼び出されたら止める
        if self.value > 5

           " timer を止める timer を登録
            let stop = { "id" : self.id }
            function! stop.call(...)
                return timer_stop(self.id)
            endfunction
            call timer_start(0, stop.call)
        endif
    endfunction
    let disp.id = timer_start(500, disp.call, { "repeat" : -1 })
endfunction

これで止めることが出来ました。