読者です 読者をやめる 読者になる 読者になる

'nobuflisted' なバッファの作り方

vim

Vim Advent Calendar 2012 356日目の記事です。

バッファをバッファリストに登録したくないときがあります。
バッファリストに登録されていないバッファは:lsでは表示されず、:bnext :bpreviousでのバッファ切換の対象になりません。
また、Vim終了時に次回起動時のための情報を書き込むviminfoファイルのバッファリスト保存・復元から除外されます。つまりVim終了時にはそのバッファは破棄され次回起動に持ち越しません。
このオプションは通常、その場限りの情報を表示するだけで、書き込む予定のない、使い捨てのバッファに設定します。

しかし、せっかく'buflisted'オプションをオフに設定しても、バッファの内容を変更すると勝手に'buflisted'がオンに設定し直されてしまいます。
正しくは「バッファの編集を始めると」オンになるのでした。:edit:split :vsplit :newなどで切り替えるとオンにされるみたいです。つまり:editなどを使わず:bufferでバッファを切り替えるのなら:setlocal nobuflistedを設定するだけでよいです。

ここではいかにして、何らかの形で意図せず'buflisted'オンになっても'buflisted'をオフに保つようにするバッファを作るのかを解説します。また、特別なバッファに設定するべき他のオプションも併せて説明します。

変更の予定のないバッファの場合

バッファを変更する予定がなければ、ただ単に'nobuflisted'オプションを設定すればいいです。
その際、ユーザにバッファの内容を変更を禁止させるように'nomodifiable'オプション、読み込み専用だということをユーザに示すために'readonly'オプションもセットしましょう。

edit examplebuf
setlocal nobuflisted nomodifiable readonly

※これらはバッファにローカルなオプションなので:setlocalではなく通常の:setで設定しても問題ありません。
:edit+cmdオプションを与えればこのコマンドを1行で表せます。

edit +setlocal\ nobuflisted\ nomodifiable\ readonly   examplebuf

変更の予定があるバッファの場合

編集が禁止されたバッファでスクリプトがバッファの内容を変更するのなら、そのときに一時的にこれらのオプションを変更し、内容変更後に元に戻せばいいでしょう。

setlocal buflisted modifiable noreadonly
call setline(1, '==example==')
setlocal nobuflisted nomodifiable readonly

ユーザが自由に編集できるバッファをバッファリストに登録させたくない場合は、そのバッファを抜けるときに'nobuflisted'に設定しなおすバッファローカルなautocmdをそのバッファに設定しておきます。
また、たまたまそのバッファにいるときにVimを終了させようとしたときにもバッファリストから除外するようにVimLeavePreイベントのautocmdも設定します。

edit examplebuf
augroup example_local
  autocmd!
  autocmd BufLeave <buffer>   setlocal nobuflisted
  autocmd VimLeavePre <buffer>    setlocal nobuflisted
augroup END

需要があるか分かりませんが、現在Vimではbuflistedにしておきたいが、Vim終了時にはnobuflistedにして次回起動時のバッファに残させないときの設定です。この場合そのバッファのバッファ番号を何らかの形で記憶しておき、autocmd VimLeavePre \*でそれらのバッファにnobuflistedオプションを設定します。

augroup example_local
  autocmd!
  autocmd VimLeavePre *    call <SID>make_bufs_nobuflisted()
augroup END

let s:bufnrs = []
function! s:make_bufs_nobuflisted()
  for bufnr in s:bufnrs
    if buflisted(bufnr)
      call setbufvar(bufnr, "&bl", 0)
    endif
  endfor
endfunction
edit examplebuf
call add(s:bufnrs, bufnr('%'))

特別なバッファに設定するべき他のオプション

readonly, nomodifiable

説明済み

buftype

ファイルと関連がなく、書き込まれる予定のない仮想的なバッファにはset buftype=nofileを設定します。
buftype=nofileを設定すると:writeが禁止されます。しかし、バッファの編集変更自体は出来るので、それを禁止させたければ前述のnomodifiableも設定しましょう。

bufhidden

バッファの使い捨てという正確を強めたいときに利用します。 バッファがウィンドウに表示されなくなったときの挙動を指定するオプションですが、そのバッファを閉じたらバッファの内容を破棄させたいのならbufhidden=unload、削除や完全削除をしたいのならbufhidden=delete(←これはまだ:bでバッファ指定するなどしたらアクセスできる)やbufhidden=wipe(←完全に削除される)を使います。
例えばkien/ctrlp.vimbufhidden=unloadが利用されています。ctrlp.vimの作るバッファは刹那的な性格が強いですし、無駄なメモリも解放されるからでしょう。

活用例

例えばShougo/vimfiler.vimの作るバッファをバッファリストに残したくない時には.vimrcに次の設定を書きます。

autocmd FileType vimfiler  setlocal nobuflisted
  \ | autocmd BufLeave    <buffer>  setlocal nobuflisted
  \ | autocmd VimLeavePre <buffer>  setlocal nobuflisted

これでバッファを閉じたときにはバッファリストのサイクルから外れますし、次回起動時にvimfilerのバッファが残っているということもありません。