Saya memiliki autocmd untuk file TeX dan Markdown untuk menyimpan file secara otomatis. Tidak ada yang aneh:
autocmd CursorHold *.tex,*.md w
Namun, saat pengaturan khusus untuk file ini meningkat, saya membaginya menjadi ftplugin/tex.vim
dan ftplugin/markdown.vim
:
" ftplugin/tex.vim
autocmd CursorHold *.tex w
" ftplugin/markdown.vim
autocmd CursorHold *.md w
Sekarang, file-file ini bersumber hanya untuk file yang sesuai, sehingga pencocokan pola menjadi berlebihan. Rupanya, autocmd
s bisa menjadi buffer-lokal. Dari :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>
Itu sepertinya dimaksudkan untuk penggunaan seperti itu. Sekarang, keduanya ftplugin/tex.vim
dan ftplugin/markdown.vim
dapat memiliki:
autocmd CursorHold <buffer> w
Saya tidak terlalu peduli dengan ekstensi yang sebenarnya selama filetype itu benar, jadi ini menyelamatkan saya dari keharusan khawatir *.md
dan *.markdown
dan ekstensi apa pun lainnya yang valid untuk penurunan harga.
Apakah penggunaan ini <buffer>
benar? Apakah ada jebakan yang harus saya waspadai? Akankah segalanya menjadi berantakan jika saya menghapus buffer dan membuka yang lain (semoga angkanya tidak akan bertabrakan, tapi ...)?
up
(kependekan:update
) akan lebih baik daripadaw
di autocmd Anda (hindari menulis yang tidak perlu).w
gagal. Berkali-kali.:up
tidak melakukan apa pun dalam kasus itu. :)Jawaban:
Saya pikir itu benar, tetapi Anda hanya perlu membungkusnya di dalam sebuah augroup, dan menghapus yang terakhir, untuk memastikan bahwa autocmd tidak akan diduplikasi setiap kali Anda menjalankan perintah yang memuat buffer yang sama.
Seperti yang Anda jelaskan, pola khusus
<buffer>
memungkinkan Anda untuk mengandalkan mekanisme deteksi tipe file bawaan, yang diterapkan di dalam file$VIMRUNTIME/filetype.vim
.Dalam file ini, Anda dapat menemukan autocmds bawaan Vim yang bertanggung jawab untuk mengatur tipe file yang benar untuk setiap buffer yang diberikan. Misalnya, untuk penurunan harga:
Di dalam plugin filetype Anda, Anda bisa menyalin pola yang sama untuk setiap autocmd yang Anda instal. Misalnya, untuk secara otomatis menyimpan buffer ketika kursor Anda belum bergerak selama beberapa detik:
Tetapi
<buffer>
jauh lebih sedikit verbose:Selain itu, jika suatu hari ekstensi lain valid, dan
$VIMRUNTIME/filetype.vim
diperbarui untuk memasukkannya, autocmds Anda tidak akan diinformasikan. Dan Anda harus memperbarui semua polanya di dalam plugin tipe file Anda.Saya tidak yakin tetapi saya tidak berpikir bahwa Vim dapat menggunakan kembali nomor buffer dari buffer yang dihapus. Saya tidak dapat menemukan bagian yang relevan dari bantuan, tetapi saya menemukan paragraf ini dari vim.wikia.com :
Selain itu, seperti yang dijelaskan oleh @ Tumbler41 , ketika Anda menghapus buffer, autocmds-nya dihapus. Dari
:h autocmd-buflocal
:Jika Anda ingin memeriksa diri Anda sendiri, Anda dapat melakukannya dengan meningkatkan tingkat verbositas Vim menjadi 6. Anda dapat melakukannya sementara, hanya untuk satu perintah, dengan menggunakan
:verbose
pengubah. Jadi, di dalam buffer penurunan harga Anda, Anda dapat menjalankan:Kemudian, jika Anda memeriksa pesan Vim:
Anda akan melihat garis yang terlihat seperti ini:
Di mana
42
nomor buffer markdown Anda.Ada 3 situasi yang saya anggap sebagai jebakan dan yang melibatkan pola khusus
<buffer>
. Di dua dari mereka,<buffer>
mungkin menjadi masalah, yang lain itu adalah solusi.Perangkap 1
Pertama, Anda harus berhati-hati dengan cara Anda menghapus augroup autocmds lokal Anda. Anda harus terbiasa dengan cuplikan ini:
Jadi, Anda bisa tergoda untuk menggunakannya untuk autocmds buffer-local Anda, tidak dimodifikasi, seperti ini:
Tetapi ini akan memiliki efek yang tidak diinginkan. Pertama kali Anda memuat buffer markdown, sebut saja
A
, autocmd-nya akan dipasang dengan benar. Kemudian, ketika Anda akan memuat ulangA
, autocmd akan dihapus (karenaautocmd!
), dan diinstal ulang. Jadi, augroup dengan benar akan mencegah duplikasi autocmd.Sekarang, misalkan Anda memuat buffer markdown ke-2, sebut saja
B
, di jendela ke-2. SEMUA autocmds dari augroup akan dihapus: itu adalah autocmd dariA
dan yang dariB
. Kemudian, autocmd TUNGGAL akan diinstal untukB
.Jadi, ketika Anda membuat beberapa perubahan
B
, dan menunggu beberapa detik untukCursorHold
dipecat, itu akan disimpan secara otomatis. Tetapi jika Anda kembali keA
dan melakukan hal yang sama, buffer tidak akan disimpan. Ini karena terakhir kali Anda memuat buffer markdown, ada ketidakseimbangan antara apa yang Anda hapus dan apa yang Anda tambahkan. Anda menghapus lebih dari yang Anda tambahkan.Solusinya adalah tidak menghapus SEMUA autocmds, tetapi hanya yang buffer saat ini, dengan meneruskan pola khusus
<buffer>
ke:autocmd!
:Perhatikan bahwa Anda dapat mengganti
CursorHold
dengan bintang untuk mencocokkan acara apa pun di baris yang menghapus autocmds:Dengan cara ini, Anda tidak perlu menentukan semua acara yang sedang didengarkan autocmds Anda saat ingin menghapus augroup.
Perangkap 2
Ada jebakan lain, tapi kali
<buffer>
ini bukan masalahnya, itu solusinya.Saat Anda memasukkan opsi lokal dalam plugin tipe file, Anda mungkin melakukannya seperti ini:
Ini akan berfungsi seperti yang diharapkan untuk opsi buffer-local, tetapi tidak selalu untuk yang window-local. Untuk mengilustrasikan masalah ini, Anda dapat mencoba eksperimen berikut. Buat file
~/.vim/after/ftdetect/potion.vim
, dan di dalamnya tulis:File ini akan secara otomatis mengatur filetype
potion
untuk file apa pun yang memiliki ekstensi.pn
. Anda tidak perlu membungkusnya di dalam augroup karena, untuk jenis file ini, Vim akan melakukannya secara otomatis (lihat:h ftdetect
).Jika direktori perantara tidak ada di sistem Anda, Anda dapat membuatnya.
Selanjutnya, buat plugin filetype
~/.vim/after/ftplugin/potion.vim
, dan di dalamnya tulis:Secara default, dalam
potion
file, pengaturan ini akan menyebabkan karakter tab ditampilkan sebagai^I
dan akhir baris sebagai$
.Sekarang, buat minimal
vimrc
; di dalam/tmp/vimrc
tulis:... untuk mengaktifkan plugin tipe file.
Juga, buat file ramuan
/tmp/pn.pn
,, dan file acak/tmp/file
. Dalam file ramuan, tulis sesuatu:Dalam file acak, tulis path ke file ramuan
/tmp/pn.pn
:Sekarang, mulai Vim dengan inisialisasi minimum, hanya sumber
vimrc
, dan buka kedua file dalam viewports vertikal:Anda akan melihat 2 viewports vertikal. File ramuan di sebelah kiri menampilkan ujung baris dengan tanda dolar, file acak di sebelah kanan tidak menampilkannya sama sekali.
Berikan fokus ke file acak, dan tekan
gf
untuk menampilkan file ramuan yang jalurnya di bawah kursor. Anda sekarang melihat buffer ramuan yang sama di viewport kanan, tetapi kali ini, akhir baris tidak ditampilkan dengan tanda dolar. Dan jika Anda mengetik:setlocal list?
, Vim harus menjawab dengannolist
:Seluruh rangkaian acara:
... tidak terjadi, karena yang pertama
BufRead
,, tidak terjadi ketika Anda menekangf
. Buffer sudah dimuat.Ini mungkin tampak tak terduga, karena ketika Anda menambahkan
setlocal list
di dalam plugin filetype ramuan Anda, Anda mungkin berpikir bahwa itu akan mengaktifkan'list'
opsi di jendela mana pun yang menampilkan buffer ramuan.Masalahnya tidak spesifik untuk
potion
tipe file baru ini . Anda dapat mengalaminya denganmarkdown
file juga.Ini juga tidak spesifik untuk
'list'
opsi. Anda dapat mengalaminya dengan pengaturan jendela-lokal lainnya, seperti'conceallevel'
,'foldmethod'
,'foldexpr'
,'foldtitle'
, ...Itu juga tidak spesifik untuk
gf
perintah. Anda dapat mengalaminya dengan perintah lain yang dapat mengubah buffer ditampilkan di jendela saat ini: tanda global,C-o
(bergerak mundur dalam jendela-jumplist lokal):b {buffer_number}
,, ...Untuk meringkas, opsi jendela-lokal akan ditetapkan dengan benar, jika dan hanya jika:
BufRead
harus dipecat):split
(dalam hal ini, ia harus mewarisi opsi jendela-lokal dari jendela tempat perintah itu dijalankan)Jika tidak, opsi jendela lokal mungkin tidak diatur dengan benar.
Solusi yang mungkin adalah dengan mengaturnya tidak secara langsung dari plugin tipe file, tetapi dari autocmd yang terinstal di yang terakhir, yang akan mendengarkan
BufWinEnter
. Acara ini harus dipecat setiap kali buffer ditampilkan di jendela.Jadi, misalnya, alih-alih menulis ini:
Anda akan menulis ini:
Dan di sini, Anda menemukan lagi pola khusus
<buffer>
.Perangkap 3
Jika Anda mengubah tipe file buffer Anda, autocmds akan tetap ada. Jika Anda ingin menghapusnya, Anda perlu mengkonfigurasi
b:undo_ftplugin
(lihat:h undo_ftplugin
), dan sertakan perintah ini di dalamnya:Namun, jangan mencoba menghapus augroup itu sendiri, karena mungkin masih ada beberapa buffer penurunan harga yang memiliki autocmds di dalamnya.
FWIW, ini cuplikan UltiSnips yang saya gunakan untuk menyetel
b:undo_ftplugin
:Dan inilah contoh nilai yang saya miliki di
~/.vim/after/ftplugin/awk.vim
:Sebagai catatan, saya mengerti mengapa Anda mengajukan pertanyaan, karena ketika saya mencari semua baris di mana pola khusus
<buffer>
digunakan dalam file default Vim:Saya hanya menemukan 9 kecocokan (Anda mungkin menemukan lebih atau kurang, saya menggunakan Vim versi 8.0, dengan tambalan hingga
134
). Dan di antara 9 pertandingan, 7 ada dalam dokumentasi, hanya 2 yang benar-benar bersumber. Anda harus menemukannya di $ VIMRUNTIME / syntax / dircolors.vim :Saya tidak tahu apakah itu bisa menyebabkan masalah, tetapi mereka tidak dalam sebuah augroup, yang berarti setiap kali Anda ulang penyangga yang filetype adalah
dircolors
(itu terjadi jika Anda mengedit file bernama.dircolors
,.dir_colors
atau yang jalan berakhir dengan/etc/DIR_COLORS
), plugin sintaks akan menambahkan autocmd lokal-buffer baru.Anda dapat memeriksanya seperti ini:
Perintah terakhir harus menampilkan ini:
Sekarang, muat ulang buffer, dan tanyakan lagi apa autocmds lokal-buffer untuk buffer saat ini:
Kali ini, Anda akan melihat:
Setelah setiap reload file,
s:reset_colors()
dans:preview_color('.')
akan disebut satu waktu tambahan, setiap kali salah satu acaraCursorHold
,CursorHoldI
,CursorMoved
,CursorMovedI
dipecat.Ini mungkin bukan masalah besar, karena bahkan setelah memuat ulang
dircolors
file beberapa kali, saya tidak melihat perlambatan nyata, atau perilaku tak terduga dari Vim.Jika ini merupakan masalah bagi Anda, Anda dapat menghubungi pengelola plugin sintaksis, tetapi sementara itu, jika Anda ingin mencegah duplikasi autocmds, Anda bisa membuat plugin sintaksis Anda sendiri untuk
dircolors
file, menggunakan file~/.vim/syntax/dircolors.vim
. Di dalamnya Anda akan mengimpor konten plugin sintaksis asli:Kemudian, dalam yang terakhir, Anda hanya akan membungkus autocmds di dalam sebuah grup yang akan Anda hapus. Jadi, Anda akan mengganti baris ini:
... dengan yang ini:
Perhatikan bahwa jika Anda membuat
dircolors
plugin sintaksis dengan file~/.vim/after/syntax/dircolors.vim
, itu tidak akan berfungsi, karena plugin sintaksis default akan bersumber sebelumnya. Dengan menggunakan~/.vim/syntax/dircolors.vim
, plugin sintaksis Anda akan bersumber sebelum yang default, dan itu akan mengatur variabel buffer-localb:current_syntax
, yang akan mencegah plugin sintaksis bersumber karena mengandung penjaga ini:Aturan umumnya tampaknya: gunakan direktori
~/.vim/ftplugin
dan~/.vim/syntax
untuk membuat plugin filetype / sintaks khusus dan mencegah plugin berikutnya (untuk filetype yang sama) di jalur runtime yang akan bersumber (termasuk yang default). Dan gunakan~/.vim/after/ftplugin
,,~/.vim/after/syntax
bukan untuk mencegah plugin lain dari sumber, tetapi hanya untuk memiliki kata terakhir pada nilai beberapa pengaturan.sumber
autocmd!
denganautocmd! CursorHold <buffer>
dalamaugroup
blok adalah gotcha yang sangat penting - dan seharusnya disorot di muka. Meskipun demikian ... ini adalah investasi waktu, usaha, dan air mata yang luar biasa.