Czy w autocmd jest sposób na zdarzenia AND?

21

Chciałbym wyzwolić autocmd na dwóch zdarzeniach, ale nie w sposób, w jaki jest to zwykle robione, tj. Jeśli którekolwiek z tych zdarzeń miało miejsce, uruchom wyzwalacz autocmd. Chcę go uruchomić, jeśli wystąpią oba zdarzenia.

Na przykład:
Zwykły sposób to zrobić

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

Ten kod wywoła StripTrailingWhiteSpaces () na BufWrite lub BufRead

Chciałbym zrobić coś takiego:

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

Innymi słowy, wyzwala an, autcmdgdy typ pliku to jeden z c, cpp, python i następuje zapis w tym buforze.

Każda pomoc jest mile widziana.

flashburn
źródło

Odpowiedzi:

14

Komenda autocommand jest wykonywana, gdy wystąpi jedno zdarzenie. Chcesz, aby polecenie zostało wykonane po wystąpieniu sekwencji zdarzeń. Można to zrobić w następujący sposób:

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

<buffer>Wzór powoduje autocommand się być wyzwalane, gdy bieżący bufor jest napisane. Widzieć

:help autocmd-buflocal

Aktualizacja

Powyższe rozwiązanie jest dość proste i ma pewne wady, które zostały omówione w komentarzach. Oto bardziej kompletne rozwiązanie, które usuwa niektóre z tych wad. Umieszcza automatyczne polecenia w grupie i usuwa automatyczne polecenie BufWritePre, jeśli istnieje, przed utworzeniem nowego. Nadal tworzy jedną komendę automatyczną na bufor, ale tylko jedną.

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

Innym rozwiązaniem, podobnym do odpowiedzi wysłanej przez lcd047, teraz usuniętą, jest rozpoznanie, że gdy wystąpi zdarzenie FileType, ustawiana jest opcja „filetype”. Następnie możesz uzależnić odpowiedź na zdarzenie BufWritePost od wartości „filetype”, jak w poniższym przykładzie. Ma tę przewagę nad innymi rozwiązaniami, że tworzona jest tylko jedna komenda automatyczna.

autocmd BufWritePre * if count(['c','cpp','python'],&filetype)
    \ | call SkipTrailingWhiteSpaces()
    \ | endif
garyjohn
źródło
Co jeśli chcę uruchomić to na wszystkich aktualnie otwartych plikach, tj. Wykonuję: wa?
flashburn
Gdyby pliki zostały otwarte z poprawnym typem pliku, FileTypeautocmd w odpowiedzi już ustawiłby drugi autocmd ( BufWritePre) do uruchomienia podczas zapisywania.
VanLaser,
1
Powyższy FileTypeautocmd uruchomi się dla każdego pliku, który otworzysz z poprawnym typem pliku, i skonfiguruje zdarzenie lokalne dla każdego z tych plików. Więc jeśli uruchomisz :wa, vim uruchomi zarejestrowane zdarzenia dla każdego bufora, przed zapisaniem do pliku.
VanLaser,
1
Więc jeśli otworzysz 5 plików Python, będziesz mieć 5 autocmds zamiast jednego, wszystkie w trakcie zapisu. Jeśli, powiedzmy, 3 z tych plików zostaną ukryte, a następnie pokazane ponownie, zostaną ponownie FileTypeuruchomione, aby uzyskać jeszcze 3 autocmds, również podczas zapisu. To jest genialne, zastanawiam się, dlaczego nie wymyśliłem tego rozwiązania. :)
lcd047,
1
Wydajność nie stanowi problemu. Uruchomienie tej funkcji stripTrailingWhiteSpaces()kilka razy dla tego samego pliku może mieć niezamierzone konsekwencje. Ponadto, im więcej autocmdmasz czasu na to samo wydarzenie dla tego samego pliku, tym większe prawdopodobieństwo, że spotkasz się z naprawdę poważnymi warunkami wyścigowymi. Spróbuj przeszukać archiwa vim_dev, aby uzyskać pomysł. Z drugiej strony, co wiem, to może po prostu działać dla ciebie, prawda?
lcd047,
4

Mówiąc bardziej ogólnie, jeśli nie wiesz, które zdarzenie nastąpi jako pierwsze, możesz użyć pomocnika do śledzenia, kiedy każdy z nich strzela, i wykonać polecenie tylko, gdy ostatni z nich strzela:

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
źródło