선택시 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.