Apakah penggunaan <buffer> ini benar?
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:
" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
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:
au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md update
Tetapi <buffer>
jauh lebih sedikit verbose:
au CursorHold <buffer> update
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.
Akankah segalanya menjadi berantakan jika saya menghapus buffer dan membuka yang lain (semoga angkanya tidak akan bertabrakan, tapi ...)?
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 :
Tidak. Vim tidak akan menggunakan kembali nomor buffer dari buffer yang dihapus untuk buffer baru. Vim akan selalu menetapkan nomor urut berikutnya untuk buffer baru.
Selain itu, seperti yang dijelaskan oleh @ Tumbler41 , ketika Anda menghapus buffer, autocmds-nya dihapus. Dari :h autocmd-buflocal
:
Ketika buffer dihapus, autocommand lokal-buffer juga hilang, tentu saja.
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:
:6verbose bwipe
Kemudian, jika Anda memeriksa pesan Vim:
:messages
Anda akan melihat garis yang terlihat seperti ini:
auto-removing autocommand: CursorHold <buffer=42>
Di mana 42
nomor buffer markdown Anda.
Apakah ada jebakan yang harus saya waspadai?
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:
augroup your_group_name
autocmd!
autocmd Event pattern command
augroup END
Jadi, Anda bisa tergoda untuk menggunakannya untuk autocmds buffer-local Anda, tidak dimodifikasi, seperti ini:
augroup my_markdown
autocmd!
autocmd CursorHold <buffer> update
augroup END
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 ulang A
, autocmd akan dihapus (karena autocmd!
), 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 dari A
dan yang dari B
. Kemudian, autocmd TUNGGAL akan diinstal untuk B
.
Jadi, ketika Anda membuat beberapa perubahan B
, dan menunggu beberapa detik untuk CursorHold
dipecat, itu akan disimpan secara otomatis. Tetapi jika Anda kembali ke A
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!
:
augroup my_markdown
autocmd! CursorHold <buffer>
autocmd CursorHold <buffer> update
augroup END
Perhatikan bahwa Anda dapat mengganti CursorHold
dengan bintang untuk mencocokkan acara apa pun di baris yang menghapus autocmds:
augroup my_markdown
autocmd! * <buffer>
autocmd CursorHold <buffer> update
augroup END
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:
setlocal option1=value
setlocal option2
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:
autocmd BufNewFile,BufRead *.pn setfiletype potion
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:
setlocal list
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:
filetype plugin on
... untuk mengaktifkan plugin tipe file.
Juga, buat file ramuan /tmp/pn.pn
,, dan file acak /tmp/file
. Dalam file ramuan, tulis sesuatu:
foo
bar
baz
Dalam file acak, tulis path ke file ramuan /tmp/pn.pn
:
/tmp/pn.pn
Sekarang, mulai Vim dengan inisialisasi minimum, hanya sumber vimrc
, dan buka kedua file dalam viewports vertikal:
$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file
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 dengan nolist
:
Seluruh rangkaian acara:
BufRead event → set 'filetype' option → load filetype plugins
... tidak terjadi, karena yang pertama BufRead
,, tidak terjadi ketika Anda menekan gf
. 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 dengan markdown
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:
- file belum dibaca selama sesi Vim saat ini (karena
BufRead
harus dipecat)
- file sedang ditampilkan di jendela di mana opsi jendela-lokal sudah diatur dengan benar
- jendela baru dibuat dengan perintah seperti
: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:
setlocal list
Anda akan menulis ini:
augroup my_potion
au! * <buffer>
au BufWinEnter <buffer> setlocal list
augroup END
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:
exe 'au! my_markdown * <buffer>'
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
:
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
Dan inilah contoh nilai yang saya miliki di ~/.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>'
\ "
Sebagai catatan, saya mengerti mengapa Anda mengajukan pertanyaan, karena ketika saya mencari semua baris di mana pola khusus <buffer>
digunakan dalam file default Vim:
:vim /au\%[tocmd!].\{-}<buffer>/ $VIMRUNTIME/**/*
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 :
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
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:
$ vim ~/.dir_colors
:au * <buffer>
Perintah terakhir harus menampilkan ini:
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('.')
Sekarang, muat ulang buffer, dan tanyakan lagi apa autocmds lokal-buffer untuk buffer saat ini:
:e
:au * <buffer>
Kali ini, Anda akan melihat:
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('.')
Setelah setiap reload file, s:reset_colors()
dan s:preview_color('.')
akan disebut satu waktu tambahan, setiap kali salah satu acara CursorHold
, 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:
$ vim ~/.vim/syntax/dircolors.vim
:r $VIMRUNTIME/syntax/dircolors.vim
Kemudian, dalam yang terakhir, Anda hanya akan membungkus autocmds di dalam sebuah grup yang akan Anda hapus. Jadi, Anda akan mengganti baris ini:
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
... dengan yang ini:
augroup my_dircolors_syntax
autocmd! * <buffer>
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
augroup END
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-local b:current_syntax
, yang akan mencegah plugin sintaksis bersumber karena mengandung penjaga ini:
if exists("b:current_syntax")
finish
endif
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.