Vimで :messages
とコマンドを実行すると, :echomsg
と :echoerr
から出力されたメッセージ履歴を閲覧することができる.
:help :messages
によると,tinyバージョンであれば,過去のメッセージを20行,それ以外だと200行閲覧することができる.
しかし,最新のメッセージのみを閲覧したい場合,最初の方のメッセージを邪魔に感じることがある.
ターミナルの clear
コマンドのように,過去のメッセージを消去するには,
function! s:clear_messages() abort for i in range(201) echomsg '' endfor endfunction command! -bar Clear call s:clear_messages()
とコマンドを定義し, :Clear
とコマンドを実行するとよい.
201回ではなく200回空文字列を出力した場合,1行分クリアできないことがあるので注意しよう.
ちなみに,
function! s:clear_message() abort for i in range(201) echomsg ' ' endfor endfunction command! -bar Clear call s:clear_message()
のように,201回半角スペースを出力した場合,201行の半角のスペースが連続してしまい,視覚的な負担は減るが,縦長の履歴になり,煩わしいことに変わりはない.
これだけでは芸が無い(この記事を書いてから,全く同じ内容の記事があることに気がついた)ので, head
コマンドや tail
コマンドのように,最初からxx行,最後のxx行のmessages履歴を表示できるコマンドを定義しよう.
function! s:redir(cmd) abort let [verbose, verbosefile] = [&verbose, &verbosefile] set verbose=0 verbosefile= redir => str execute 'silent!' a:cmd redir END let [&verbose, &verbosefile] = [verbose, verbosefile] return str endfunction function! s:echo(use_echomsg, lines) abort if a:use_echomsg for line in a:lines echomsg line endfor else for line in a:lines echo line endfor endif endfunction function! s:messages_head(has_bang, ...) abort let n = a:0 > 0 ? a:1 : 10 let lines = filter(split(s:redir('messages'), "\n"), 'v:val !=# ""')[: n] call s:echo(a:has_bang, lines) endfunction command! -bar -bang -nargs=? MessagesHead call s:messages_head(<bang>0, <f-args>) function! s:messages_tail(has_bang, ...) abort let n = a:0 > 0 ? a:1 : 10 let lines = filter(split(s:redir('messages'), "\n"), 'v:val !=# ""') if n > len(lines) let n = len(lines) endif let lines = lines[len(lines) - n :] call s:echo(a:has_bang, lines) endfunction command! -bar -bang -nargs=? MessagesTail call s:messages_tail(<bang>0, <f-args>)
:MessagesHead 5
や :MessagesTail 20
のように,引数に指定した行数だけ, :messages
の履歴を表示する.
引数に指定しなかった場合は,デフォルト値として,10行だけ表示するようになっている.
!
を付加してコマンドを実行した場合は, echo
ではなく, echomsg
で出力する.
以下はおまけの話だ.
もし,第二引数にハイライトグループを指定したいなら,次のようにするとよい.
function! s:redir(cmd) abort let [verbose, verbosefile] = [&verbose, &verbosefile] set verbose=0 verbosefile= redir => str execute 'silent!' a:cmd redir END let [&verbose, &verbosefile] = [verbose, verbosefile] return str endfunction function! s:echo(use_echomsg, lines) abort if a:use_echomsg for line in a:lines echomsg line endfor else for line in a:lines echo line endfor endif endfunction " ハイライトグループを補完する関数 " 2つ目の引数でないと,補完候補を返却しない " -complete=highlight では2つ目の引数のみ補完という動作が実現できないので,エミュレート関数を用意した function! s:complete_messages(arglead, cmdline, cursorpos) let nargs = a:cmdline ==# '' ? 1 : len(split(split(a:cmdline, '[^\\]\zs|')[-1], '\s\+')) if nargs == 2 || (nargs == 3 && a:arglead !=# '') let _arglead = tolower(a:arglead) return sort(filter(map(split(s:redir('highlight'), "\n"), 'split(v:val, "\\s\\+")[0]'), \ '!stridx(tolower(v:val), _arglead)')) else return [] endif endfunction function! s:messages_head(has_bang, ...) let n = a:0 > 0 ? a:1 : 10 let lines = filter(split(s:redir('messages'), "\n"), 'v:val !=# ""')[: n] if a:0 > 1 execute 'echohl' a:2 endif call s:echo(a:has_bang, lines) if a:0 > 1 echohl None endif endfunction command! -bar -bang -nargs=+ -complete=customlist,s:complete_messages MessagesHead \ call s:messages_head(<bang>0, <f-args>) function! s:messages_tail(has_bang, ...) let n = a:0 > 0 ? a:1 : 10 let lines = filter(split(s:redir('messages'), "\n"), 'v:val !=# ""') if n > len(lines) let n = len(lines) endif if a:0 > 1 execute 'echohl' a:2 endif let lines = lines[len(lines) - n :] call s:echo(a:has_bang, lines) if a:0 > 1 echohl None endif endfunction command! -bar -bang -nargs=+ -complete=customlist,s:complete_messages MessagesTail \ call s:messages_tail(<bang>0, <f-args>)
2つ目の引数の補完時のみ,ハイライトグループの補完ができる. すなわち,
:MessagesHead 15 E<Tab>
や
:MessagesTail 25 <Tab>
と <Tab>
を入力すると,ハイライトグループが補完される.