Cette utilisation de <buffer> est-elle correcte?
Je pense que c'est correct, mais vous avez juste besoin de l'envelopper dans un augroup, et effacer ce dernier, pour vous assurer que l'autocmd ne sera pas dupliqué à chaque fois que vous exécutez une commande qui recharge le même tampon.
Comme vous l'avez expliqué, le modèle spécial <buffer>
vous permet de vous fier au mécanisme de détection de type de fichier intégré, implémenté à l'intérieur du fichier $VIMRUNTIME/filetype.vim
.
Dans ce fichier, vous pouvez trouver les autocmds intégrés de Vim qui sont responsables de la définition du type de fichier correct pour tout tampon donné. Par exemple, pour le démarque:
" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
Dans votre plugin de type de fichier, vous pouvez copier les mêmes modèles pour chaque autocmd que vous installez. Par exemple, pour enregistrer automatiquement le tampon lorsque votre curseur n'a pas bougé pendant quelques secondes:
au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md update
Mais <buffer>
est beaucoup moins verbeux:
au CursorHold <buffer> update
De plus, si un jour une autre extension est valide et $VIMRUNTIME/filetype.vim
est mise à jour pour l'inclure, vos autocmds ne seront pas informés. Et vous devrez mettre à jour tous leurs modèles dans vos plugins de type de fichier.
Est-ce que les choses vont mal tourner si j'essuie un tampon et j'ouvre un autre (j'espère que les chiffres ne se heurteront pas, mais…)?
Je ne suis pas sûr mais je ne pense pas que Vim puisse réutiliser le numéro de tampon d'un tampon effacé. Je n'ai pas trouvé la section pertinente de l'aide, mais j'ai trouvé ce paragraphe sur vim.wikia.com :
Non. Vim ne réutilisera pas le numéro de tampon d'un tampon supprimé pour un nouveau tampon. Vim attribuera toujours le prochain numéro séquentiel pour un nouveau tampon.
De plus, comme @ Tumbler41 l'a expliqué, lorsque vous effacez un tampon, ses autocmds sont supprimés. De :h autocmd-buflocal
:
Lorsqu'un tampon est effacé, ses autocommandes de tampon local ont également disparu, bien sûr.
Si vous voulez vous vérifier, vous pouvez le faire en augmentant le niveau de verbosité de Vim à 6. Vous pouvez le faire temporairement, juste pour une commande, en utilisant le :verbose
modificateur. Ainsi, à l'intérieur de votre tampon de démarque, vous pouvez exécuter:
:6verbose bwipe
Ensuite, si vous consultez les messages de Vim:
:messages
Vous devriez voir une ligne ressemblant à ceci:
auto-removing autocommand: CursorHold <buffer=42>
Où 42
était le numéro de votre tampon de démarque.
Y a-t-il des pièges dont je devrais être conscient?
Il y a 3 situations que je considérerais comme des pièges et qui impliquent le schéma spécial <buffer>
. Dans deux d'entre eux, <buffer>
peut être un problème, dans l'autre, c'est une solution.
Piège 1
Tout d'abord, vous devez être prudent avec la façon dont vous effacez les augroups de vos autocmds tampon-local. Vous devez être familiarisé avec cet extrait:
augroup your_group_name
autocmd!
autocmd Event pattern command
augroup END
Donc, vous pourriez être tenté de l'utiliser pour vos autocmds tampon-local, non modifié, comme ceci:
augroup my_markdown
autocmd!
autocmd CursorHold <buffer> update
augroup END
Mais cela aura un effet indésirable. La première fois que vous chargez un tampon de démarque, appelons-le A
, son autocmd sera correctement installé. Ensuite, lorsque vous rechargerez A
, l'autocmd sera supprimé (à cause de autocmd!
) et réinstallé. Ainsi, l'augroup empêchera correctement la duplication de l'autocmd.
Supposons maintenant que vous chargiez un 2e tampon de démarque, appelons-le B
, dans une 2e fenêtre. TOUS les autocmds du augroup seront effacés: c'est l'autocmd de A
et celui de B
. Ensuite, un seul autocmd sera installé pour B
.
Ainsi, lorsque vous apportez des modifications B
et attendez quelques secondes pour CursorHold
être renvoyé, il sera automatiquement enregistré. Mais si vous revenez à A
et faites la même chose, le tampon ne sera pas enregistré. En effet, la dernière fois que vous avez chargé un tampon de démarque, il y avait un déséquilibre entre ce que vous avez supprimé et ce que vous avez ajouté. Vous avez supprimé plus que ce que vous avez ajouté.
La solution est de ne pas supprimer TOUS autocommandes, mais seulement ceux du tampon courant, en passant le motif spécial <buffer>
à :autocmd!
:
augroup my_markdown
autocmd! CursorHold <buffer>
autocmd CursorHold <buffer> update
augroup END
Notez que vous pouvez remplacer CursorHold
par une étoile pour correspondre à n'importe quel événement de la ligne qui supprime les autocmds:
augroup my_markdown
autocmd! * <buffer>
autocmd CursorHold <buffer> update
augroup END
De cette façon, vous n'avez pas besoin de spécifier tous les événements que vos autocmds écoutent lorsque vous souhaitez effacer le groupe.
Piège 2
Il y a un autre écueil, mais cette fois <buffer>
- ci ce n'est pas le problème, c'est la solution.
Lorsque vous incluez une option locale dans un plugin de type de fichier, vous le faites probablement comme ceci:
setlocal option1=value
setlocal option2
Cela fonctionnera comme prévu pour les options locales du tampon, mais pas toujours pour les options locales de la fenêtre. Pour illustrer le problème, vous pouvez essayer l'expérience suivante. Créez le fichier ~/.vim/after/ftdetect/potion.vim
et écrivez à l'intérieur:
autocmd BufNewFile,BufRead *.pn setfiletype potion
Ce fichier définira automatiquement le type potion
de fichier pour tout fichier dont l'extension est .pn
. Vous n'avez pas besoin de l'envelopper dans un augroup car, pour ce type de fichier particulier, Vim le fera automatiquement (voir :h ftdetect
).
Si les répertoires intermédiaires n'existent pas sur votre système, vous pouvez les créer.
Ensuite, créez le plugin de type de fichier ~/.vim/after/ftplugin/potion.vim
, et à l'intérieur, écrivez:
setlocal list
Par défaut, dans un potion
fichier, ce paramètre entraînera l'affichage des caractères de tabulation en tant que ^I
et la fin des lignes en tant que $
.
Maintenant, créez un minimum vimrc
; /tmp/vimrc
écrire à l' intérieur :
filetype plugin on
... pour activer les plugins de type de fichier.
Créez également un fichier de potion /tmp/pn.pn
et un fichier aléatoire /tmp/file
. Dans le fichier de potion, écrivez quelque chose:
foo
bar
baz
Dans le fichier aléatoire, écrivez le chemin d'accès au fichier de potion /tmp/pn.pn
:
/tmp/pn.pn
Maintenant, démarrez Vim avec un minimum d'initialisations, juste en recherchant le vimrc
, et ouvrez les deux fichiers dans des fenêtres verticales:
$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file
Vous devriez voir 2 fenêtres verticales. Le fichier de potion à gauche affiche la fin des lignes avec des signes dollar, le fichier aléatoire à droite ne les affiche pas du tout.
Donnez le focus au fichier aléatoire et appuyez sur gf
pour afficher le fichier de potion dont le chemin se trouve sous le curseur. Vous voyez maintenant le même tampon de potion dans la fenêtre de droite, mais cette fois, la fin des lignes ne s'affiche pas avec des signes dollar. Et si vous tapez :setlocal list?
, Vim devrait répondre avec nolist
:
Toute la chaîne d'événements:
BufRead event → set 'filetype' option → load filetype plugins
... ne s'est pas produit, car le premier d'entre eux BufRead
, ne s'est pas produit lorsque vous avez appuyé gf
. Le tampon était déjà chargé.
Cela peut sembler inattendu, car lorsque vous avez ajouté à l' setlocal list
intérieur de votre plugin de type de fichier de potion, vous avez peut-être pensé qu'il activerait l' 'list'
option dans n'importe quelle fenêtre affichant un tampon de potion.
Le problème n'est pas spécifique à ce nouveau type de potion
fichier. Vous pouvez également en faire l'expérience avec un markdown
fichier.
Ce n'est pas spécifique à l' 'list'
option non plus. Vous pouvez faire l' expérience avec d' autres paramètres de la fenêtre locale, comme 'conceallevel'
, 'foldmethod'
, 'foldexpr'
, 'foldtitle'
, ...
Ce n'est pas spécifique à la gf
commande non plus. Vous pouvez en faire l'expérience avec d'autres commandes qui peuvent changer le tampon affiché dans la fenêtre courante: marque globale, C-o
(reculer dans la liste des fenêtres locale),, :b {buffer_number}
...
Pour résumer, les options locales de la fenêtre seront correctement définies, si et seulement si:
- le fichier n'a pas été lu pendant la session Vim en cours (car il
BufRead
devra être viré)
- le fichier est affiché dans une fenêtre où les options locales de la fenêtre étaient déjà correctement définies
- la nouvelle fenêtre est créée avec une commande telle que
:split
(dans ce cas, elle doit hériter des options window-local de la fenêtre où la commande a été exécutée)
Sinon, les options locales de la fenêtre risquent de ne pas être correctement définies.
Une solution possible serait de les définir non pas directement à partir d'un plugin de type de fichier, mais à partir d'un autocmd installé dans ce dernier, qui l'écouterait BufWinEnter
. Cet événement doit être déclenché chaque fois qu'un tampon est affiché dans une fenêtre.
Ainsi, par exemple, au lieu d'écrire ceci:
setlocal list
Vous écririez ceci:
augroup my_potion
au! * <buffer>
au BufWinEnter <buffer> setlocal list
augroup END
Et ici, vous retrouvez le motif spécial <buffer>
.
Piège 3
Si vous modifiez le type de fichier de votre tampon, les autocmds resteront. Si vous souhaitez les supprimer, vous devez configurer b:undo_ftplugin
(voir :h undo_ftplugin
) et y inclure cette commande:
exe 'au! my_markdown * <buffer>'
Cependant, n'essayez pas de supprimer l'augroup lui-même, car il pourrait toujours y avoir des tampons de démarque contenant des autocmds.
FWIW, voici l'extrait UltiSnips que j'utilise pour définir 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
Et voici un exemple de valeur que j'ai dans ~/.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>'
\ "
En remarque, je comprends pourquoi vous avez posé la question, car lorsque j'ai cherché toutes les lignes où le motif spécial <buffer>
était utilisé dans les fichiers par défaut de Vim:
:vim /au\%[tocmd!].\{-}<buffer>/ $VIMRUNTIME/**/*
Je n'ai trouvé que 9 correspondances (vous pouvez en trouver plus ou moins, j'utilise la version 8.0 de Vim, avec des correctifs jusqu'à 134
). Et parmi les 9 correspondances, 7 sont dans la documentation, seulement 2 sont réellement originaires. Vous devriez les trouver dans $ VIMRUNTIME / syntax / dircolors.vim :
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
Je ne sais pas si cela peut causer un problème, mais ils ne sont pas à l' intérieur d' un augroup, ce qui signifie que chaque fois que vous rechargerez un tampon dont le type de fichier est dircolors
(il arrive si vous modifiez un fichier nommé .dircolors
, .dir_colors
ou dont les extrémités de chemin avec /etc/DIR_COLORS
), le plugin de syntaxe ajoutera un nouvel autocmd tampon local.
Vous pouvez le vérifier comme ceci:
$ vim ~/.dir_colors
:au * <buffer>
La dernière commande devrait afficher ceci:
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('.')
Maintenant, rechargez le tampon et demandez à nouveau quels sont les autocmds tampon-local pour le tampon actuel:
:e
:au * <buffer>
Cette fois, vous verrez:
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('.')
Après chaque rechargement du fichier, s:reset_colors()
et s:preview_color('.')
sera appelé un temps supplémentaire, chaque fois que l' un des cas CursorHold
, CursorHoldI
, CursorMoved
, CursorMovedI
est tiré.
Ce n'est probablement pas un gros problème, car même après avoir rechargé un dircolors
fichier plusieurs fois, je n'ai pas vu de ralentissement notable ou de comportement inattendu de Vim.
Si c'est un problème pour vous, vous pouvez contacter le responsable du plugin de syntaxe, mais en attendant, si vous souhaitez empêcher la duplication des autocmds, vous pouvez créer votre propre plugin de syntaxe pour les dircolors
fichiers, en utilisant le fichier ~/.vim/syntax/dircolors.vim
. À l'intérieur, vous importeriez le contenu du plugin de syntaxe d'origine:
$ vim ~/.vim/syntax/dircolors.vim
:r $VIMRUNTIME/syntax/dircolors.vim
Ensuite, dans ce dernier, vous emballeriez simplement les autocmds dans un augroup que vous effaceriez. Donc, vous remplaceriez ces lignes:
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
... avec ceux-ci:
augroup my_dircolors_syntax
autocmd! * <buffer>
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
augroup END
Notez que si vous avez créé votre dircolors
plug-in de syntaxe avec le fichier ~/.vim/after/syntax/dircolors.vim
, cela ne fonctionnerait pas, car le plug-in de syntaxe par défaut proviendrait auparavant. En utilisant ~/.vim/syntax/dircolors.vim
, votre plugin de syntaxe sera sourced avant celui par défaut, et il définira la variable buffer-local b:current_syntax
, ce qui empêchera le plugin de syntaxe par défaut d'être sourced car il contient cette garde:
if exists("b:current_syntax")
finish
endif
La règle générale semble être: utiliser les répertoires ~/.vim/ftplugin
et ~/.vim/syntax
pour créer un plugin de type / syntaxe de fichier personnalisé et empêcher que le prochain plugin (pour le même type de fichier) dans le chemin d'exécution soit sourcé (y compris ceux par défaut). Et l' utilisation ~/.vim/after/ftplugin
, ~/.vim/after/syntax
non pas pour empêcher les autres plug - ins d'être source, mais juste pour avoir le dernier mot sur la valeur de certains paramètres.