Bir ftplugin içindeki bir autocmd için desen eşleştirme mi yoksa <tamponlama mı?


14

Dosyayı otomatik olarak kaydetmek için TeX ve Markdown dosyaları için bir autocmd var. Alışılmadık bir şey yok:

autocmd CursorHold *.tex,*.md w

Ancak, bu dosyalar için özel ayarlar arttıkça, bunları ftplugin/tex.vimve klasörlerine ayırdım ftplugin/markdown.vim:

" ftplugin/tex.vim
autocmd CursorHold *.tex w
" ftplugin/markdown.vim
autocmd CursorHold *.md w

Şimdi, bu dosyalar sadece uygun dosyalar için kaynaklanmıştır, bu nedenle desen eşleşmesi gereksizdir. Görünüşe göre, autocmds, tampon-lokal olabilir. Gönderen :h autocmd-buffer-local:

Buffer-local autocommands are attached to a specific buffer.  They are useful
if the buffer does not have a name and when the name does not match a specific
pattern.  But it also means they must be explicitly added to each buffer.

Instead of a pattern buffer-local autocommands use one of these forms:
        <buffer>        current buffer
        <buffer=99>     buffer number 99
        <buffer=abuf>   using <abuf> (only when executing autocommands)
                        <abuf>

Bu tür bir kullanım içindir. Şimdi, hem ftplugin/tex.vimve ftplugin/markdown.vimsahip olabilir:

autocmd CursorHold <buffer> w

Dosya türü doğru olduğu sürece gerçek uzantı hakkında gerçekten endişelenmiyorum, bu yüzden endişelenmekten *.mdve *.markdownMarkdown için geçerli olan diğer uzantılardan beni kurtarıyor .

Bu kullanım <buffer>doğru mu? Dikkat etmem gereken tuzaklar var mı? Bir tamponu silip bir başkasını açarsam işler dağınık mı olur (umarım sayılar çarpışmaz, ama…)?


1
Bir tamponu silerseniz, arabellek-yerel autocmds de silinir eminim.
Tumbler41

@ Tumbler41 gerçekten. Yardımda birkaç paragraf aşağı olduğu söyleniyor.
muru

1
Tam olarak sorduğunuz şey değil, ama up(kısa :update) wautocmd'nizden daha iyi olurdu (gereksiz yazımlardan kaçının).
mMontu

@montu güzel. Hatta git geçmişinden incelediğim bir dosya için autocmd etkinleştirildiğinde yaşadığım bir sorunu çözüyor. Arabellek salt okunurdu ve wbaşarısız oldu. Defalarca. :upbu durumda hiçbir şey yapmaz. :)
muru

Sevdiğinize sevindim :) Bu arada, 'otomatik yaz' seçeneğini de yararlı bulabilirsiniz (motivasyonunuza bağlı olarak, autocmds'i düşürebilirsiniz).
mMontu

Yanıtlar:


11

Bu <tamponlayıcı> kullanımı doğru mu?

Doğru olduğunu düşünüyorum, ancak aynı tamponu yeniden yükleyen bir komutu her çalıştırdığınızda autocmd'nin çoğaltılmayacağından emin olmak için onu bir grubun içine sarmanız ve ikincisini temizlemeniz gerekir.

Açıkladığınız gibi, özel desen <buffer>dosyanın içine yerleştirilmiş yerleşik dosya tipi algılama mekanizmasına güvenmenizi sağlar $VIMRUNTIME/filetype.vim.

Bu dosyada, belirli bir arabellek için doğru dosya türünü ayarlamaktan sorumlu olan Vim'in yerleşik autocmds'ını bulabilirsiniz. Örneğin, işaretleme için:

" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md  setf markdown

Dosya türü eklentinizin içinde, yüklediğiniz her autocmd için aynı kalıpları kopyalayabilirsiniz. Örneğin, imleciniz birkaç saniye boyunca hareket etmediğinde arabelleği otomatik olarak kaydetmek için:

au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md  update

Ama <buffer>çok daha az ayrıntılı:

au CursorHold <buffer> update

Ayrıca, bir gün başka bir uzantı geçerliyse ve $VIMRUNTIME/filetype.vimbunu içerecek şekilde güncellenirse, oto cmd'leriniz bilgilendirilmez. Ayrıca tüm dosya türlerini dosya türü eklentilerinizde güncellemeniz gerekir.


Bir tamponu silip bir başkasını açarsam işler dağınık olur mu (umarım sayılar çarpışmaz, ama…)?

Emin değilim ama Vim'in silinmiş bir arabellek arabellek numarasını tekrar kullanabileceğini sanmıyorum. Yardımdan ilgili bölümü bulamadım, ancak bu paragrafı vim.wikia.com'dan buldum :

Hayır. Vim, silinen bir arabellek arabellek numarasını yeni bir arabellek için yeniden kullanmayacaktır. Vim her zaman yeni bir arabellek için bir sonraki sıra numarasını atayacaktır.

Ayrıca, @ Tumbler41'in açıkladığı gibi, bir tamponu sildiğinizde, autocmds kaldırılır. Gönderen :h autocmd-buflocal:

Bir tampon silindiğinde, tampon-yerel oto komutları da elbette kaybolur.

Kendinizi kontrol etmek istiyorsanız, Vim'in ayrıntı düzeyini 6'ya çıkararak bunu yapabilirsiniz :verbose. Değiştiriciyi kullanarak geçici olarak, sadece bir komut için yapabilirsiniz . Böylece, işaretleme tamponunuzun içinde şunları yürütebilirsiniz:

:6verbose bwipe

Ardından, Vim'in mesajlarını kontrol ederseniz:

:messages

Şöyle bir çizgi görmelisiniz:

auto-removing autocommand: CursorHold <buffer=42>

42İşaretleme tamponunuzun sayısı neredeydi .


Dikkat etmem gereken tuzaklar var mı?

Tuzaklar olarak kabul edeceğim ve özel modeli içeren 3 durum var <buffer>. İkisinde <buffer>bir sorun olabilir, diğerinde bir çözüm.

Tuzak 1

İlk olarak, arabellek yerel oto cmd'lerinizin ağ gruplarını temizleme şeklinize dikkat etmelisiniz. Bu snippet'e aşina olmalısınız:

augroup your_group_name
    autocmd!
    autocmd Event pattern command
augroup END

Yani, bu gibi değiştirilmemiş, arabellek-yerel oto cmd'leriniz için kullanmaya cazip olabilirsiniz:

augroup my_markdown
    autocmd!
    autocmd CursorHold <buffer> update
augroup END

Ancak bunun istenmeyen bir etkisi olacaktır. İlk kez bir işaretleme arabelleği yüklediğinizde, diyelim ki A, autocmd doğru şekilde kurulacaktır. Ardından, yeniden yüklediğinizde A, autocmd silinir (nedeniyle autocmd!) ve yeniden yüklenir. Bu nedenle, ağ grubu autocmd'nin kopyalanmasını doğru şekilde önleyecektir.

Şimdi, ikinci bir işaretleme arabelleği yüklediğinizi varsayalım B, ikinci bir pencerede diyelim . Augroup'un TÜM autocmds temizlenecek: yani autocmd Ave biri B. Ardından, bir SINGLE autocmd yüklenecektir B.

Bu nedenle, bazı değişiklikler yaptığınızda Bve CursorHoldişten çıkarılmanız için birkaç saniye beklediğinizde , otomatik olarak kaydedilir. Ancak Aaynı şeye geri dönüp aynı şeyi yaparsanız, arabellek kaydedilmez. Bunun nedeni, en son bir işaretleme arabelleği yüklediğinizde, kaldırdıklarınız ve ekledikleriniz arasında bir dengesizlik olmasıydı. Eklediğinizden daha fazlasını kaldırdınız.

Çözüm, TÜM oto cmd'leri değil, yalnızca özel arabelleği geçirerek geçerli arabellekleri <buffer>kaldırmaktır :autocmd!:

augroup my_markdown
    autocmd! CursorHold <buffer>
    autocmd CursorHold <buffer> update
augroup END

CursorHoldSatırdaki autocmds'i kaldıran herhangi bir etkinliğe uyacak bir yıldızla değiştirebileceğinizi unutmayın:

augroup my_markdown
    autocmd! * <buffer>
    autocmd CursorHold <buffer> update
augroup END

Bu şekilde, ağ grubunu temizlemek istediğinizde otomatik cmd'lerinizin dinlediği tüm olayları belirtmeniz gerekmez.


Tuzak 2

Başka bir tuzak daha var, ama bu sefer <buffer>sorun değil, çözüm.

Bir filetype eklentisine yerel bir seçenek eklediğinizde, muhtemelen böyle yaparsınız:

setlocal option1=value
setlocal option2

Bu, arabellek-yerel seçenekler için beklendiği gibi çalışacaktır, ancak her zaman pencere-yerel seçenekler için geçerli olmayacaktır. Sorunu göstermek için aşağıdaki denemeyi deneyebilirsiniz. Dosyayı oluşturun ~/.vim/after/ftdetect/potion.vimve içine şunu yazın:

autocmd BufNewFile,BufRead *.pn setfiletype potion

Bu dosya potion, uzantısı olan herhangi bir dosya için dosya türünü otomatik olarak ayarlar .pn. Bu tür bir dosya için Vim otomatik olarak yapacak (çünkü), bir grubun içine sarmanıza gerek yok :h ftdetect.

Ara dizinler sisteminizde yoksa, bunları oluşturabilirsiniz.

Ardından, filetype eklentisini oluşturun ~/.vim/after/ftplugin/potion.vimve içine şunu yazın:

setlocal list

Varsayılan olarak, bir potiondosyada bu ayar, sekme karakterlerinin olarak ^Ive satır sonu olarak görüntülenmesine neden olur $.

Şimdi bir minimal oluşturun vimrc; iç /tmp/vimrcyazma:

filetype plugin on

... filetype eklentilerini etkinleştirmek için.

Ayrıca, bir iksir dosyası /tmp/pn.pnve rastgele bir dosya oluşturun /tmp/file. İksir dosyasına bir şey yazın:

foo
bar
baz

Rastgele dosyaya, iksir dosyasının yolunu yazın /tmp/pn.pn:

/tmp/pn.pn

Şimdi, Vim'i minimum başlatmalarla başlatın, sadece kaynak kodlayın vimrcve her iki dosyayı dikey görünüm pencerelerinde açın:

$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file

2 dikey görünüm alanı görmelisiniz. Soldaki iksir dosyası dolar işareti olan satırların sonunu görüntüler, sağdaki rastgele dosya hiç göstermez.

Odağı rastgele dosyaya verin ve gfyolu imlecin altında olan iksir dosyasını görüntülemek için tuşuna basın . Şimdi aynı iksir arabelleğini sağ görüntü portunda görüyorsunuz, ancak bu sefer satırların sonu dolar işareti ile gösterilmiyor. Ve yazarsanız :setlocal list?, Vim cevap vermelidir nolist:

resim açıklamasını buraya girin

Bütün olaylar zinciri:

BufRead event → set 'filetype' option → load filetype plugins

... olmadı, çünkü bunlardan ilki, BufReadbastığınızda gerçekleşmedi gf. Arabellek zaten yüklendi.

Beklenmedik görünebilir, çünkü setlocal listiksir dosya türü eklentinizin içine eklediğinizde , 'list'bir iksir arabelleği görüntüleyen herhangi bir pencerede seçeneği etkinleştireceğini düşünmüş olabilirsiniz .

Sorun bu yeni potiondosya türüyle ilgili değil. Bir markdowndosyayla da deneyimleyebilirsiniz .

Seçeneğe de özgü 'list'değil. Diğer pencere yerel ayarlarla yaşayabilirsiniz gibi 'conceallevel', 'foldmethod', 'foldexpr', 'foldtitle', ...

gfKomuta da özgü değil. Geçerli pencerede görüntülenen arabelleği değiştirebilecek diğer komutlarla karşılaşabilirsiniz: genel işaret, C-o(pencere-yerel atlama listesinde geri git) :b {buffer_number},, ...

Özetlemek gerekirse, pencere yerel seçenekleri yalnızca aşağıdaki durumlarda doğru ayarlanacaktır:

  • geçerli Vim oturumu sırasında dosya okunmadı (çünkü BufReadişten çıkarılması gerekecek)
  • dosya, yerel pencere seçeneklerinin doğru ayarlandığı bir pencerede görüntüleniyor
  • yeni pencere gibi bir komutla oluşturulur :split(bu durumda, komutun yürütüldüğü pencereden pencere-yerel seçeneklerini devralmalıdır)

Aksi takdirde, pencere yerel seçenekleri doğru ayarlanmamış olabilir.

Olası bir çözüm, onları doğrudan bir dosya türü eklentisinden değil, ikincisinde yüklü bir autocmd'den dinlemektir BufWinEnter. Bir pencerede her arabellek görüntülendiğinde bu olay başlatılmalıdır.

Örneğin, bunu yazmak yerine:

setlocal list

Bunu yazarsınız:

augroup my_potion
    au! * <buffer>
    au BufWinEnter <buffer> setlocal list
augroup END

Ve burada, yine özel modeli buluyorsun <buffer>.

resim açıklamasını buraya girin


Tuzak 3

Arabellek dosya türünü değiştirirseniz, autocmds kalır. Bunları kaldırmak istiyorsanız, yapılandırmanız b:undo_ftplugin(bkz. :h undo_ftplugin) Ve bu komutu içine eklemeniz gerekir:

exe 'au! my_markdown * <buffer>'

Ancak, grubun kendisini kaldırmaya çalışmayın, çünkü içinde autocmds olan bazı işaretleme arabellekleri hala olabilir.

FWIW, ayarlamak için kullandığım UltiSnips snippet'i 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

Ve işte sahip olduğum değere bir örnek ~/.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>'
                    \  "

Bir yan not olarak, soruyu neden sorduğunuzu anlıyorum, çünkü <buffer>Vim'in varsayılan dosyalarında özel desenin kullanıldığı tüm satırları aradığımda :

:vim /au\%[tocmd!].\{-}<buffer>/ $VIMRUNTIME/**/*

Sadece 9 eşleşme buldum (az ya da çok bulabilirsiniz, Vim sürüm 8.0 kullanıyorum, yamalar kadar 134). Ve 9 maç arasında 7'si dokümantasyonda, sadece 2 tanesi aslında kaynaklıdır. Bunları $ VIMRUNTIME / sözdizimi / dircolors.vim'de bulmalısınız :

autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI   <buffer> call s:reset_colors()

Bir soruna neden olabilir eğer bilmiyorum, ama onlar filetype olan bir tampon yeniden her zaman anlamına gelir augroup, içeride değil dircolors(eğer adlı bir dosya üzerinde düzeltmeler olur .dircolors, .dir_colorsya da kimin yolu uçları ile /etc/DIR_COLORS), sözdizimi eklentisi yeni bir arabellek-yerel autocmd ekleyecektir.

Bu şekilde kontrol edebilirsiniz:

$ vim ~/.dir_colors
:au * <buffer>

Son komut şunu göstermelidir:

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('.')

Şimdi, arabelleği yeniden yükleyin ve geçerli arabelleğin arabellek yerel autocmds'ının ne olduğunu tekrar sorun:

:e
:au * <buffer>

Bu sefer şunu göreceksiniz:

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('.')

Her dosyanın yeniden, sonra s:reset_colors()ve s:preview_color('.')bir ek süre adı verilecek, olayın her zaman bir CursorHold, CursorHoldI, CursorMoved, CursorMovedIateşlenir.

Muhtemelen büyük bir sorun değil, çünkü bir dircolorsdosyayı birkaç kez yeniden yükledikten sonra bile, Vim'den fark edilir bir yavaşlama veya beklenmedik bir davranış görmedim.

Bu sizin için bir sorunsa, sözdizimi eklentisinin koruyucusuna başvurabilirsiniz, ancak bu arada, autocmds'ın çoğaltılmasını önlemek istiyorsanız dircolors, dosyayı kullanarak dosyalar için kendi sözdizimi eklentinizi oluşturabilirsiniz ~/.vim/syntax/dircolors.vim. İçinde orijinal sözdizimi eklentisinin içeriğini içe aktaracaksınız:

$ vim ~/.vim/syntax/dircolors.vim
:r $VIMRUNTIME/syntax/dircolors.vim

Sonra, ikincisinde, autocmds'ı temizleyeceğiniz bir grubun içine sarmanız yeterlidir. Yani, şu satırları değiştirirsiniz:

autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI   <buffer> call s:reset_colors()

... bunlarla:

augroup my_dircolors_syntax
    autocmd! * <buffer>
    autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
    autocmd CursorHold,CursorHoldI   <buffer> call s:reset_colors()
augroup END

dircolorsSözdizimi eklentinizi dosyayla oluşturduysanız ~/.vim/after/syntax/dircolors.vim, varsayılan sözdizimi eklentisinin daha önce kaynaklanacağından işe yaramayacağını unutmayın. Kullanarak ~/.vim/syntax/dircolors.vim, sözdizimi eklentiniz varsayılandan önce kaynaklanacaktır ve b:current_syntaxbu koruyucuyu içerdiği için varsayılan sözdizimi eklentisinin kaynaklanmasını önleyecek olan tampon yerel değişkeni ayarlayacaktır :

if exists("b:current_syntax")
    finish
endif

Genel kural şöyledir: özel bir dosya türü / sözdizimi eklentisi oluşturmak için ~/.vim/ftpluginve ~/.vim/syntaxdizinlerini kullanın ve çalışma zamanı yolundaki bir sonraki eklentinin (aynı dosya türü için) kaynaklanmasını (varsayılan olanlar dahil) önleyin. Ve ~/.vim/after/ftplugin, ~/.vim/after/syntaxdiğer eklentilerin kaynaklanmasını önlemek için değil, sadece bazı ayarların değerinde son kelimeye sahip olmak için kullanın.


1
Keşke bu kadar zorlanabilseydim.
Zengin

3
@Rich bunu senin için zorlaştırdım. Benim tek şikayet bir özet "tl; dr" olmaması. Anlamak için hayati önem taşıyan metinsel minutiae sayfaları, yaşlanmak için canımı acıtıyor. Yerine autocmd!ile autocmd! CursorHold <buffer>de augroupbloklar özellikle kritik yakaladım - ve peşin vurgulanan gerekirdi. Yine de ... bu inanılmaz bir zaman, çaba ve kanlı gözyaşı yatırımıdır.
Cecil Curry
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.