<buffer>のこの使用法は正しいですか?
私はそれが正しいと思いますが、同じバッファをリロードするコマンドを実行するたびにautocmdが複製されないように、augroup内にラップし、後者をクリアする必要があります。
説明したように、特別なパターンを<buffer>
使用すると、ファイル内に実装された組み込みのファイルタイプ検出メカニズムに依存できます$VIMRUNTIME/filetype.vim
。
このファイルには、特定のバッファに正しいファイルタイプを設定するVimの組み込みautocmdがあります。たとえば、マークダウンの場合:
" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
ファイルタイププラグイン内で、インストールするすべてのautocmdに同じパターンをコピーできます。たとえば、カーソルが数秒間動かなかったときに自動的にバッファを保存するには:
au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md update
しかし、<buffer>
はるかに冗長です:
au CursorHold <buffer> update
さらに、いつか別の拡張機能が有効で、$VIMRUNTIME/filetype.vim
それを含めるように更新された場合、autocmdに通知されません。そして、ファイルタイププラグイン内のすべてのパターンを更新する必要があります。
バッファをワイプして別のバッファを開くと、事態は面倒になります(うまくいけば、数値は衝突しませんが...)。
よくわかりませんが、Vimがワイプされたバッファーのバッファー番号を再利用できるとは思いません。ヘルプから関連するセクションを見つけることができませんでしたが、vim.wikia.comからこの段落を見つけました:
いいえ。Vimは削除されたバッファーのバッファー番号を新しいバッファーに再利用しません。Vimは常に新しいバッファーに次の連番を割り当てます。
また、@ Tumbler41が説明したように、バッファを消去すると、そのautocmdは削除されます。から:h autocmd-buflocal
:
もちろん、バッファが消去されると、そのバッファローカルのオートコマンドも消えます。
自分で確認したい場合は、Vimの冗長レベルを6に上げることで確認できます。1つのコマンドに対して、:verbose
修飾子を使用して一時的に確認できます。したがって、マークダウンバッファー内で、次を実行できます。
:6verbose bwipe
次に、Vimのメッセージを確認すると:
:messages
次のような行が表示されます。
auto-removing autocommand: CursorHold <buffer=42>
42
マークダウンバッファの番号はどこにありましたか。
知っておくべき落とし穴はありますか?
私が落とし穴と考えて、特別なパターンを含む3つの状況があります<buffer>
。そのうちの2つは<buffer>
問題になる可能性があり、もう1つは解決策です。
落とし穴1
最初に、バッファローカルautocmdのaugroupsをクリアする方法に注意する必要があります。このスニペットに精通している必要があります。
augroup your_group_name
autocmd!
autocmd Event pattern command
augroup END
したがって、次のように、バッファローカルのautocmdに変更せずに使用したくなるかもしれません。
augroup my_markdown
autocmd!
autocmd CursorHold <buffer> update
augroup END
しかし、これには望ましくない効果があります。A
マークダウンバッファーを初めて読み込むときに呼び出します。そのautocmdは正しくインストールされます。次に、リロードするA
と、autocmdが(のためautocmd!
)削除され、再インストールされます。そのため、augroupはautocmdの重複を正しく防ぎます。
ここで、2番目のマークダウンバッファーを読み込むと仮定B
し、2番目のウィンドウで呼び出します。augroupのすべてのautocmdがクリアされます。つまり、のautocmdとのautocmd A
ですB
。次に、SINGLE autocmdがインストールされB
ます。
そのため、でいくつかの変更を行いB
、CursorHold
起動されるまで数秒待つと、自動的に保存されます。しかし、戻ってA
同じことをすると、バッファは保存されません。これは、最後にマークダウンバッファをロードしたときに、削除したものと追加したものの間に不均衡があったためです。追加したものよりも多く削除しました。
解決策は、特別なパターン<buffer>
を:autocmd!
次のように渡すことにより、すべてのautocmdを削除するのではなく、現在のバッファーのautocmdのみを削除することです。
augroup my_markdown
autocmd! CursorHold <buffer>
autocmd CursorHold <buffer> update
augroup END
CursorHold
autocmdを削除する行のイベントに一致するようにスターに置き換えることができることに注意してください。
augroup my_markdown
autocmd! * <buffer>
autocmd CursorHold <buffer> update
augroup END
この方法では、augroupをクリアするときに、autocmdがリッスンするすべてのイベントを指定する必要はありません。
落とし穴2
別の落とし穴がありますが、今回<buffer>
は問題ではなく、解決策です。
filetypeプラグインにローカルオプションを含めると、おそらく次のようになります。
setlocal option1=value
setlocal option2
これは、バッファローカルオプションでは期待どおりに機能しますが、ウィンドウローカルオプションでは常に機能するとは限りません。問題を説明するために、次の実験を試すことができます。ファイルを作成し~/.vim/after/ftdetect/potion.vim
、その中に書き込みます:
autocmd BufNewFile,BufRead *.pn setfiletype potion
このファイルはpotion
、拡張子がのファイルのファイルタイプを自動的に設定します.pn
。この特定の種類のファイルについては、Vimが自動的に行うため、augroup内にラップする必要はありません(参考文献を参照:h ftdetect
)。
中間ディレクトリがシステムに存在しない場合は、作成できます。
次に、filetypeプラグインを作成し~/.vim/after/ftplugin/potion.vim
、その中に書き込みます。
setlocal list
デフォルトでは、potion
ファイルでは、この設定によりタブ文字がとして表示され^I
、行末がとして表示され$
ます。
ここで、最小限のものを作成しvimrc
ます。内部/tmp/vimrc
書き込み:
filetype plugin on
...ファイルタイププラグインを有効にします。
また、ポーションファイル/tmp/pn.pn
、およびランダムファイルを作成します/tmp/file
。ポーションファイルに何かを書きます。
foo
bar
baz
ランダムファイルで、ポーションファイルへのパスを記述します/tmp/pn.pn
。
/tmp/pn.pn
ここで、最小限の初期化でVimを起動し、をソースしてvimrc
、両方のファイルを垂直ビューポートで開きます。
$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file
2つの垂直ビューポートが表示されます。左側のポーションファイルには行末にドル記号が表示され、右側のランダムファイルにはそれらがまったく表示されません。
ランダムファイルにフォーカスを置き、を押しgf
て、カーソルの下にパスがあるポーションファイルを表示します。右側のビューポートに同じポーションバッファーが表示されますが、今回は行末がドル記号で表示されません。そして入力すると:setlocal list?
、Vimは次のように答えるはずですnolist
。
イベントのチェーン全体:
BufRead event → set 'filetype' option → load filetype plugins
...が発生BufRead
しなかったのは、を押しgf
たときに最初のが発生しなかったためです。バッファはすでにロードされています。
setlocal list
ポーションファイルタイププラグイン内に追加したときに'list'
、ポーションバッファを表示しているウィンドウでオプションを有効にすると考えていた可能性があるため、予期しないように思われるかもしれません。
この問題は、この新しいpotion
ファイルタイプに固有のものではありません。markdown
ファイルでも体験できます。
'list'
オプションに固有のものでもありません。あなたのような、他のウィンドウローカルの設定でそれを体験することができ'conceallevel'
、'foldmethod'
、'foldexpr'
、'foldtitle'
、...
gf
コマンドに固有のものでもありません。現在のウィンドウに表示されるバッファを変更する可能性のある他のコマンドでそれを体験できます:グローバルマーク、C-o
(ウィンドウローカルジャンプリスト内で後方に移動)、、:b {buffer_number}
...
要約すると、ウィンドウローカルオプションは、次の場合にのみ正しく設定されます。
- 現在のVimセッション中にファイルが読み取られていない(
BufRead
起動する必要があるため)
- ファイルは、ウィンドウローカルオプションがすでに正しく設定されているウィンドウに表示されています
- 新しいウィンドウは、次のようなコマンドで作成されます
:split
(この場合、コマンドが実行されたウィンドウからウィンドウローカルオプションを継承する必要があります)
そうしないと、ウィンドウローカルオプションが正しく設定されない場合があります。
考えられる解決策は、ファイルタイププラグインから直接設定するのではなく、後者にインストールされているautocmdから設定することBufWinEnter
です。このイベントは、ウィンドウにバッファが表示されるたびに発生します。
したがって、たとえば、これを書く代わりに:
setlocal list
あなたはこれを書くでしょう:
augroup my_potion
au! * <buffer>
au BufWinEnter <buffer> setlocal list
augroup END
そして、ここで、あなたは再び特別なパターンを見つけます<buffer>
。
落とし穴3
バッファのファイルタイプを変更しても、autocmdは残ります。それらを削除したい場合は、設定b:undo_ftplugin
(を参照:h undo_ftplugin
)して、このコマンドをその中に含める必要があります:
exe 'au! my_markdown * <buffer>'
ただし、aucmd自体を削除しようとしないでください。autocmdを含むマークダウンバッファーがまだ残っている可能性があるためです。
FWIW、これは私が設定に使用しているUltiSnipsスニペットですb:undo_ftplugin
:
snippet undo "undo ftplugin settings" bm
" teardown {{{1
let b:undo_ftplugin = get(b:, 'undo_ftplugin', '')
\ .(empty(get(b:, 'undo_ftplugin', '')) ? '' : '|')
\ ."${1:
\ setl ${2:option}<}${3:
\ | exe '${4:n}unmap <buffer> ${5:lhs}'}${6:
\ | exe 'au! ${7:group_name} * <buffer>'}${8:
\ | unlet! b:${9:variable}}${10:
\ | delcommand ${11:Cmd}}
\ "
$0
endsnippet
そして、ここに私が持っている価値の例があります~/.vim/after/ftplugin/awk.vim
:
let b:undo_ftplugin = get(b:, 'undo_ftplugin', '')
\ .(empty(get(b:, 'undo_ftplugin', '')) ? '' : '|')
\ ."
\ setl cms< cocu< cole< fdm< fdt< tw<
\| exe 'nunmap <buffer> K'
\| exe 'au! my_awk * <buffer>'
\| exe 'au! my_awk_format * <buffer>'
\ "
補足として、<buffer>
Vimのデフォルトファイルで特別なパターンが使用されているすべての行を検索したとき、なぜあなたが質問をしたのか理解しています。
:vim /au\%[tocmd!].\{-}<buffer>/ $VIMRUNTIME/**/*
一致するものは9個しか見つかりませんでした(多かれ少なかれ、Vimバージョン8.0を使用していますが、パッチは最大で134
)。そして、9つのマッチのうち、7つはドキュメントにあり、実際にソースされているのは2つだけです。これらは$ VIMRUNTIME / syntax / dircolors.vimにあります。
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
それが問題を引き起こすことができるかどうかはわからないが、彼らはあなたがファイルタイプであるバッファリロードするたびに意味augroup、内部ではありませんdircolors
(という名前のファイルを編集した場合、それが起こると.dircolors
、.dir_colors
またはそのパスを終了すると/etc/DIR_COLORS
、)構文プラグインは、新しいバッファローカルautocmdを追加します。
次のように確認できます。
$ vim ~/.dir_colors
:au * <buffer>
最後のコマンドはこれを表示するはずです:
CursorHold
<buffer=1>
call s:reset_colors()
CursorHoldI
<buffer=1>
call s:reset_colors()
CursorMoved
<buffer=1>
call s:preview_color('.')
CursorMovedI
<buffer=1>
call s:preview_color('.')
ここで、バッファをリロードし、現在のバッファのバッファローカルautocmdをもう一度尋ねます。
:e
:au * <buffer>
今回は、以下が表示されます。
CursorHold
<buffer=1>
call s:reset_colors()
call s:reset_colors()
CursorHoldI
<buffer=1>
call s:reset_colors()
call s:reset_colors()
CursorMoved
<buffer=1>
call s:preview_color('.')
call s:preview_color('.')
CursorMovedI
<buffer=1>
call s:preview_color('.')
call s:preview_color('.')
すべてのファイルの再ロード、後s:reset_colors()
とs:preview_color('.')
もう1回呼び出されます、毎回イベントの一つはCursorHold
、CursorHoldI
、CursorMoved
、CursorMovedI
発射されます。
dircolors
ファイルを何度もリロードした後でも、顕著な減速やVimの予期しない動作が見られなかったため、おそらく大きな問題ではありません。
問題がある場合は、構文プラグインのメンテナーに連絡することができますが、その間にautocmdの重複を防ぎたい場合はdircolors
、fileを使用してファイル用の独自の構文プラグインを作成できます~/.vim/syntax/dircolors.vim
。その中に、元の構文プラグインのコンテンツをインポートします。
$ vim ~/.vim/syntax/dircolors.vim
:r $VIMRUNTIME/syntax/dircolors.vim
次に、後者では、autocmdsをaugroup内にラップするだけで、クリアします。したがって、次の行を置き換えます。
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
...これらのものと:
augroup my_dircolors_syntax
autocmd! * <buffer>
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
augroup END
dircolors
fileを使用して構文プラグインを作成した場合~/.vim/after/syntax/dircolors.vim
、デフォルトの構文プラグインが以前にソースされるため、機能しないことに注意してください。を使用する~/.vim/syntax/dircolors.vim
と、構文プラグインはデフォルトの前にソースされ、buffer-local変数を設定しますb:current_syntax
。これにより、このガードが含まれているため、デフォルトの構文プラグインがソースされなくなります。
if exists("b:current_syntax")
finish
endif
一般的なルールは次のとおりです:~/.vim/ftplugin
および~/.vim/syntax
ディレクトリを使用してカスタムファイルタイプ/構文プラグインを作成し、ランタイムパス内の次のプラグイン(同じファイルタイプ用)がソースされることを防ぎます(デフォルトのものを含む)。また、、を使用して~/.vim/after/ftplugin
、~/.vim/after/syntax
他のプラグインのソースを妨げるのではなく、一部の設定の値に最後の言葉を付けます。