選択時に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以上の他の多くの改良と一緒に)。
マス

これを作成してくれてありがとう!やってみます。
ルークデイビス

回答:


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 YngveLervåg16年

1
@KarlYngveLervåg良い点。それはまだ比較的新しい機能(v7.4.330だと思います)であり、一度お尻を噛んだので、無意識のうちにそれを避けました。回答を更新して使用します。
トミーA

これは完全に完璧です。どうもありがとう!Vimscriptの良い習慣も。各行を理解しようとします。あなたがこの種のユーティリティを最初に書いたなら、これはかなり人気があると思います。
ルークデイビス

@LukeDavisこれから気付いた望ましくない影響があります。ジャンプリストが台無しになります。私は<c-o>、一致が見つかった回数を使用して、ある方法でそれを修正する方法を考え出しました。問題は、ウィンドウの先頭行をジャンプリストに追加するmatchit.vimにバグがあることです。 それは認められましたが、それを修正するための急ぎはないようです。
トミーA

@TommyAねえ、このユーティリティにもう一度感謝します。私のコンピューターでは、CursorMove autocmdによる遅延はごくわずかです。s:get_match_lines(line)無限ループを防ぐために関数を更新しました。これは、特定の奇妙なコンテキストで私にとって大きな問題になりました。残念ながらmatchit.vim欠陥がたくさんあります。上記の私の編集を見て、何か提案があれば私に知らせてください。私はvimscriptの初心者です。
ルークデイビス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.