선택시 matchit.vim에 의해 정의 된 일치하는“%”이름 (예 : if / end, for / end)을 어떻게 강조 표시합니까?


10

현재 내 Vim은 시안 색 배경 및 흰색 전경으로 일치하는 괄호, 괄호, 따옴표 등을 강조 표시합니다. 커서를로 사이를 이동할 수 있습니다 %. matchit.vim 덕분에 %if / end, for / end 등으로 전환 할 수도 있지만 선택시 강조 표시되지는 않습니다.

괄호로 자동으로 수행되는 것처럼 선택시 이러한 일치하는 쌍을 자동으로 강조 표시하는 방법은 무엇입니까?

또한 :highlight?를 사용하여 이러한 쌍에 사용되는 배경색을 어떻게 수정할 수 있습니까?

미리 감사드립니다.


아래의 @Tommy A에 의해 답변이 잘못 지정되어 matchit.vim그룹이 잘못 지정 되고 %운영자가 커서를 원래 위치 로 되 돌리지 않는 다른 상황 을 설명했습니다. "while"루프의 차이점을 확인하십시오. 이 스레드를 읽는 사람은 무한 루프를 피하기 위해이 버전을 사용하는 것이 좋습니다.

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
나는 이것이 오래된 질문이라는 것을 알고 있지만 잠시 전에 첫 페이지에 팝업으로 나타나는 것을 보았습니다. : 그냥 내 새로운 플러그인 매치 업이보다 강력한 방법으로, 정확하게이 작업을 수행 할 수 있도록 설계되었습니다 언급 할 github.com/andymass/vim-matchup (matchit을 통해 많은 개선과 함께 참조).
Mass

이것을 만들어 주셔서 감사합니다 정말 유용합니다! 시도해 볼게요.
Luke Davis

답변:


12

나는이 아이디어가 흥미 로웠다고 생각했다. HTML과 같은 밀도가 높은 파일에 특히 유용합니다.

매치 라인

다음 스크립트는 단순히 matchit.vim행 번호를 기록하는 동안 수행하는 작업을 수행합니다. 스크립트 주석에 설명이 있습니다.

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

그래도 이런 일이 싫습니다 CursorMoved. 필요할 때 사용할 수있는 키 맵이 더 낫다고 생각합니다.

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

matchaddpos대신 함수를 사용할 수 있습니다 . 약간 빠르며 어쨌든 전체 라인을 강조 표시하면 상황이 약간 단순화됩니다.
Karl Yngve Lervåg

1
@ KarlYngveLervåg 좋은 지적입니다. 나는 여전히 상대적으로 새로운 기능이기 때문에 무의식적으로 피합니다 (v7.4.330 생각합니다). 답변을 업데이트하여 사용하겠습니다.
Tommy A

정말 고마워요! 좋은 Vimscript 연습도; 각 줄을 이해하려고 노력할 것입니다. 이런 종류의 유틸리티를 처음 쓰는 사람이라면 이것이 인기가있을 것 같습니다.
Luke Davis

@LukeDavis 내가 알았던 것에서 원하지 않는 효과가 있습니다 : 점프 목록을 망칠 것입니다. 나는 <c-o>경기가 발견 된 횟수만큼 사용하여 그것을 고칠 수있는 방법을 찾았으며 어떤 방식으로 작동합니다. 문제는 matchit.vim에 창의 맨 윗줄을 점프 목록에 추가하는 버그가 있다는 것입니다. 그것은 인정 되었지만 그것을 고칠 서두르지 않는 것 같습니다.
Tommy A

@TommyA이 유틸리티에 다시 한번 감사드립니다. 나는 실제로 내 컴퓨터에서 CursorMove autocmd의 지연이 무시할 만하다는 것을 알았습니다. s:get_match_lines(line)무한 루프를 방지하기 위해 함수 를 업데이트하여 특정 이상한 상황에서 큰 문제가되었습니다. 불행히도 matchit.vim결함이 가득합니다. 위의 편집 내용을 참조하고 제안 사항이 있으면 알려주십시오. 저는 vimscript 초보자입니다.
Luke Davis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.