Existe-t-il un moyen d'accéder aux événements AND dans l'autocmd?

21

Je voudrais déclencher un autocmd sur deux événements, mais pas de la manière habituelle, c'est-à-dire que si l'un des événements s'est produit, déclencher un autocmd. Je veux le déclencher si les deux événements se sont produits.

Par exemple:
la façon habituelle de le faire

autocmd BufWrite,BufRead *.c *.py *.h :call StripTrailingWhitespaces()

Ce code appellera StripTrailingWhiteSpaces () sur BufWrite ou BufRead

Je voudrais faire quelque chose comme:

autocmd Filetype c,cpp,python AND BufWrite :call StripTrailingWhiteSpaces()

En d'autres termes, déclencher un autcmdlorsque le type de fichier est l'un de c, cpp, python et l'écriture sur ce tampon se produit.

Toute aide est appréciée.

flashburn
la source

Réponses:

14

Une commande de commande automatique est exécutée lorsqu'un événement se produit. Vous souhaitez qu'une commande soit exécutée après qu'une séquence d'événements s'est produite. Une façon de le faire est la suivante:

autocmd FileType c,cpp,python
    \ autocmd BufWritePre <buffer> call StripTrailingWhiteSpaces()

Le <buffer>modèle provoque le déclenchement de l'autocommande lorsque le tampon actuel est écrit. Voir

:help autocmd-buflocal

Mise à jour

La solution ci-dessus est assez simple et présente des défauts qui ont été discutés dans les commentaires. Voici une solution plus complète qui corrige certains de ces défauts. Il place les commandes automatiques dans un groupe et supprime la commande automatique BufWritePre, le cas échéant, avant d'en créer une nouvelle. Il crée toujours une autocommande par tampon, mais une seule.

augroup TrailSpace
    autocmd FileType c,cpp,python
        \ autocmd! TrailSpace BufWritePost <buffer> call SkipTrailingWhiteSpaces()
augroup END

Une autre solution, similaire à la réponse publiée par lcd047, maintenant supprimée, consiste à reconnaître que lorsque l'événement FileType se produit, l'option «filetype» est définie. Vous pouvez ensuite conditionner la réponse à l'événement BufWritePost sur la valeur de "type de fichier", comme dans l'exemple suivant. Il a l'avantage sur les autres solutions qu'une seule autocommande est créée.

autocmd BufWritePre * if count(['c','cpp','python'],&filetype)
    \ | call SkipTrailingWhiteSpaces()
    \ | endif
garyjohn
la source
Que faire si je veux l'exécuter sur tous les fichiers actuellement ouverts, c'est-à-dire que j'exécute: wa?
flashburn
Si les fichiers ont été ouverts avec le type de fichier correct, l' FileTypeautocmd dans la réponse aurait déjà configuré le deuxième autocmd ( BufWritePre) pour se déclencher lorsque vous les enregistrez.
VanLaser
1
L' FileTypeautocmd ci-dessus se déclenchera pour chaque fichier que vous ouvrirez avec le type de fichier correct et configurera un événement local tampon pour chacun de ces fichiers. Donc, si vous exécutez :wa, vim exécutera les événements enregistrés pour chaque tampon, avant d'enregistrer dans un fichier.
VanLaser
1
Donc, si vous ouvrez 5 fichiers Python, vous aurez 5 autocmds au lieu d'un seul, tout en écriture. Ensuite, si, par exemple, 3 de ces fichiers sont masqués, puis affichés à nouveau, FileTypesont redéclenchés de sorte que vous obtenez 3 autocmds supplémentaires , également en écriture. C'est génial, je me demande pourquoi je n'ai pas trouvé cette solution. :)
lcd047
1
La performance n'est pas un problème. L'exécution de la fonction stripTrailingWhiteSpaces()plusieurs fois sur le même fichier peut cependant avoir des conséquences inattendues. En outre, plus autocmdvous avez de s pour le même événement pour le même fichier, plus vous risquez de rencontrer des conditions de course vraiment réelles. Essayez de chercher dans les archives vim_dev pour vous faire une idée. Là encore, qu'est-ce que je sais, cela pourrait bien fonctionner pour vous, non?
lcd047
4

Plus généralement, si vous ne savez pas quel événement se produira en premier, vous pouvez utiliser un assistant pour suivre le moment où chacun se déclenche et exécuter votre commande uniquement lorsque le dernier se déclenche:

function StripTrailingWhiteSpacesIfReady(event) abort
  if !exists('b:events_for_whitespace')
    let b:events_for_whitespace = {}
  endif
  let b:events_for_whitespace[a:event] = 1
  if has_key(b:events_for_whitespace, 'FileType') && has_key(b:events_for_whitespace, 'Buf')
    " Strip trailing whitespace
    %s/\m\s\+$//
  endif
endfunction
autocmd Filetype c,cpp,python call StripTrailingWhiteSpacesIfReady('FileType')
autocmd BufWrite,BufRead * StripTrailingWhiteSpacesIfReady('Buf')
Mu Mind
la source