ftpluginのautocmdの場合、パターンマッチングまたは<buffer>を使用する必要がありますか?


14

TeXおよびMarkdownファイルのautocmdを使用して、ファイルを自動的に保存します。異常なし:

autocmd CursorHold *.tex,*.md w

ただし、これらのファイルのカスタム設定が増加したため、それらをftplugin/tex.vimおよびに分割しましたftplugin/markdown.vim

" ftplugin/tex.vim
autocmd CursorHold *.tex w
" ftplugin/markdown.vim
autocmd CursorHold *.md w

現在、これらのファイルは適切なファイルのみをソースとしているため、パターンマッチングは冗長です。どうやら、autocmdsはバッファローカルにすることができます。から:h autocmd-buffer-local

Buffer-local autocommands are attached to a specific buffer.  They are useful
if the buffer does not have a name and when the name does not match a specific
pattern.  But it also means they must be explicitly added to each buffer.

Instead of a pattern buffer-local autocommands use one of these forms:
        <buffer>        current buffer
        <buffer=99>     buffer number 99
        <buffer=abuf>   using <abuf> (only when executing autocommands)
                        <abuf>

それはそのような使用法を意図しているようです。今、両方ftplugin/tex.vimftplugin/markdown.vim持つことができます:

autocmd CursorHold <buffer> w

これは気にすることから私を節約できますので、私は本当に、ファイルタイプが正しい限り、実際の拡張子心配ないよ*.md*.markdown、その他どんな拡張マークダウンのために有効です。

これは<buffer>正しい使い方ですか?知っておくべき落とし穴はありますか?バッファをワイプして別のバッファを開くと、事態は面倒になります(数値が衝突しないことを願っていますが...)。


1
バッファを消去すると、バッファローカルのautocmdも消去されます。
タンブラー41

本当に@ Tumbler41。ヘルプでは、数段落下がっていると言われています。
ムル

1
正確にあなたが尋ねたものではありませんが、up(の略:update)はwautocmd よりも良いでしょう(不必要な書き込みを避けます)。
mMontu

@mMontuニース。それは、git履歴から調べていたファイルに対してautocmdがアクティブになったときの問題を解決します。バッファーは読み取り専用であり、w失敗しました。繰り返し。 :upその場合は何もしません。:)
ムル

気に入ってくれてうれしい:)ちなみに、「autowrite」オプションも便利です(動機に応じて、autocmdをドロップできます)。
mMontu

回答:


11

<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ます。

そのため、でいくつかの変更を行いBCursorHold起動されるまで数秒待つと、自動的に保存されます。しかし、戻ってA同じことをすると、バッファは保存されません。これは、最後にマークダウンバッファをロードしたときに、削除したものと追加したものの間に不均衡があったためです。追加したものよりも多く削除しました。

解決策は、特別なパターン<buffer>:autocmd!次のように渡すことにより、すべてのautocmdを削除するのではなく、現在のバッファーのautocmdのみを削除することです。

augroup my_markdown
    autocmd! CursorHold <buffer>
    autocmd CursorHold <buffer> update
augroup END

CursorHoldautocmdを削除する行のイベントに一致するようにスターに置き換えることができることに注意してください。

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回呼び出されます、毎回イベントの一つはCursorHoldCursorHoldICursorMovedCursorMovedI発射されます。

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

dircolorsfileを使用して構文プラグインを作成した場合~/.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他のプラグインのソースを妨げるのではなく、一部の設定の値に最後の言葉を付けます。


1
これをもっと一生懸命に賛成できたらと思います。
リッチ

3
@Rich私はあなたのためにこれをより強く支持しました。私の唯一の不満は、要約「tl; dr」の欠如です。テキストの詳細のページは、理解に不可欠ですが、私の老化した魂を苦しめます。ブロック内のautocmd!with の置換は、特に重要な落とし穴です。前もって強調されるべきでした。それにもかかわらず...これは、時間、労力、血まみれの涙の露骨に驚くべき投資です。autocmd! CursorHold <buffer>augroup
セシルカレー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.