Ist diese Verwendung von <buffer> korrekt?
Ich denke, es ist richtig, aber Sie müssen es nur in eine Augroup einschließen und diese löschen, um sicherzustellen, dass die autocmd nicht jedes Mal dupliziert wird, wenn Sie einen Befehl ausführen, der denselben Puffer neu lädt.
Wie Sie erklärt haben, <buffer>
können Sie sich mit dem speziellen Muster auf den in der Datei implementierten Mechanismus zur Erkennung von Dateitypen verlassen $VIMRUNTIME/filetype.vim
.
In dieser Datei finden Sie die in Vim integrierten Autocmds, die für die Einstellung des richtigen Dateityps für einen bestimmten Puffer verantwortlich sind. Zum Beispiel für Abschriften:
" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
In Ihrem Dateityp-Plugin können Sie für jede von Ihnen installierte Autocmd die gleichen Muster kopieren. So speichern Sie beispielsweise den Puffer automatisch, wenn sich der Cursor einige Sekunden lang nicht bewegt hat:
au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md update
Aber <buffer>
ist viel weniger ausführlich:
au CursorHold <buffer> update
Außerdem, wenn eines Tages eine andere Erweiterung gültig ist und $VIMRUNTIME/filetype.vim
aktualisiert wird, um sie einzuschließen, werden Ihre AutocMDS nicht informiert. Und Sie müssen alle Muster in Ihren Dateityp-Plugins aktualisieren.
Wird es chaotisch, wenn ich einen Puffer lösche und einen anderen öffne (hoffentlich werden die Zahlen nicht kollidieren, aber ...)?
Ich bin nicht sicher, aber ich glaube nicht, dass Vim die Puffernummer eines gelöschten Puffers wiederverwenden kann. Ich konnte den relevanten Abschnitt in der Hilfe nicht finden, aber ich habe diesen Absatz von vim.wikia.com gefunden :
Nein. Vim verwendet die Puffernummer eines gelöschten Puffers nicht für einen neuen Puffer. Vim weist immer die nächste fortlaufende Nummer für einen neuen Puffer zu.
Außerdem werden, wie @ Tumbler41 erklärte, beim Löschen eines Puffers dessen Autocmds entfernt. Von :h autocmd-buflocal
:
Wenn ein Puffer gelöscht wird, gehen natürlich auch seine pufferlokalen Autobefehle verloren.
Wenn Sie sich selbst überprüfen möchten, können Sie dies tun, indem Sie die Ausführlichkeitsstufe von Vim auf 6 erhöhen. Sie können dies vorübergehend für nur einen Befehl tun, indem Sie den :verbose
Modifikator verwenden. So können Sie in Ihrem Abschriftenpuffer Folgendes ausführen:
:6verbose bwipe
Wenn Sie dann die Nachrichten von Vim überprüfen:
:messages
Sie sollten eine Zeile sehen, die so aussieht:
auto-removing autocommand: CursorHold <buffer=42>
Wo 42
war die Nummer Ihres Abschriftenpuffers?
Gibt es irgendwelche Fallstricke, auf die ich achten sollte?
Es gibt drei Situationen, die ich als Fallstricke betrachten würde und die das spezielle Muster betreffen <buffer>
. In zwei Fällen <buffer>
kann es sich um ein Problem handeln, in den anderen um eine Lösung.
Fallstricke 1
Zunächst sollten Sie vorsichtig sein, wie Sie die Augroups Ihrer pufferlokalen Autocmds löschen. Sie müssen mit diesem Snippet vertraut sein:
augroup your_group_name
autocmd!
autocmd Event pattern command
augroup END
Sie könnten also versucht sein, es für Ihre pufferlokalen autocmds zu verwenden, die nicht modifiziert wurden, wie folgt:
augroup my_markdown
autocmd!
autocmd CursorHold <buffer> update
augroup END
Dies hat jedoch einen unerwünschten Effekt. A
Wenn Sie einen Abschriftenpuffer zum ersten Mal laden, rufen wir ihn auf , seine Autocmd wird korrekt installiert. Wenn Sie dann neu laden A
, wird die autocmd (wegen autocmd!
) gelöscht und neu installiert. Die Augroup verhindert also korrekterweise das Duplizieren der Autocmd.
Angenommen, Sie laden einen zweiten Abschriftenpuffer, nennen wir ihn B
in einem zweiten Fenster. ALLE autocmds der Augroup werden gelöscht: das ist die autocmd von A
und die von B
. Dann wird eine SINGLE-Autocmd für installiert B
.
Wenn Sie also eine Änderung vornehmen B
und einige Sekunden warten, CursorHold
bis sie ausgelöst wird, wird sie automatisch gespeichert. Wenn Sie jedoch zurückkehren A
und dasselbe tun, wird der Puffer nicht gespeichert. Dies liegt daran, dass beim letzten Laden eines Markdown-Puffers ein Ungleichgewicht zwischen dem Entfernten und dem Hinzugefügten aufgetreten ist. Sie haben mehr entfernt, als Sie hinzugefügt haben.
Die Lösung besteht darin, nicht ALLE AutocMDS zu entfernen, sondern nur die des aktuellen Puffers, indem das spezielle Muster <buffer>
an :autocmd!
folgende Adresse übergeben wird :
augroup my_markdown
autocmd! CursorHold <buffer>
autocmd CursorHold <buffer> update
augroup END
Beachten Sie, dass Sie CursorHold
jedes Ereignis in der Zeile, in der autocmds entfernt werden , durch einen Stern ersetzen können:
augroup my_markdown
autocmd! * <buffer>
autocmd CursorHold <buffer> update
augroup END
Auf diese Weise müssen Sie nicht alle Ereignisse angeben, die Ihre Autocmds abhören, wenn Sie die Augroup löschen möchten.
Fallstricke 2
Es gibt noch eine weitere Falle, aber diesmal <buffer>
ist es nicht das Problem, sondern die Lösung.
Wenn Sie eine lokale Option in ein Dateityp-Plugin einfügen, geschieht dies wahrscheinlich folgendermaßen:
setlocal option1=value
setlocal option2
Dies funktioniert erwartungsgemäß für pufferlokale Optionen, jedoch nicht immer für fensterlokale Optionen. Um das Problem zu veranschaulichen, können Sie das folgende Experiment versuchen. Erstellen Sie die Datei ~/.vim/after/ftdetect/potion.vim
und schreiben Sie darin:
autocmd BufNewFile,BufRead *.pn setfiletype potion
Diese Datei legt automatisch den Dateityp potion
für jede Datei mit der Erweiterung fest .pn
. Sie müssen es nicht in eine Augroup einschließen, da Vim es für diese bestimmte Art von Datei automatisch ausführt (siehe :h ftdetect
).
Wenn die Zwischenverzeichnisse auf Ihrem System nicht vorhanden sind, können Sie sie erstellen.
Als nächstes erstellen Sie das Dateityp-Plugin ~/.vim/after/ftplugin/potion.vim
und schreiben darin:
setlocal list
Standardmäßig potion
bewirkt diese Einstellung in einer Datei, dass die Tabulatorzeichen als ^I
und das Zeilenende als angezeigt werden $
.
Erstellen Sie nun ein Minimum vimrc
. innen /tmp/vimrc
schreiben:
filetype plugin on
... um die Dateityp-Plugins zu aktivieren.
Erstellen Sie außerdem eine Trankdatei /tmp/pn.pn
und eine zufällige Datei /tmp/file
. Schreiben Sie in die Trankdatei Folgendes:
foo
bar
baz
Schreiben Sie in die Zufallsdatei den Pfad zur Trankdatei /tmp/pn.pn
:
/tmp/pn.pn
Starten Sie nun Vim mit einem Minimum an Initialisierungen, indem Sie nur die Quelle auswählen vimrc
und beide Dateien in vertikalen Ansichtsfenstern öffnen:
$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file
Sie sollten 2 vertikale Ansichtsfenster sehen. Die Zaubertrank-Datei auf der linken Seite zeigt das Ende von Zeilen mit Dollarzeichen an, die Zufallsdatei auf der rechten Seite zeigt sie überhaupt nicht an.
Setzen Sie den Fokus auf die Zufallsdatei und drücken Sie gf
, um die Trankdatei anzuzeigen, deren Pfad sich unter dem Cursor befindet. Sie sehen jetzt den gleichen Trankpuffer im rechten Ansichtsfenster, aber dieses Mal wird das Zeilenende nicht mit Dollarzeichen angezeigt. Und wenn Sie tippen :setlocal list?
, sollte Vim antworten mit nolist
:
Die ganze Kette von Ereignissen:
BufRead event → set 'filetype' option → load filetype plugins
... ist nicht aufgetreten, weil der erste von ihnen, BufRead
nicht aufgetreten ist, als Sie gedrückt haben gf
. Der Puffer wurde bereits geladen.
Es mag unerwartet erscheinen, weil Sie beim Hinzufügen setlocal list
in Ihrem Potion-Dateityp-Plugin möglicherweise gedacht haben, dass es die 'list'
Option in jedem Fenster aktivieren würde, in dem ein Potion-Puffer angezeigt wird .
Das Problem ist nicht spezifisch für diesen neuen potion
Dateityp. Sie können es auch mit einer markdown
Datei erleben .
Es ist auch nicht spezifisch für die 'list'
Option. Sie können es mit anderen Fenstern-lokalen Einstellungen erfahren, wie 'conceallevel'
, 'foldmethod'
, 'foldexpr'
, 'foldtitle'
, ...
Es ist auch nicht spezifisch für den gf
Befehl. Sie können es mit anderen Befehlen erleben, die den im aktuellen Fenster angezeigten Puffer ändern können: globale Markierung, C-o
(in der fensterlokalen Sprungliste rückwärts bewegen),, :b {buffer_number}
...
Zusammenfassend werden die fensterlokalen Optionen nur dann korrekt festgelegt, wenn:
- Die Datei wurde während der aktuellen Vim-Sitzung nicht gelesen (weil
BufRead
sie gefeuert werden muss)
- Die Datei wird in einem Fenster angezeigt, in dem die fensterlokalen Optionen bereits korrekt festgelegt wurden
- Das neue Fenster wird mit folgendem Befehl erstellt:
:split
(In diesem Fall sollten die fensterlokalen Optionen von dem Fenster übernommen werden, in dem der Befehl ausgeführt wurde.)
Andernfalls sind die fensterlokalen Optionen möglicherweise nicht richtig eingestellt.
Eine mögliche Lösung wäre, sie nicht direkt über ein Dateityp-Plugin festzulegen, sondern über eine in diesem installierte AutocMD, die sie abhört BufWinEnter
. Dieses Ereignis sollte jedes Mal ausgelöst werden, wenn ein Puffer in einem Fenster angezeigt wird.
Also zum Beispiel, anstatt dies zu schreiben:
setlocal list
Du würdest folgendes schreiben:
augroup my_potion
au! * <buffer>
au BufWinEnter <buffer> setlocal list
augroup END
Und hier finden Sie wieder das spezielle Muster <buffer>
.
Fallstricke 3
Wenn Sie den Dateityp Ihres Puffers ändern, bleiben die AutocMDS erhalten. Wenn Sie sie entfernen möchten, müssen Sie Folgendes konfigurieren b:undo_ftplugin
(siehe :h undo_ftplugin
) und den folgenden Befehl einfügen:
exe 'au! my_markdown * <buffer>'
Versuchen Sie jedoch nicht, die Augroup selbst zu entfernen, da es noch einige Abschriftenpuffer geben kann, in denen sich Autocmds befinden.
FWIW, dies ist das UltiSnips-Snippet, das ich verwende, um Folgendes festzulegen 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
Und hier ist ein Beispiel für den Wert, den ich habe ~/.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>'
\ "
Als Randnotiz verstehe ich, warum Sie die Frage gestellt haben, denn als ich nach allen Zeilen gesucht habe, in denen das spezielle Muster <buffer>
in den Standarddateien von Vim verwendet wurde:
:vim /au\%[tocmd!].\{-}<buffer>/ $VIMRUNTIME/**/*
Ich habe nur 9 Übereinstimmungen gefunden (möglicherweise finden Sie mehr oder weniger Übereinstimmungen, ich verwende Vim Version 8.0 mit Patches bis zu 134
). Und unter den 9 Übereinstimmungen sind 7 in der Dokumentation, nur 2 wurden tatsächlich beschafft. Sie sollten sie in $ VIMRUNTIME / syntax / dircolors.vim finden :
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
Ich weiß nicht , ob es ein Problem verursachen kann, aber sie sind nicht in einem augroup, die jedes Mal , bedeutet , dass Sie einen Puffer , dessen Dateityp neu zu laden ist dircolors
(es passiert , wenn Sie eine Datei mit dem Namen bearbeiten .dircolors
, .dir_colors
oder dessen Pfad endet mit /etc/DIR_COLORS
), Das Syntax-Plugin fügt eine neue pufferlokale Autocmd hinzu.
Sie können dies folgendermaßen überprüfen:
$ vim ~/.dir_colors
:au * <buffer>
Der letzte Befehl sollte dies anzeigen:
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('.')
Laden Sie nun den Puffer neu und fragen Sie erneut nach den pufferlokalen Autocmds für den aktuellen Puffer:
:e
:au * <buffer>
Dieses Mal werden Sie sehen:
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('.')
Nach jedem der Datei neu zu laden, s:reset_colors()
und s:preview_color('.')
wird ein weiteres Mal aufgerufen werden, jedes Mal , wenn einer der Veranstaltung CursorHold
, CursorHoldI
, CursorMoved
, CursorMovedI
wird gefeuert.
Dies ist wahrscheinlich kein großes Problem, da dircolors
ich auch nach mehrmaligem Neuladen einer Datei keine merkliche Verlangsamung oder ein unerwartetes Verhalten von Vim feststellen konnte.
Wenn es ein Problem für Sie ist, können Sie sich an den Betreuer des Syntax-Plugins wenden. Wenn Sie jedoch in der Zwischenzeit die Duplizierung von autocmds verhindern möchten, können Sie dircolors
mithilfe der Datei ein eigenes Syntax-Plugin für Dateien erstellen ~/.vim/syntax/dircolors.vim
. Darin würden Sie den Inhalt des ursprünglichen Syntax-Plugins importieren:
$ vim ~/.vim/syntax/dircolors.vim
:r $VIMRUNTIME/syntax/dircolors.vim
In letzterem Fall würden Sie die autocmds einfach in eine Augroup einschließen, die Sie löschen würden. Also würden Sie diese Zeilen ersetzen:
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
... mit diesen:
augroup my_dircolors_syntax
autocmd! * <buffer>
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
augroup END
Beachten Sie, dass, wenn Sie Ihr dircolors
Syntax-Plugin mit der Datei erstellt haben ~/.vim/after/syntax/dircolors.vim
, dies nicht funktioniert, da das Standardsyntax-Plugin zuvor verwendet wurde. Bei Verwendung von ~/.vim/syntax/dircolors.vim
wird Ihr Syntax-Plug-In vor dem Standard-Plug-In bereitgestellt und es wird die pufferlokale Variable festgelegt b:current_syntax
, die verhindert, dass das Standardsyntax-Plug-In bereitgestellt wird, da es diesen Schutz enthält:
if exists("b:current_syntax")
finish
endif
Die allgemeine Regel scheint zu lauten: Verwenden Sie die Verzeichnisse ~/.vim/ftplugin
und ~/.vim/syntax
, um ein benutzerdefiniertes Dateityp- / Syntax-Plugin zu erstellen und zu verhindern, dass das nächste Plugin (für denselben Dateityp) im Laufzeitpfad (einschließlich der Standard-Plugins) bezogen wird. Und Gebrauch ~/.vim/after/ftplugin
, ~/.vim/after/syntax
nicht zu verhindern , dass andere Plugins von Quellen zu werden, aber nur das letzte Wort haben , auf dem Wert von einigen Einstellungen.