Questo uso di <buffer> è corretto?
Penso che sia corretto, ma devi solo avvolgerlo all'interno di un augroup e cancellare quest'ultimo, per assicurarti che autocmd non venga duplicato ogni volta che esegui un comando che ricarica lo stesso buffer.
Come spiegato, il modello speciale <buffer>consente di fare affidamento sul meccanismo di rilevamento del tipo di file incorporato, implementato all'interno del file $VIMRUNTIME/filetype.vim.
In questo file, puoi trovare gli autocmds integrati di Vim che sono responsabili dell'impostazione del tipo di file corretto per ogni dato buffer. Ad esempio, per il markdown:
" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
All'interno del plug-in del tipo di file, è possibile copiare gli stessi schemi per ogni autocmd che si installa. Ad esempio, per salvare automaticamente il buffer quando il cursore non si è mosso per alcuni secondi:
au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md update
Ma <buffer>è molto meno prolisso:
au CursorHold <buffer> update
Inoltre, se un giorno un altro interno è valido e $VIMRUNTIME/filetype.vimviene aggiornato per includerlo, i tuoi autocmds non verranno informati. E dovrai aggiornare tutti i loro pattern all'interno dei tuoi plugin di tipo file.
Le cose diventeranno confuse se pulisco un buffer e ne apro un altro (speriamo che i numeri non si scontrino, ma ...)?
Non sono sicuro ma non credo che Vim possa riutilizzare il numero di buffer di un buffer cancellato. Non sono riuscito a trovare la sezione pertinente dall'aiuto, ma ho trovato questo paragrafo da vim.wikia.com :
No. Vim non riutilizzerà il numero di buffer di un buffer eliminato per un nuovo buffer. Vim assegnerà sempre il numero sequenziale successivo per un nuovo buffer.
Inoltre, come ha spiegato @ Tumbler41 , quando si cancella un buffer, i suoi autocmds vengono rimossi. Da :h autocmd-buflocal:
Quando un buffer viene cancellato, anche i suoi autocomandi locali del buffer scompaiono, ovviamente.
Se vuoi controllare te stesso, puoi farlo aumentando il livello di verbosità di Vim a 6. Puoi farlo temporaneamente, solo per un comando, usando il :verbosemodificatore. Quindi, all'interno del buffer di markdown, è possibile eseguire:
:6verbose bwipe
Quindi, se controlli i messaggi di Vim:
:messages
Dovresti vedere una linea simile a questa:
auto-removing autocommand: CursorHold <buffer=42>
Dov'era 42il numero del buffer di markdown.
Ci sono delle insidie di cui dovrei essere a conoscenza?
Ci sono 3 situazioni che considererei insidie e che coinvolgono il modello speciale <buffer>. In due di essi, <buffer>potrebbe essere un problema, nell'altro è una soluzione.
Pitfall 1
Innanzitutto, dovresti stare attento al modo in cui cancelli i gruppi di file degli autocmds buffer-locali. Devi conoscere questo frammento:
augroup your_group_name
autocmd!
autocmd Event pattern command
augroup END
Quindi, potresti essere tentato di usarlo per i tuoi autocmds buffer-locali, non modificati, in questo modo:
augroup my_markdown
autocmd!
autocmd CursorHold <buffer> update
augroup END
Ma questo avrà un effetto indesiderato. La prima volta che carichi un buffer Amarkdown, chiamiamolo , il suo autocmd verrà installato correttamente. Quindi, quando ricarichi A, l'autocd verrà eliminato (a causa di autocmd!) e reinstallato. Pertanto, l'augroup impedirà correttamente la duplicazione di autocmd.
Supponiamo ora di caricare un secondo buffer di markdown, chiamiamolo B, in una seconda finestra. TUTTI gli autocmd di augroup verranno cancellati: questo è autocmd di Ae quello di B. Quindi, verrà installato un SINGOLO autocmd per B.
Quindi, quando effettui qualche modifica Be attendi qualche secondo per CursorHoldessere licenziato, verrà automaticamente salvato. Ma se torni a Afare la stessa cosa, il buffer non verrà salvato. Questo perché l'ultima volta che hai caricato un buffer markdown, c'era uno squilibrio tra ciò che hai rimosso e ciò che hai aggiunto. Hai rimosso più di quello che hai aggiunto.
La soluzione è quella di non rimuovere TUTTI gli autocmds, ma solo quelli del buffer corrente, passando lo schema speciale <buffer>a :autocmd!:
augroup my_markdown
autocmd! CursorHold <buffer>
autocmd CursorHold <buffer> update
augroup END
Si noti che è possibile sostituire CursorHoldcon una stella per abbinare qualsiasi evento nella riga che rimuove autocmds:
augroup my_markdown
autocmd! * <buffer>
autocmd CursorHold <buffer> update
augroup END
In questo modo, non è necessario specificare tutti gli eventi a cui i vostri autocmds stanno ascoltando quando si desidera cancellare l'augroup.
Pitfall 2
C'è un'altra trappola, ma questa volta <buffer>non è il problema, è la soluzione.
Quando includi un'opzione locale in un plug-in di tipo di file, probabilmente lo fai in questo modo:
setlocal option1=value
setlocal option2
Funzionerà come previsto per le opzioni buffer-local, ma non sempre per quelle window-local. Per illustrare il problema, puoi provare il seguente esperimento. Crea il file ~/.vim/after/ftdetect/potion.vime al suo interno scrivi:
autocmd BufNewFile,BufRead *.pn setfiletype potion
Questo file imposterà automaticamente il tipo di file potionper qualsiasi file la cui estensione è .pn. Non è necessario avvolgerlo all'interno di un augroup perché, per questo particolare tipo di file, Vim lo farà automaticamente (vedi :h ftdetect).
Se le directory intermedie non esistono sul tuo sistema, puoi crearle.
Quindi, crea il plugin filetype ~/.vim/after/ftplugin/potion.vime al suo interno scrivi:
setlocal list
Per impostazione predefinita, in un potionfile, questa impostazione farà apparire i caratteri della scheda come ^Ie la fine delle righe come $.
Ora crea un minimo vimrc; dentro /tmp/vimrcscrivi:
filetype plugin on
... per abilitare i plugin del tipo di file.
Inoltre, crea un file pozione /tmp/pn.pne un file casuale /tmp/file. Nel file di pozioni, scrivi qualcosa:
foo
bar
baz
Nel file casuale, scrivi il percorso nel file pozione /tmp/pn.pn:
/tmp/pn.pn
Ora, avvia Vim con un minimo di inizializzazioni, procurando semplicemente il vimrc, e apri entrambi i file nelle finestre verticali:
$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file
Dovresti vedere 2 finestre verticali. Il file di pozione a sinistra mostra la fine delle linee con segni di dollaro, il file casuale a destra non le mostra affatto.
Dai lo stato attivo al file casuale e premi gfper visualizzare il file di pozione il cui percorso è sotto il cursore. Ora vedi lo stesso buffer di pozioni nella vista corretta, ma questa volta la fine delle linee non viene visualizzata con i simboli del dollaro. E se digiti :setlocal list?, Vim dovrebbe rispondere con nolist:

L'intera catena di eventi:
BufRead event → set 'filetype' option → load filetype plugins
... non si è verificato, perché il primo di essi BufRead, non si è verificato quando hai premuto gf. Il buffer era già caricato.
Può sembrare inaspettato, perché quando hai aggiunto setlocal listil plug-in del tipo di file di pozioni, potresti aver pensato che avrebbe abilitato l' 'list'opzione in qualsiasi finestra che mostra un buffer di pozioni.
Il problema non è specifico per questo nuovo tipo di potionfile. Puoi provarlo anche con un markdownfile.
Non è nemmeno specifico per l' 'list'opzione. Si può sperimentare con altre impostazioni della finestra locale, come 'conceallevel', 'foldmethod', 'foldexpr', 'foldtitle', ...
Non è nemmeno specifico per il gfcomando. È possibile sperimentarlo con altri comandi che possono modificare il buffer visualizzato nella finestra corrente: segno globale, C-o(spostarsi indietro nella jumplist locale della finestra) :b {buffer_number}, ...
Per riassumere, le opzioni locali della finestra saranno impostate correttamente, se e solo se:
- il file non è stato letto durante l'attuale sessione di Vim (perché
BufReaddovrà essere attivato)
- il file viene visualizzato in una finestra in cui le opzioni locali della finestra erano già impostate correttamente
- la nuova finestra viene creata con un comando come
:split(in questo caso, dovrebbe ereditare le opzioni finestra locale dalla finestra in cui è stato eseguito il comando)
Altrimenti, le opzioni locali della finestra potrebbero non essere impostate correttamente.
Una possibile soluzione sarebbe quella di impostarli non direttamente da un plug-in di tipo di file, ma da un autocmd installato in quest'ultimo, che ascolterebbe BufWinEnter. Questo evento deve essere generato ogni volta che viene visualizzato un buffer in una finestra.
Quindi, ad esempio, invece di scrivere questo:
setlocal list
Scriveresti questo:
augroup my_potion
au! * <buffer>
au BufWinEnter <buffer> setlocal list
augroup END
E qui trovi di nuovo lo schema speciale <buffer>.

Pitfall 3
Se si modifica il tipo di file del buffer, rimarranno gli autocmds. Se vuoi rimuoverli, devi configurare b:undo_ftplugin(vedi :h undo_ftplugin) e includere questo comando al suo interno:
exe 'au! my_markdown * <buffer>'
Tuttavia, non tentare di rimuovere l'ugroup stesso, perché potrebbero esserci ancora alcuni buffer di markdown che contengono autocmds al suo interno.
FWIW, questo è lo snippet UltiSnips che sto usando per impostare 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
Ed ecco un esempio di valore che ho in ~/.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>'
\ "
Come nota a margine, capisco perché hai posto la domanda, perché quando ho cercato tutte le linee in cui è <buffer>stato utilizzato lo schema speciale nei file predefiniti di Vim:
:vim /au\%[tocmd!].\{-}<buffer>/ $VIMRUNTIME/**/*
Ho trovato solo 9 corrispondenze (potresti trovare più o meno, sto usando Vim versione 8.0, con patch fino a 134). E tra le 9 partite, 7 sono nella documentazione, solo 2 sono effettivamente di provenienza. Dovresti trovarli in $ VIMRUNTIME / syntax / dircolors.vim :
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
Non so se può causare un problema, ma non sono all'interno di un augroup, il che significa che ogni volta che si ricarica un buffer il cui tipo di file è dircolors(succede se si modifica un file di nome .dircolors, .dir_colorso le cui estremità percorso con /etc/DIR_COLORS), il plugin di sintassi aggiungerà un nuovo autocmd buffer-local.
Puoi verificarlo in questo modo:
$ vim ~/.dir_colors
:au * <buffer>
L'ultimo comando dovrebbe visualizzare questo:
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('.')
Ora ricaricare il buffer e chiedere di nuovo quali sono gli autocmds buffer-locali per il buffer corrente:
:e
:au * <buffer>
Questa volta vedrai:
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('.')
Dopo ogni ricarico del file, s:reset_colors()e s:preview_color('.')si chiamerà una volta in più, ogni volta che uno degli eventi CursorHold, CursorHoldI, CursorMoved, CursorMovedIviene licenziato.
Probabilmente non è un grosso problema, perché anche dopo aver ricaricato un dircolorsfile più volte, non ho visto un rallentamento evidente o un comportamento inaspettato da Vim.
Se si tratta di un problema per te, puoi contattare il manutentore del plug-in di sintassi, ma nel frattempo, se vuoi impedire la duplicazione di autocmds, puoi creare il tuo plug-in di sintassi per i dircolorsfile, utilizzando il file ~/.vim/syntax/dircolors.vim. Al suo interno verrai importato il contenuto del plugin di sintassi originale:
$ vim ~/.vim/syntax/dircolors.vim
:r $VIMRUNTIME/syntax/dircolors.vim
Quindi, in quest'ultimo caso, avresti semplicemente avvolto gli autocmds all'interno di un augroup che elimineresti. Quindi, sostituiresti queste righe:
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
... con questi:
augroup my_dircolors_syntax
autocmd! * <buffer>
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
augroup END
Nota che se hai creato il tuo dircolorsplugin di sintassi con il file ~/.vim/after/syntax/dircolors.vim, non funzionerebbe, perché il plugin di sintassi predefinito sarebbe stato fornito in precedenza. Usando ~/.vim/syntax/dircolors.vim, il tuo plug-in di sintassi verrà fornito prima di quello predefinito e imposterà la variabile buffer-local b:current_syntax, che impedirà di ottenere il plug-in di sintassi predefinito perché contiene questo guard:
if exists("b:current_syntax")
finish
endif
La regola generale sembra essere: utilizzare le directory ~/.vim/ftplugine ~/.vim/syntaxper creare un plug-in di tipo file / sintassi personalizzato e impedire che il plug-in successivo (per lo stesso tipo di file) nel percorso di runtime venga fornito (inclusi quelli predefiniti). E usa ~/.vim/after/ftplugin, ~/.vim/after/syntaxnon per impedire la provenienza di altri plugin, ma solo per avere l'ultima parola sul valore di alcune impostazioni.