Làm cách nào tôi có thể làm nổi bật các tên%% phù hợp (ví dụ if / end, for / end) được xác định bởi matchit.vim trên vùng chọn?


10

Hiện tại Vim của tôi làm nổi bật các dấu ngoặc đơn, ngoặc vuông, dấu ngoặc kép, v.v. với nền Cyan và nền trước màu trắng - con trỏ có thể được di chuyển giữa các dấu này với %. Nhờ vào matchit.vim của tôi, tôi cũng có thể chuyển đổi %giữa if / end, for / end, v.v. - tuy nhiên những thứ này không được tô sáng trên vùng chọn.

Làm cách nào tôi có thể tự động làm nổi bật các cặp kết hợp này khi lựa chọn, như được tự động thực hiện với dấu ngoặc đơn?

Hơn nữa, làm thế nào tôi có thể sửa đổi màu nền được sử dụng cho các cặp này bằng cách sử dụng :highlight?

Cảm ơn trước.


Tôi đã cập nhật câu trả lời của @T Mom A bên dưới để giải thích cho matchit.vimcác nhóm được chỉ định kém và các tình huống khác mà %nhà điều hành không trả con trỏ về vị trí ban đầu. Kiểm tra sự khác biệt trong vòng lặp "while". Bất cứ ai đọc chủ đề này đều được khuyên nên sử dụng phiên bản này, để tránh các vòng lặp vô hạn:

function! s:get_match_lines(line) abort
  " Loop until `%` returns the original line number; abort if
  " (1) the % operator keeps us on the same line, or
  " (2) the % operator doesn't return us to the same line after some nubmer of jumps
  let a:tolerance=25
  let a:badbreak=1
  let a:linebefore=-1
  let lines = []
  while a:tolerance && a:linebefore != line('.')
    let a:linebefore=line('.')
    let a:tolerance-=1
    normal %
    if line('.') == a:line
      " Note that the current line number is never added to the `lines`
      " list. a:line is the input argument 'line'; a is the FUNCTION BUFFER
      let a:badbreak=0
      break
    endif
    call add(lines, line('.'))
  endwhile
  "Return to original line no matter what, return list of lines to highlight
  execute "normal ".a:line."gg"
  if a:badbreak==1
    return []
  else
    return lines
  endif
endfunction

function! s:hl_matching_lines() abort
  " `b:hl_last_line` prevents running the script again while the cursor is
  " moved on the same line.  Otherwise, the cursor won't move if the current
  " line has matching pairs of something.
  if exists('b:hl_last_line') && b:hl_last_line == line('.')
    return
  endif
  let b:hl_last_line = line('.')
  " Save the window's state.
  let view = winsaveview()
  " Delete a previous match highlight.  `12345` is used for the match ID.
  " It can be anything as long as it's unique.
  silent! call matchdelete(12345)
  " Try to get matching lines from the current cursor position.
  let lines = s:get_match_lines(view.lnum)
  if empty(lines)
    " It's possible that the line has another matching line, but can't be
    " matched at the current column.  Move the cursor to column 1 to try
    " one more time.
    call cursor(view.lnum, 1)
    let lines = s:get_match_lines(view.lnum)
  endif
  if len(lines)
    " Since the current line is not in the `lines` list, only the other
    " lines are highlighted.  If you want to highlight the current line as
    " well:
    " call add(lines, view.lnum)
    if exists('*matchaddpos')
      " If matchaddpos() is availble, use it to highlight the lines since it's
      " faster than using a pattern in matchadd().
      call matchaddpos('MatchLine', lines, 0, 12345)
    else
      " Highlight the matching lines using the \%l atom.  The `MatchLine`
      " highlight group is used.
      call matchadd('MatchLine', join(map(lines, '''\%''.v:val.''l'''), '\|'), 0, 12345)
    endif
  endif
  " Restore the window's state.
  call winrestview(view)
endfunction
function! s:hl_matching_lines_clear() abort
  silent! call matchdelete(12345)
  unlet! b:hl_last_line
endfunction

" The highlight group that's used for highlighting matched lines.  By
" default, it will be the same as the `MatchParen` group.
highlight default link MatchLine MatchParen
augroup matching_lines
  autocmd!
  " Highlight lines as the cursor moves.
  autocmd CursorMoved * call s:hl_matching_lines()
  " Remove the highlight while in insert mode.
  autocmd InsertEnter * call s:hl_matching_lines_clear()
  " Remove the highlight after TextChanged.
  autocmd TextChanged,TextChangedI * call s:hl_matching_lines_clear()
augroup END

2
Tôi biết đây là một câu hỏi cũ, nhưng tôi chỉ thấy nó hiện lên trên trang nhất một lúc trước. Chỉ muốn đề cập đến kết hợp plugin mới của tôi được thiết kế để thực hiện chính xác điều này, theo cách mạnh mẽ hơn: github.com/andymass/vim-matchup (cùng với nhiều cải tiến khác so với matchit).
Thánh lễ

Trông thật hữu ích, cảm ơn vì đã làm điều này! Tôi se thử no.
Luke Davis

Câu trả lời:


12

Tôi nghĩ ý tưởng này là thú vị, vì vậy tôi đã cho nó một shot. Nó sẽ đặc biệt hữu ích trong các tệp dày đặc, chẳng hạn như HTML.

đường khớp

Kịch bản sau đây chỉ đơn giản cho phép matchit.vimthực hiện những gì nó làm trong khi ghi lại số dòng. Giải thích là trong các ý kiến ​​của kịch bản.

matchlines.vim

function! s:get_match_lines(line) abort
  let lines = []

  " Loop until `%` returns the original line number
  while 1
    normal %
    if line('.') == a:line
      " Note that the current line number is never added to the `lines`
      " list.
      break
    endif
    call add(lines, line('.'))
  endwhile

  return lines
endfunction

function! s:hl_matching_lines() abort
  " `b:hl_last_line` prevents running the script again while the cursor is
  " moved on the same line.  Otherwise, the cursor won't move if the current
  " line has matching pairs of something.
  if exists('b:hl_last_line') && b:hl_last_line == line('.')
    return
  endif

  let b:hl_last_line = line('.')

  " Save the window's state.
  let view = winsaveview()

  " Delete a previous match highlight.  `12345` is used for the match ID.
  " It can be anything as long as it's unique.
  silent! call matchdelete(12345)

  " Try to get matching lines from the current cursor position.
  let lines = s:get_match_lines(view.lnum)

  if empty(lines)
    " It's possible that the line has another matching line, but can't be
    " matched at the current column.  Move the cursor to column 1 to try
    " one more time.
    call cursor(view.lnum, 1)
    let lines = s:get_match_lines(view.lnum)
  endif

  if len(lines)
    " Since the current line is not in the `lines` list, only the other
    " lines are highlighted.  If you want to highlight the current line as
    " well:
    " call add(lines, view.lnum)
    if exists('*matchaddpos')
      " If matchaddpos() is availble, use it to highlight the lines since it's
      " faster than using a pattern in matchadd().
      call matchaddpos('MatchLine', lines, 0, 12345)
    else
      " Highlight the matching lines using the \%l atom.  The `MatchLine`
      " highlight group is used.
      call matchadd('MatchLine', join(map(lines, '''\%''.v:val.''l'''), '\|'), 0, 12345)
    endif
  endif

  " Restore the window's state.
  call winrestview(view)
endfunction

function! s:hl_matching_lines_clear() abort
  silent! call matchdelete(12345)
  unlet! b:hl_last_line
endfunction


" The highlight group that's used for highlighting matched lines.  By
" default, it will be the same as the `MatchParen` group.
highlight default link MatchLine MatchParen

augroup matching_lines
  autocmd!
  " Highlight lines as the cursor moves.
  autocmd CursorMoved * call s:hl_matching_lines()
  " Remove the highlight while in insert mode.
  autocmd InsertEnter * call s:hl_matching_lines_clear()
  " Remove the highlight after TextChanged.
  autocmd TextChanged,TextChangedI * call s:hl_matching_lines_clear()
augroup END

Tôi không thực sự thích điều này xảy ra trên CursorMoved, mặc dù. Tôi nghĩ rằng nó tốt hơn khi là bản đồ chính có thể được sử dụng khi tôi cần:

nnoremap <silent> <leader>l :<c-u>call <sid>hl_matching_lines()<cr>

Bạn có thể sử dụng matchaddposchức năng thay thế. Nó nhanh hơn một chút và nếu bạn làm nổi bật toàn bộ dòng dù sao, nó sẽ đơn giản hóa mọi thứ một chút.
Karl Yngve Lervåg

1
@ KarlYngveLervåg Điểm tốt. Tôi vô tình tránh nó bởi vì nó vẫn là một chức năng tương đối mới (v7.4.330 tôi nghĩ) và nó cắn tôi một lần. Tôi sẽ cập nhật câu trả lời để sử dụng nó.
Tommy A

Điều này là hoàn toàn hoàn hảo, cảm ơn rất nhiều! Thực hành Vimscript tốt quá; sẽ cố gắng để hiểu từng dòng. Tôi tưởng tượng điều này có thể khá phổ biến nếu bạn là người đầu tiên viết loại tiện ích này.
Luke Davis

@LukeDavis Có một hiệu ứng không mong muốn xuất phát từ điều này mà tôi nhận thấy: nó sẽ làm hỏng danh sách nhảy. Tôi đã nghĩ ra một cách để khắc phục nó bằng cách sử dụng <c-o>số lần tìm thấy trận đấu và nó hoạt động theo cách. Vấn đề là có một lỗi trong matchit.vim có thêm dòng trên cùng của cửa sổ vào danh sách nhảy. Nó đã được thừa nhận , nhưng dường như không có bất kỳ sự vội vàng nào để sửa nó.
Tommy A

@TommyA Này, cảm ơn lần nữa vì tiện ích này. Tôi thực sự tìm thấy trên máy tính của mình độ trễ với autocmd CthonMove là không đáng kể. Tôi đã cập nhật chức năng của bạn s:get_match_lines(line)để giúp bảo vệ chống lại các vòng lặp vô hạn, điều đang trở thành một vấn đề lớn đối với tôi trong những bối cảnh kỳ lạ nhất định. Thật không may matchit.vimlà đầy sai sót. Xem chỉnh sửa của tôi ở trên và cho tôi biết nếu bạn có bất kỳ đề xuất nào; Tôi là người mới bắt đầu vimscript.
Luke Davis
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.