Gibt es einen Weg zu AND-Ereignissen in der AutocMD?

21

Ich möchte ein autocmd Ereignis bei zwei Ereignissen auslösen, aber nicht so, wie dies normalerweise der Fall ist. Wenn also eines der Ereignisse eingetreten ist, wird ein Ereignis ausgelöst autocmd. Ich möchte es auslösen, wenn beide Ereignisse passiert sind.

Zum Beispiel:
Die übliche Vorgehensweise

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

Dieser Code ruft StripTrailingWhiteSpaces () für BufWrite oder BufRead auf

Ich würde gerne etwas machen wie:

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

Mit anderen Worten, es wird ausgelöst, autcmdwenn der Dateityp c, cpp oder python ist und das Schreiben in diesen Puffer erfolgt.

Jede Hilfe wird geschätzt.

Blitzbrand
quelle

Antworten:

14

Ein Autocommand-Befehl wird ausgeführt, wenn ein Ereignis eintritt. Sie möchten, dass ein Befehl ausgeführt wird, nachdem eine Abfolge von Ereignissen aufgetreten ist. Ein Weg dies zu tun ist wie folgt:

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

Das <buffer>Muster bewirkt, dass der automatische Befehl ausgelöst wird, wenn der aktuelle Puffer geschrieben wird. Sehen

:help autocmd-buflocal

Aktualisieren

Die obige Lösung ist ziemlich einfach und weist einige Fehler auf, die in den Kommentaren besprochen wurden. Hier finden Sie eine umfassendere Lösung, die einige dieser Mängel behebt. Es ordnet die Autobefehle einer Gruppe zu und löscht den BufWritePre-Autobefehl, falls vorhanden, bevor ein neuer erstellt wird. Es wird immer noch ein Autobefehl pro Puffer erstellt, aber nur einer.

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

Eine andere Lösung, ähnlich der Antwort von lcd047, die jetzt gelöscht wurde, besteht darin, zu erkennen, dass beim Auftreten des FileType-Ereignisses die Option 'filetype' gesetzt ist. Anschließend können Sie die Antwort auf das BufWritePost-Ereignis wie im folgenden Beispiel auf den Wert 'filetype' festlegen. Es hat gegenüber den anderen Lösungen den Vorteil, dass nur ein Autobefehl erstellt wird.

autocmd BufWritePre * if count(['c','cpp','python'],&filetype)
    \ | call SkipTrailingWhiteSpaces()
    \ | endif
garyjohn
quelle
Was ist, wenn ich dies für alle Dateien ausführen möchte, die gerade geöffnet sind, dh ich führe Folgendes aus: wa?
Flashburn
Wenn die Dateien mit dem richtigen Dateityp geöffnet worden wären, hätte die FileTypein der Antwort enthaltene autocmd bereits die zweite autocmd ( BufWritePre) eingerichtet, die beim Speichern ausgelöst wird .
VanLaser
1
Die FileTypeautocmd oben Willen Feuer für jede Datei , die Sie mit dem richtigen Dateityp zu öffnen, und werden das Einrichten eines Puffer lokales Ereignis für jede dieser Dateien. Wenn Sie also ausführen :wa, führt vim registrierte Ereignisse für jeden Puffer aus, bevor in einer Datei gespeichert wird.
VanLaser
1
Wenn Sie also 5 Python-Dateien öffnen, haben Sie autocmdstatt einer einzigen nur 5 Sekunden Zeit zum Schreiben. Wenn dann beispielsweise 3 dieser Dateien ausgeblendet werden, werden sie erneut angezeigt und erneut FileTypeausgelöst, sodass Sie 3 weitere autocmds erhalten, auch beim Schreiben. Das ist genial, ich frage mich, warum ich nicht auf diese Lösung gekommen bin. :)
lcd047
1
Leistung ist kein Problem. Das stripTrailingWhiteSpaces()mehrmalige Ausführen der Funktion für dieselbe Datei kann jedoch unbeabsichtigte Folgen haben. Je mehr autocmds Sie für dasselbe Ereignis für dieselbe Datei haben, desto wahrscheinlicher ist es, dass Sie auf einige echte Rennbedingungen stoßen. Versuchen Sie, vim_dev-Archive zu durchsuchen, um eine Vorstellung zu bekommen. Andererseits, was weiß ich, könnte es nur für dich funktionieren, oder?
lcd047
4

Wenn Sie nicht wissen, welches Ereignis zuerst eintritt, können Sie einen Helfer verwenden, um zu verfolgen, wann jedes Ereignis ausgelöst wird, und Ihren Befehl nur dann ausführen, wenn das letzte ausgelöst wird:

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
quelle