🏄
Vimでシンプルなsmooth scroll
はじめに
Vimにはいくつかスムーズスクロールを実現するプラグインがあります。
中には物理演算をするようなものもあるのですが、画面の描画が遅いと動作がもっさりしてしまうことがあって、使うのをやめてしまいました。
しかし、私はset nonumber
を設定しているので、C-d
、C-u
をしたときに画面に連続性がないと見づらいです。
そこで自分で書いてみたところ、意外と簡単な処理でいい感じに動きました。
コード
これだけです。
let s:stop_time = 10
function! s:down(timer) abort
execute "normal! 3\<C-e>3j"
endfunction
function! s:up(timer) abort
execute "normal! 3\<C-y>3k"
endfunction
function! s:smooth_scroll(fn) abort
let working_timer = get(s:, 'smooth_scroll_timer', 0)
if !empty(timer_info(working_timer))
call timer_stop(working_timer)
endif
if (a:fn ==# 'down' && line('$') == line('w$')) ||
\ (a:fn ==# 'up' && line('w0') == 1)
return
endif
let s:smooth_scroll_timer = timer_start(s:stop_time, function('s:' . a:fn), {'repeat' : &scroll/3})
endfunction
nnoremap <silent> <C-u> <cmd>call <SID>smooth_scroll('up')<CR>
nnoremap <silent> <C-d> <cmd>call <SID>smooth_scroll('down')<CR>
vnoremap <silent> <C-u> <cmd>call <SID>smooth_scroll('up')<CR>
vnoremap <silent> <C-d> <cmd>call <SID>smooth_scroll('down')<CR>
s:smooth_scroll()
のところは
function! s:smooth_scroll(fn) abort
let F = function('s:' . a:fn)
for i in range(&scroll/3)
call F()
sleep 10m
redraw
endfor
endfunction
のようにしても動くのですが、これだとキーリピートの間隔を短くしているときにキーを押し続けると処理が止まらなくなってしまいます。
画面のスクロール処理をtimerにのせて、smooth_scroll()
が呼ばれたときに動いているtimerは止めて新しいtimerを開始することで、キーを離したときにスクロールも終了するようになります。
また一度にスクロールする量を1行ではなく3行にすることで、画面の再描画の回数を減らしています。
Discussion