Czy to użycie <bufora> jest prawidłowe?
Myślę, że jest poprawny, ale wystarczy owinąć go w grupę aug i wyczyścić tę ostatnią, aby mieć pewność, że autocmd nie będzie duplikowany za każdym razem, gdy wykonasz polecenie, które ponownie ładuje ten sam bufor.
Jak wyjaśniono, specjalny wzorzec <buffer>
pozwala polegać na wbudowanym mechanizmie wykrywania typu pliku, zaimplementowanym w pliku $VIMRUNTIME/filetype.vim
.
W tym pliku możesz znaleźć wbudowane autocmdy Vima, które są odpowiedzialne za ustawienie poprawnego rodzaju pliku dla dowolnego bufora. Na przykład dla obniżki cen:
" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
Wewnątrz wtyczki typu pliku możesz skopiować te same wzorce dla każdej instalowanej aplikacji autocmd. Na przykład, aby automatycznie zapisać bufor, gdy kursor nie poruszy się w ciągu kilku sekund:
au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md update
Ale <buffer>
jest o wiele mniej gadatliwy:
au CursorHold <buffer> update
Poza tym, jeśli któregoś dnia inne rozszerzenie będzie ważne i $VIMRUNTIME/filetype.vim
zostanie zaktualizowane, aby je uwzględnić, twoje autocmds nie zostaną poinformowane. Będziesz musiał zaktualizować wszystkie ich wzorce we wtyczkach typu pliku.
Czy sprawy się popsują, jeśli wyczyszczę bufor i otworzę inny (mam nadzieję, że liczby się nie zderzą, ale…)?
Nie jestem pewien, ale nie sądzę, że Vim może ponownie użyć numeru bufora wyczyszczonego bufora. Nie mogłem znaleźć odpowiedniej sekcji z pomocy, ale znalazłem ten akapit z vim.wikia.com :
Nie. Vim nie użyje ponownie numeru bufora usuniętego dla nowego bufora. Vim zawsze przypisze następny numer kolejny do nowego bufora.
Poza tym, jak wyjaśnił @ Tumbler41 , po wyczyszczeniu bufora jego autocmds są usuwane. Od :h autocmd-buflocal
:
Oczywiście, kiedy bufor zostanie wyczyszczony, jego lokalne polecenia buforowe również znikną.
Jeśli chcesz się sprawdzić, możesz to zrobić, zwiększając poziom szczegółowości Vima do 6. Możesz to zrobić tymczasowo, tylko dla jednej komendy, używając :verbose
modyfikatora. Tak więc w buforze przecen możesz wykonać:
:6verbose bwipe
Następnie, jeśli sprawdzisz wiadomości Vima:
:messages
Powinieneś zobaczyć linię wyglądającą tak:
auto-removing autocommand: CursorHold <buffer=42>
Gdzie 42
był numer bufora przecen.
Czy są jakieś pułapki, o których powinienem wiedzieć?
Istnieją 3 sytuacje, które uznałbym za pułapki i które dotyczą specjalnego wzorca <buffer>
. W dwóch z nich <buffer>
może być problem, w drugim rozwiązanie.
Pitfall 1
Po pierwsze, powinieneś uważać na sposób, w jaki usuwasz grupy augocd z lokalnych buforów. Musisz znać ten fragment kodu:
augroup your_group_name
autocmd!
autocmd Event pattern command
augroup END
Można więc pokusić się o użycie go w przypadku autocmd-buforów lokalnych, niezmodyfikowanych, takich jak to:
augroup my_markdown
autocmd!
autocmd CursorHold <buffer> update
augroup END
Ale będzie to miało niepożądany efekt. Przy pierwszym załadowaniu bufora przeceny nazwijmy go A
, jego autocmd zostanie poprawnie zainstalowany. Następnie, gdy przeładujesz A
, autocmd zostanie usunięty (z powodu autocmd!
) i ponownie zainstalowany. Augroup poprawnie zapobiegnie duplikowaniu programu autocmd.
Załóżmy teraz, że ładujesz drugi bufor przeceny, nazwijmy go B
w drugim oknie. Wszystkie autocmds grupy aug zostaną usunięte: to jest autocmd A
i jeden z B
. Następnie zostanie zainstalowany POJEDYNCZY autocmd B
.
Tak więc, kiedy wprowadzisz jakieś zmiany B
i zaczekasz kilka sekund na uruchomienie CursorHold
, zostanie ono automatycznie zapisane. Ale jeśli wrócisz A
i zrobisz to samo, bufor nie zostanie zapisany. Jest tak, ponieważ podczas ostatniego ładowania bufora przeceny istniała nierównowaga między tym, co usunąłeś, a tym, co dodałeś. Usunąłeś więcej niż dodałeś.
Rozwiązaniem jest nie usuwanie WSZYSTKICH autocmds, ale tylko tych z bieżącego bufora, poprzez przekazanie specjalnego wzorca <buffer>
do :autocmd!
:
augroup my_markdown
autocmd! CursorHold <buffer>
autocmd CursorHold <buffer> update
augroup END
Pamiętaj, że możesz zastąpić CursorHold
gwiazdką, aby dopasować dowolne zdarzenie w wierszu, które usuwa autocmds:
augroup my_markdown
autocmd! * <buffer>
autocmd CursorHold <buffer> update
augroup END
W ten sposób nie musisz określać wszystkich zdarzeń, na które nasłuchują autorzy, gdy chcesz wyczyścić grupę aug.
Pitfall 2
Jest jeszcze jedna pułapka, ale tym razem <buffer>
to nie problem, to rozwiązanie.
Po dołączeniu opcji lokalnej do wtyczki typu pliku prawdopodobnie robisz to w następujący sposób:
setlocal option1=value
setlocal option2
Będzie to działać zgodnie z oczekiwaniami dla opcji lokalnych buforów, ale nie zawsze dla opcji lokalnych okien. Aby zilustrować problem, możesz wypróbować następujący eksperyment. Utwórz plik ~/.vim/after/ftdetect/potion.vim
, a w nim napisz:
autocmd BufNewFile,BufRead *.pn setfiletype potion
Ten plik automatycznie ustawi typ pliku potion
dla każdego pliku, którego rozszerzenie jest .pn
. Nie musisz owijać go w augroup, ponieważ dla tego rodzaju pliku Vim zrobi to automatycznie (patrz :h ftdetect
).
Jeśli katalogi pośrednie nie istnieją w twoim systemie, możesz je utworzyć.
Następnie utwórz wtyczkę typu pliku ~/.vim/after/ftplugin/potion.vim
, a wewnątrz niej napisz:
setlocal list
Domyślnie w potion
pliku to ustawienie spowoduje wyświetlanie znaków tabulacji jako ^I
i końca linii jako $
.
Teraz stwórz minimum vimrc
; w środku /tmp/vimrc
napisz:
filetype plugin on
... aby włączyć wtyczki typu pliku.
Utwórz również plik mikstury /tmp/pn.pn
i plik losowy /tmp/file
. W pliku mikstury napisz coś:
foo
bar
baz
W losowym pliku zapisz ścieżkę do pliku mikstury /tmp/pn.pn
:
/tmp/pn.pn
Teraz uruchom Vima z minimum inicjalizacji, po prostu pozyskaj vimrc
i otwórz oba pliki w rzutniach pionowych:
$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file
Powinieneś zobaczyć 2 pionowe rzutnie. Plik mikstury po lewej stronie wyświetla koniec linii ze znakami dolara, losowy plik po prawej w ogóle ich nie wyświetla.
Ustaw fokus na losowym pliku i naciśnij, gf
aby wyświetlić plik mikstury, którego ścieżka znajduje się pod kursorem. Teraz widzisz ten sam bufor mikstury w prawej rzutni, ale tym razem koniec linii nie jest wyświetlany ze znakami dolara. A jeśli wpiszesz :setlocal list?
, Vim powinien odpowiedzieć nolist
:
Cały łańcuch wydarzeń:
BufRead event → set 'filetype' option → load filetype plugins
... nie wystąpił, ponieważ pierwszy z nich BufRead
nie pojawił się po naciśnięciu gf
. Bufor został już załadowany.
Może się to wydawać nieoczekiwane, ponieważ po dodaniu setlocal list
do wtyczki typu pliku mikstury możesz pomyśleć, że włączy ona 'list'
opcję w dowolnym oknie wyświetlającym bufor mikstury.
Problem nie jest specyficzny dla tego nowego typu potion
pliku. Możesz także doświadczyć tego z markdown
plikiem.
Nie jest to również specyficzne dla 'list'
opcji. Można wystąpić z innymi ustawieniami okiennych lokalnego, jak 'conceallevel'
, 'foldmethod'
, 'foldexpr'
, 'foldtitle'
, ...
Nie jest to również specyficzne dla gf
polecenia. Możesz tego doświadczyć z innymi poleceniami, które mogą zmienić bufor wyświetlany w bieżącym oknie: znak globalny, C-o
(przesuń się do tyłu w lokalnej liście okien),, :b {buffer_number}
...
Podsumowując, opcje lokalne dla okna zostaną poprawnie ustawione, jeśli i tylko jeśli:
- plik nie został odczytany podczas bieżącej sesji Vima (ponieważ
BufRead
będzie musiał zostać uruchomiony )
- plik jest wyświetlany w oknie, w którym opcje lokalne dla okna zostały już poprawnie ustawione
- nowe okno jest tworzone za pomocą polecenia, takiego jak
:split
(w tym przypadku powinno dziedziczyć opcje okna lokalnego z okna, w którym polecenie zostało wykonane)
W przeciwnym razie opcje lokalne dla okna mogą nie być ustawione poprawnie.
Możliwym rozwiązaniem byłoby ustawienie ich nie bezpośrednio z wtyczki typu pliku, ale z autocmd zainstalowanego w tym drugim, który będzie nasłuchiwał BufWinEnter
. To zdarzenie powinno być uruchamiane za każdym razem, gdy bufor jest wyświetlany w oknie.
Na przykład zamiast pisać to:
setlocal list
Napisałbyś to:
augroup my_potion
au! * <buffer>
au BufWinEnter <buffer> setlocal list
augroup END
I tutaj znów znajdziesz specjalny wzór <buffer>
.
Pitfall 3
Jeśli zmienisz typ pliku bufora, autocmds pozostaną. Jeśli chcesz je usunąć, musisz skonfigurować b:undo_ftplugin
(patrz :h undo_ftplugin
) i dołączyć do niego następujące polecenie:
exe 'au! my_markdown * <buffer>'
Nie próbuj jednak usuwać samej grupy augroup, ponieważ nadal mogą istnieć bufory przecen, które zawierają w sobie autocmd.
FWIW, to jest fragment UltiSnips, którego używam do ustawienia 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
A oto przykład wartości, którą mam ~/.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>'
\ "
Na marginesie rozumiem, dlaczego zadałeś pytanie, ponieważ kiedy szukałem wszystkich wierszy, w których zastosowano specjalny wzór <buffer>
w domyślnych plikach Vima:
:vim /au\%[tocmd!].\{-}<buffer>/ $VIMRUNTIME/**/*
Znalazłem tylko 9 dopasowań (możesz znaleźć mniej więcej, używam Vima w wersji 8.0, z łatami do 134
). A spośród 9 dopasowań, 7 znajduje się w dokumentacji, tylko 2 faktycznie pochodzą. Powinieneś je znaleźć w $ VIMRUNTIME / syntax / dircolors.vim :
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
Nie wiem, czy to może powodować problem, ale nie są one wewnątrz augroup, co oznacza, że za każdym razem przeładować bufor, którego filetype jest dircolors
(to się dzieje, jeśli edytować plik o nazwie .dircolors
, .dir_colors
lub których końce Ścieżka z /etc/DIR_COLORS
), wtyczka do składni doda nowy autocmd dla bufora lokalnego.
Możesz to sprawdzić w następujący sposób:
$ vim ~/.dir_colors
:au * <buffer>
Ostatnie polecenie powinno wyświetlać to:
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('.')
Teraz ponownie załaduj bufor i ponownie zapytaj, jakie są lokalne autocmds dla bieżącego bufora:
:e
:au * <buffer>
Tym razem zobaczysz:
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('.')
Po każdym przeładunku pliku s:reset_colors()
i s:preview_color('.')
będzie nazwany jeden dodatkowy czas, każdy czas imprezy CursorHold
, CursorHoldI
, CursorMoved
, CursorMovedI
zostaje zwolniony.
Prawdopodobnie nie jest to duży problem, ponieważ nawet po dircolors
kilkukrotnym przeładowaniu pliku nie zauważyłem zauważalnego spowolnienia ani nieoczekiwanego zachowania Vima.
Jeśli jest to dla Ciebie problem, możesz skontaktować się z opiekunem wtyczki składni, ale w międzyczasie, jeśli chcesz zapobiec powielaniu autocmds, możesz utworzyć własną wtyczkę składni dircolors
plików, używając tego pliku ~/.vim/syntax/dircolors.vim
. Wewnątrz możesz zaimportować zawartość oryginalnej wtyczki składni:
$ vim ~/.vim/syntax/dircolors.vim
:r $VIMRUNTIME/syntax/dircolors.vim
Następnie, w tym ostatnim, po prostu owiniesz autocmds wewnątrz grupy aug, którą wyczyścisz. Więc zastąpiłbyś te linie:
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
... z tymi:
augroup my_dircolors_syntax
autocmd! * <buffer>
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
augroup END
Zauważ, że jeśli utworzyłeś dircolors
wtyczkę składni z plikiem ~/.vim/after/syntax/dircolors.vim
, to nie działałoby, ponieważ wcześniej domyślna wtyczka składniowa byłaby pozyskiwana. Korzystając z tej wtyczki, tworzona jest wtyczka składniowa ~/.vim/syntax/dircolors.vim
przed domyślną, i ustawi zmienną lokalną dla bufora b:current_syntax
, co zapobiegnie źródłowej wtyczce składni, ponieważ zawiera tę ochronę:
if exists("b:current_syntax")
finish
endif
Ogólna zasada wygląda następująco: użyj katalogów ~/.vim/ftplugin
i, ~/.vim/syntax
aby utworzyć niestandardową wtyczkę typu pliku / składni i zapobiec kolejnemu wtyczce (dla tego samego typu pliku) w ścieżce środowiska wykonawczego (w tym domyślnym). I używaj ~/.vim/after/ftplugin
, ~/.vim/after/syntax
nie po to, aby zapobiec pozyskiwaniu innych wtyczek, ale po prostu, aby mieć ostatnie słowo na temat wartości niektórych ustawień.