Cách sử dụng <đệm> này có đúng không?
Tôi nghĩ đó là chính xác, nhưng bạn chỉ cần bọc nó trong một nhóm, và xóa phần sau, để đảm bảo rằng autocmd sẽ không bị trùng lặp mỗi khi bạn thực hiện lệnh tải lại cùng bộ đệm.
Như bạn đã giải thích, mẫu đặc biệt <buffer>
cho phép bạn dựa vào cơ chế phát hiện filetype tích hợp, được triển khai bên trong tệp $VIMRUNTIME/filetype.vim
.
Trong tệp này, bạn có thể tìm thấy các autocmds tích hợp của Vim chịu trách nhiệm thiết lập kiểu tệp chính xác cho bất kỳ bộ đệm nào. Ví dụ: để đánh dấu:
" Markdown
au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
Trong plugin filetype của bạn, bạn có thể sao chép các mẫu tương tự cho mỗi autocmd bạn cài đặt. Ví dụ: để tự động lưu bộ đệm khi con trỏ của bạn không di chuyển trong vài giây:
au CursorHold *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md update
Nhưng <buffer>
là cách ít dài dòng hơn:
au CursorHold <buffer> update
Ngoài ra, nếu một ngày nào đó một tiện ích mở rộng khác hợp lệ và $VIMRUNTIME/filetype.vim
được cập nhật để bao gồm nó, thì autocmds của bạn sẽ không được thông báo. Và bạn sẽ phải cập nhật tất cả các mẫu của chúng bên trong các plugin filetype của bạn.
Mọi thứ sẽ trở nên lộn xộn nếu tôi xóa một bộ đệm và mở một bộ đệm khác (hy vọng các con số sẽ không va chạm với nhau, nhưng là)?
Tôi không chắc nhưng tôi không nghĩ rằng Vim có thể sử dụng lại số bộ đệm của bộ đệm bị xóa. Tôi không thể tìm thấy phần có liên quan từ trợ giúp, nhưng tôi đã tìm thấy đoạn này từ vim.wikia.com :
Không. Vim sẽ không sử dụng lại số bộ đệm của bộ đệm đã xóa cho bộ đệm mới. Vim sẽ luôn gán số thứ tự tiếp theo cho bộ đệm mới.
Ngoài ra, như @ Tumbler41 đã giải thích, khi bạn xóa bộ đệm, autocmds của nó sẽ bị xóa. Từ :h autocmd-buflocal
:
Dĩ nhiên, khi bộ đệm bị xóa, bộ đệm tự động cục bộ cũng không còn nữa.
Nếu bạn muốn tự kiểm tra, bạn có thể làm như vậy bằng cách tăng mức độ chi tiết của Vim lên 6. Bạn có thể làm điều đó tạm thời, chỉ với một lệnh, bằng cách sử dụng công cụ :verbose
sửa đổi. Vì vậy, bên trong bộ đệm markdown của bạn, bạn có thể thực thi:
:6verbose bwipe
Sau đó, nếu bạn kiểm tra tin nhắn của Vim:
:messages
Bạn sẽ thấy một dòng trông như thế này:
auto-removing autocommand: CursorHold <buffer=42>
Trong trường hợp 42
là số lượng đệm markdown của bạn.
Có bất kỳ cạm bẫy nào tôi nên nhận thức?
Có 3 tình huống mà tôi coi là cạm bẫy và liên quan đến mô hình đặc biệt <buffer>
. Trong hai trong số đó, <buffer>
có thể là một vấn đề, mặt khác đó là một giải pháp.
Cạm bẫy 1
Trước tiên, bạn nên cẩn thận với cách bạn xóa các nhóm của bộ đệm tự động cục bộ. Bạn phải làm quen với đoạn trích này:
augroup your_group_name
autocmd!
autocmd Event pattern command
augroup END
Vì vậy, bạn có thể bị cám dỗ sử dụng nó cho bộ đệm - bộ đệm tự động cục bộ, không được sửa đổi, như thế này:
augroup my_markdown
autocmd!
autocmd CursorHold <buffer> update
augroup END
Nhưng điều này sẽ có tác dụng không mong muốn. Lần đầu tiên bạn tải bộ đệm đánh dấu, hãy gọi nó A
, autocmd của nó sẽ được cài đặt chính xác. Sau đó, khi bạn sẽ tải lạiA
, autocmd sẽ bị xóa (vì autocmd!
) và được cài đặt lại. Vì vậy, các nhóm sẽ ngăn chặn chính xác sự trùng lặp của autocmd.
Bây giờ, giả sử bạn tải bộ đệm đánh dấu thứ 2, hãy gọi nó B
, trong cửa sổ thứ 2. TẤT CẢ các autocmds của auggroup sẽ bị xóa: đó là autocmd của A
và một trong số đó B
. Sau đó, một autocmd SINGLE sẽ được cài đặt choB
.
Vì vậy, khi bạn thực hiện một số thay đổi B
và đợi vài giây CursorHold
để được kích hoạt, nó sẽ tự động được lưu. Nhưng nếu bạn quay trở lạiA
và làm điều tương tự, bộ đệm sẽ không được lưu. Điều này là do lần cuối cùng bạn tải bộ đệm đánh dấu, có sự mất cân bằng giữa những gì bạn đã xóa và những gì bạn đã thêm. Bạn đã loại bỏ nhiều hơn những gì bạn đã thêm.
Giải pháp là không xóa TẤT CẢ các autocmds, mà chỉ xóa các bộ đệm hiện tại, bằng cách chuyển mẫu đặc biệt <buffer>
tới :autocmd!
:
augroup my_markdown
autocmd! CursorHold <buffer>
autocmd CursorHold <buffer> update
augroup END
Lưu ý rằng bạn có thể thay thế CursorHold
bằng một ngôi sao để khớp với bất kỳ sự kiện nào trong dòng loại bỏ autocmds:
augroup my_markdown
autocmd! * <buffer>
autocmd CursorHold <buffer> update
augroup END
Bằng cách này, bạn không phải chỉ định tất cả các sự kiện mà autocmds của bạn đang lắng nghe khi bạn muốn xóa nhóm.
Cạm bẫy 2
Có một cạm bẫy khác, nhưng lần này <buffer>
này không phải là vấn đề, đó là giải pháp.
Khi bạn bao gồm một tùy chọn cục bộ trong một plugin filetype, bạn có thể làm như thế này:
setlocal option1=value
setlocal option2
Điều này sẽ hoạt động như mong đợi cho các tùy chọn bộ đệm cục bộ, nhưng không phải lúc nào cũng cho các tùy chọn cục bộ cửa sổ. Để minh họa vấn đề, bạn có thể thử thí nghiệm sau. Tạo tập tin ~/.vim/after/ftdetect/potion.vim
và bên trong nó viết:
autocmd BufNewFile,BufRead *.pn setfiletype potion
Tệp này sẽ tự động đặt loại tệp potion
cho bất kỳ tệp nào có phần mở rộng .pn
. Bạn không cần phải bọc nó trong một nhóm, bởi vì, đối với loại tệp cụ thể này, Vim sẽ tự động thực hiện (xem :h ftdetect
).
Nếu các thư mục trung gian không tồn tại trên hệ thống của bạn, bạn có thể tạo chúng.
Tiếp theo, tạo plugin filetype ~/.vim/after/ftplugin/potion.vim
và bên trong nó viết:
setlocal list
Theo mặc định, trong một potion
tệp, cài đặt này sẽ khiến các ký tự tab được hiển thị dưới dạng ^I
và cuối dòng là$
.
Bây giờ, tạo tối thiểu vimrc
; bên trong /tmp/vimrc
viết:
filetype plugin on
... Để kích hoạt các plugin filetype.
Ngoài ra, tạo một tệp thuốc /tmp/pn.pn
và một tệp ngẫu nhiên /tmp/file
. Trong tệp thuốc, viết một cái gì đó:
foo
bar
baz
Trong tệp ngẫu nhiên, viết đường dẫn đến tệp thuốc /tmp/pn.pn
:
/tmp/pn.pn
Bây giờ, hãy bắt đầu Vim với tối thiểu các lần khởi tạo, chỉ cần tìm nguồn vimrc
và mở cả hai tệp trong chế độ xem dọc:
$ vim -Nu /tmp/vimrc -O /tmp/pn.pn /tmp/file
Bạn sẽ thấy 2 khung nhìn dọc. Tệp thuốc ở bên trái hiển thị cuối dòng có ký hiệu đô la, tệp ngẫu nhiên ở bên phải hoàn toàn không hiển thị chúng.
Đặt tiêu điểm cho tệp ngẫu nhiên và nhấn gf
để hiển thị tệp thuốc có đường dẫn nằm dưới con trỏ. Bây giờ bạn nhìn thấy bộ đệm thuốc tương tự trong chế độ xem bên phải, nhưng lần này, cuối dòng không được hiển thị với ký hiệu đô la. Và nếu bạn gõ :setlocal list?
, Vim nên trả lời nolist
:
Toàn bộ chuỗi sự kiện:
BufRead event → set 'filetype' option → load filetype plugins
... đã không xảy ra, bởi vì lần đầu tiên BufRead
, đã không xảy ra khi bạn nhấn gf
. Bộ đệm đã được tải.
Điều này có vẻ bất ngờ, bởi vì khi bạn thêm vào setlocal list
bên trong plugin filetype của bạn, bạn có thể đã nghĩ rằng nó sẽ cho phép 'list'
tùy chọn trong bất kỳ cửa sổ nào hiển thị bộ đệm thuốc.
Vấn đề không cụ thể đối với potion
loại tệp mới này . Bạn có thể trải nghiệm nó với một markdown
tập tin quá.
Nó cũng không cụ thể cho 'list'
tùy chọn. Bạn có thể trải nghiệm nó với các thiết lập cửa sổ địa phương khác, như 'conceallevel'
, 'foldmethod'
, 'foldexpr'
,'foldtitle'
, ...
Nó cũng không cụ thể cho gf
lệnh. Bạn có thể trải nghiệm nó với các lệnh khác có thể thay đổi bộ đệm hiển thị trong cửa sổ hiện hành: dấu ấn toàn cầu, C-o
(di chuyển lạc hậu trong jumplist cửa sổ địa phương), :b {buffer_number}
...
Để tóm tắt, các tùy chọn cục bộ cửa sổ sẽ được đặt chính xác, nếu và chỉ khi:
- tập tin chưa được đọc trong phiên Vim hiện tại (vì
BufRead
sẽ phải bị loại bỏ)
- tập tin đang được hiển thị trong một cửa sổ nơi các tùy chọn cục bộ cửa sổ đã được đặt chính xác
- cửa sổ mới được tạo bằng một lệnh như
:split
(trong trường hợp này, nó sẽ kế thừa các tùy chọn cục bộ cửa sổ từ cửa sổ nơi lệnh được thực thi)
Nếu không, các tùy chọn cục bộ cửa sổ có thể không được đặt chính xác.
Một giải pháp khả thi sẽ là đặt chúng không trực tiếp từ một plugin filetype, mà từ một autocmd được cài đặt ở phần sau, nó sẽ lắng nghe BufWinEnter
. Sự kiện này sẽ được kích hoạt mỗi khi bộ đệm được hiển thị trong cửa sổ.
Vì vậy, ví dụ, thay vì viết này:
setlocal list
Bạn sẽ viết điều này:
augroup my_potion
au! * <buffer>
au BufWinEnter <buffer> setlocal list
augroup END
Và ở đây, bạn tìm thấy một mẫu đặc biệt <buffer>
.
Cạm bẫy 3
Nếu bạn thay đổi kiểu tệp của bộ đệm, autocmds sẽ vẫn còn. Nếu bạn muốn loại bỏ chúng, bạn cần cấu hình b:undo_ftplugin
(xem :h undo_ftplugin
) và bao gồm lệnh này trong đó:
exe 'au! my_markdown * <buffer>'
Tuy nhiên, đừng cố gắng loại bỏ chính nhóm, bởi vì vẫn có thể có một số bộ đệm đánh dấu có autocmds bên trong nó.
FWIW, đây là đoạn mã UltiSnips mà tôi đang sử dụng để đặt 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
Và đây là một ví dụ về giá trị mà tôi có ~/.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>'
\ "
Là một lưu ý phụ, tôi hiểu lý do tại sao bạn đặt câu hỏi, bởi vì khi tôi tìm tất cả các dòng có mẫu đặc biệt <buffer>
được sử dụng trong các tệp mặc định của Vim:
:vim /au\%[tocmd!].\{-}<buffer>/ $VIMRUNTIME/**/*
Tôi chỉ tìm thấy 9 trận đấu (bạn có thể tìm thấy nhiều hơn hoặc ít hơn, tôi đang sử dụng Vim phiên bản 8.0, với các bản vá lên đến 134
). Và trong số 9 trận đấu, 7 trận trong tài liệu, chỉ có 2 trận thực sự có nguồn gốc. Bạn nên tìm thấy chúng trong $ VIMRUNTIME / cú pháp / dircolors.vim :
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
Tôi không biết nếu nó có thể gây ra một vấn đề, nhưng họ không phải là bên trong một augroup, có nghĩa là mỗi khi bạn tải lại một bộ đệm mà filetype là dircolors
(nó sẽ xảy ra nếu bạn chỉnh sửa một file có tên .dircolors
, .dir_colors
hoặc những người có đầu con đường với/etc/DIR_COLORS
), plugin cú pháp sẽ thêm một autocmd bộ đệm cục bộ mới.
Bạn có thể kiểm tra nó như thế này:
$ vim ~/.dir_colors
:au * <buffer>
Lệnh cuối cùng sẽ hiển thị điều này:
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('.')
Bây giờ, tải lại bộ đệm và hỏi lại các autocmds cục bộ cho bộ đệm hiện tại là gì:
:e
:au * <buffer>
Lần này, bạn sẽ thấy:
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('.')
Sau mỗi tải lại của tập tin, s:reset_colors()
và s:preview_color('.')
sẽ được gọi là một lần bổ sung, mỗi một thời gian của sự kiện CursorHold
, CursorHoldI
, CursorMoved
, CursorMovedI
bị sa thải.
Đây có lẽ không phải là một vấn đề lớn, bởi vì ngay cả sau khi tải lại dircolors
vài lần, tôi vẫn không thấy sự chậm chạp đáng chú ý hoặc hành vi bất ngờ từ Vim.
Nếu đó là vấn đề với bạn, bạn có thể liên hệ với người bảo trì plugin cú pháp, nhưng trong lúc này, nếu bạn muốn ngăn chặn việc sao chép autocmds, bạn có thể tạo plugin cú pháp của riêng mình cho dircolors
các tệp, sử dụng tệp ~/.vim/syntax/dircolors.vim
. Trong đó, bạn sẽ nhập nội dung của plugin cú pháp gốc:
$ vim ~/.vim/syntax/dircolors.vim
:r $VIMRUNTIME/syntax/dircolors.vim
Sau đó, trong phần sau, bạn sẽ chỉ bọc các autocmds bên trong một nhóm mà bạn sẽ xóa. Vì vậy, bạn sẽ thay thế các dòng này:
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
... với những cái này:
augroup my_dircolors_syntax
autocmd! * <buffer>
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
autocmd CursorHold,CursorHoldI <buffer> call s:reset_colors()
augroup END
Lưu ý rằng nếu bạn đã tạo dircolors
plugin cú pháp của mình với tệp ~/.vim/after/syntax/dircolors.vim
, nó sẽ không hoạt động, bởi vì plugin cú pháp mặc định sẽ có nguồn gốc trước đó. Bằng cách sử dụng ~/.vim/syntax/dircolors.vim
, plugin cú pháp của bạn sẽ có nguồn gốc trước cái mặc định và nó sẽ đặt biến bộ đệm cục bộ b:current_syntax
, điều này sẽ ngăn plugin cú pháp mặc định không có nguồn gốc vì nó có chứa bảo vệ này:
if exists("b:current_syntax")
finish
endif
Quy tắc chung dường như là: sử dụng các thư mục ~/.vim/ftplugin
và ~/.vim/syntax
thư mục để tạo một plugin kiểu tệp / cú pháp tùy chỉnh và ngăn chặn plugin tiếp theo (cho cùng một kiểu tệp) trong đường dẫn thời gian chạy có nguồn gốc (bao gồm cả các mặc định). Và sử dụng ~/.vim/after/ftplugin
, ~/.vim/after/syntax
không phải để ngăn các plugin khác có nguồn gốc, mà chỉ để có từ cuối cùng về giá trị của một số cài đặt.