Matchit.vim [%,]%,% làm gì?


7

Matchit là %/ g%đủ đơn giản để sử dụng, nhưng tôi gặp khó khăn khi hiểu các ánh xạ khác, nghe có vẻ hữu ích nhưng dường như không hoạt động theo bất kỳ cách dễ hiểu nào.

]%  Go to [count] next unmatched group, as specified by
    |b:match_words|.  Similar to |]}|.

Tôi hy vọng điều này có thể cho phép tôi nhảy tới endif, endfunctionv.v. Lấy ví dụ về vimscript sau, sử dụng vim ftplugin tích hợp ( b:match_wordsdường như được đặt.)

function! SuperTab()
  let l:part = strpart(getline('.'),col('.')-2,1)
  if (l:part=~'^\W\?$')
      return "\<Tab>"
  else
      return "\<C-n>"
  endif
endfunction

[%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 ifvà hoàn toàn bỏ qua (s. ]%nhảy đến )s và không có gì khác. va%hành xử giống hệt [%trong ví dụ này và không chọn bất cứ điều gì. Đây có phải là hành vi bình thường? Có một số ví dụ mà những ánh xạ này có ý nghĩa?


1
Câu hỏi hay! Tôi nghĩ tôi sẽ kích hoạt nó và đưa ra câu trả lời nhưng tôi cũng bối rối như bạn. Theo như tôi có thể thấy ]%hầu như không có gì. Tôi sẽ phải xem mã.
Lớp B

Tôi nghĩ rằng nó có thể chỉ là lỗi. Theo như tôi có thể nói từ các tài liệu và ý kiến ​​trong mã, nó sẽ hoạt động như bạn đề xuất. Có thể ai đó (@BLayer? Hoặc có thể là tôi!) Sẽ xem mã thực tế và cho bạn biết lý do / làm thế nào nó sai.
Giàu

Tôi sẽ cố gắng trả lời vào cuối tuần này. Tôi đã chọc lại một lúc và chắc chắn rằng nó đã bị lỗi rất nhiều nhưng tôi đã không gỡ lỗi ở bất kỳ độ sâu nào.
Lớp B

Tôi chỉ cố gắng của neovim matchit trong vim (đáng ngạc nhiên là khác với vim) và nó dường như làm việc .. lạ github.com/neovim/neovim/blob/master/runtime/plugin/matchit.vim
Thánh lễ

1
Tuy nhiên, neovim va% ((( )))không "mở rộng" sau khi lặp lại a%. Tôi không chắc là vim đã từng làm chưa, nhưng imo nó nên như vậy a(.
Thánh lễ

Câu trả lời:


6

Tôi sẽ giả định rằng bạn sử dụng matchitphiê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 ifvà 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 whilevò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ố :normallệ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 cdvà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.0bả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 :normalcá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

nhập mô tả hình ảnh ở đây


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 matchitviệ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 :normalcác lệnh nữa, nhưng gọi hàm winsaveview()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:count1khô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&l:matchpairs, không chỉ ). Ít nhất, nó làm trên máy của tôi.

nhập mô tả hình ảnh ở đây


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ư elsetrong 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 ovà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]%

nhập mô tả hình ảnh ở đây


Đây là phiên bản của matchitplugin, 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 matchitplugin mặc định (hoặc bạn không muốn), bạn có thể tạo tệp ~/.vim/plugin/matchit.vimvà viết matchitplugin thử nghiệm của mình ở đó.

Vì trong runtimepath, ~/.vimxuấ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 đủ.


vui lòng mở các sự cố cho các sự cố khác nhau mà bạn đã khắc phục tại github.com/chrisbra/matchit
Christian Brabandt

@ChristianBrabandt Ok, tôi đã mở 2 vấn đề để thảo luận ]%v_a%ánh xạ có thể thay đổi một chút.
dùng852573

Câu trả lời tuyệt vời! Tôi hơi ngạc nhiên khi rõ ràng ít người sử dụng các tính năng này, nhưng tôi vui vì chúng ta có thể hiểu những gì đang diễn ra.
Thánh lễ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.