Tôi sẽ giả định rằng bạn sử dụng matchit
phiên bản plugin mới nhất 1.13.3 mà tôi có thể tìm thấy tại thời điểm này trên kho github của Vim.
[%
hầu hết thời gian nhảy đến function!
, đôi khi (không nhất quán tùy thuộc vào vị trí con trỏ) nhảy đến if
và hoàn toàn bỏ qua (
s.
Khi bạn nhấn [%
, s:MultiMatch()
chức năng được gọi. Vào cuối của cái sau, có một while
vòng lặp có số lần lặp là v:count1
. Biến này lưu số đếm cho lệnh bình thường cuối cùng. Ở đây, nó nên như vậy 1
, bởi vì bạn đã không đạt được bất kỳ số nào trước đó [%
. Nhưng ở giữa hàm, một số :normal
lệnh được thực thi để lưu vị trí màn hình và con trỏ. Các lệnh bình thường này thay đổi giá trị của v:count1
.
Bạn có thể kiểm tra như thế này:
nno cd :<c-u>call Func()<cr>
fu! Func()
echom v:count1
endfu
Nguồn mã này và nhấn cd
, đọc tin nhắn của bạn ( :messages
): bạn sẽ thấy 1
, bởi vì bạn chưa nhấn bất kỳ số nào trước đó cd
. Bây giờ, nguồn mã này:
nno cd :<c-u>call Func()<cr>
fu! Func()
norm! 3G
echom v:count1
endfu
Và thực hiện cùng một thí nghiệm, nhấn cd
vào một tệp có hơn 3 dòng. Lần này, trong các tin nhắn, bạn sẽ thấy 3
, không 1
.
Bởi vì điều này, searchpair()
chức năng bên trong vòng lặp được gọi quá nhiều lần, mà, tôi nghi ngờ, giải thích hành vi bạn mô tả. Ít nhất, nó có trên máy của tôi ( 8.0
bản vá Linux, Vim 1-134
).
Để khắc phục điều này, bạn có thể xóa dòng 729 :
let level = v:count1
Và di chuyển nó ở đầu hàm (trước bất kỳ lệnh nào khác, bao gồm :normal
các lệnh, có cơ hội thay đổi v:count1
):
fun! s:MultiMatch(spflag, mode)
if !exists("b:match_words") || b:match_words == ""
return ""
end
let level = v:count1
Tôi mới thử matchit của neovim trong vim (đáng ngạc nhiên là khác với vim) và nó dường như hoạt động .. kỳ lạ
Điều này có lẽ là do yêu cầu kéo # 5124 mà neovim đã sáp nhập một năm trước. Theo thông điệp cam kết, mục đích của nó là ngăn chặn matchit
việc thêm một mục không mong muốn vào jumplist. Để giải quyết điều này, cam kết đã thay đổi cách lưu vị trí của màn hình và con trỏ. Nó không sử dụng :normal
các lệnh nữa, nhưng gọi hàm winsaveview()
và winrestview()
. Bằng cách loại bỏ :normal
, vì một mục đích khác, họ cũng đã khắc phục vấn đề bạn mô tả trước đó, vì v:count1
không được sửa đổi nữa. Mặc dù nó có thể trong tương lai nếu một số lệnh được thêm vào giữa hàm.
]%
nhảy đến )
s và không có gì khác.
Đến cuối s:MultiMatch()
hàm, dòng 722 , mẫu mô tả phần cuối của một nhóm mã thông báo được định nghĩa như sau:
let closepat = substitute(closepat, ',', '\\|', 'g')
Mục đích của việc thay thế là để thay thế mỗi dấu phẩy, phân tách 2 nhóm mã thông báo liên tiếp, với một thanh thoát kép sẽ được giải thích bởi công cụ regex của Vim như một sự thay thế (tách giữa 2 nhánh). Tôi nghĩ rằng sự thay thế cũng nên thay thế các dấu hai chấm :
tách các mã thông báo bên trong mỗi nhóm. Vì vậy, bạn có thể viết lại thay thế như thế này:
let closepat = substitute(closepat, '[,:]', '\\|', 'g')
Với thay đổi này, ]%
nên di chuyển con trỏ trên các mã thông báo khác nhau được mô tả trong b:match_words
và &l:matchpairs
, không chỉ )
. Ít nhất, nó làm trên máy của tôi.
va%
hành xử giống hệt [%
trong ví dụ này và không chọn bất cứ điều gì.
Với các thay đổi trước đó, đặc biệt là lần thứ 2, va%
nên chọn văn bản giữa 2 mã thông báo xung quanh. Mặc dù, plugin dường như coi phần giữa của một nhóm mã thông báo (như else
trong if|else|endif
) là phần kết thúc (nó được chuyển searchpair()
qua đối số thứ 3 chứ không phải thứ 2). Vì vậy, những gì nó được coi là mã thông báo xung quanh đôi khi có thể làm bạn ngạc nhiên.
Tuy nhiên, neovim va%
((( )))
không "mở rộng" sau khi lặp lại a%
. Tôi không chắc nếu vim đã từng làm, nhưng tôi nên làm vậy. giống như a(
.
Hiện tại, ánh xạ trực quan a%
được xác định trên dòng 71 như thế này:
vmap a% <Esc>[%v]%
Khi tôi thêm o
vào đầu {rhs}
, để di chuyển con trỏ đến đầu lựa chọn ( :h v_o
), tôi nhận được hành vi mà bạn muốn:
vmap a% o<Esc>[%v]%
Đây là phiên bản của matchit
plugin, với 3 thay đổi nhỏ được mô tả cho đến nay.
Và đây là một cái khác mà tôi đã cố gắng bao gồm PR # 5124 từ Neovim.
Nếu bạn muốn kiểm tra mã trên máy của mình, nhưng bạn không có quyền thay đổi matchit
plugin mặc định (hoặc bạn không muốn), bạn có thể tạo tệp ~/.vim/plugin/matchit.vim
và viết matchit
plugin thử nghiệm của mình ở đó.
Vì trong runtimepath, ~/.vim
xuất hiện trước $VIMRUNTIME
, Vim nên tìm nguồn phiên bản tùy chỉnh của bạn trước phiên bản mặc định. Và kể từ đó, plugin mặc định có bảo vệ:
if exists("loaded_matchit") || &cp
finish
endif
let loaded_matchit = 1
... chỉ phiên bản của bạn nên có nguồn gốc đầy đủ.
]%
hầu như không có gì. Tôi sẽ phải xem mã.