Wie kann ich übereinstimmende% -Namen (z. B. if / end, for / end) hervorheben, die bei der Auswahl von matchit.vim definiert wurden?

10

Derzeit hebt mein Vim übereinstimmende Klammern, Klammern, Anführungszeichen usw. mit Cyan-Hintergrund und weißem Vordergrund hervor - der Cursor kann mit diesen zwischen diesen bewegt werden %. Dank meiner matchit.vim kann ich auch %zwischen if / end, for / end usw. wechseln - diese werden jedoch bei der Auswahl nicht hervorgehoben.

Wie kann ich diese übereinstimmenden Paare bei der Auswahl automatisch hervorheben, wie dies automatisch mit Klammern geschieht?

Wie kann ich außerdem die Hintergrundfarbe ändern, die für diese Paare verwendet wird :highlight?

Danke im Voraus.


Ich habe die Antwort von @Tommy A unten aktualisiert , um schlecht spezifizierte matchit.vimGruppen und andere Situationen zu berücksichtigen , in denen der %Bediener den Cursor niemals an die ursprüngliche Position zurückbringt. Überprüfen Sie die Unterschiede in der "while" -Schleife. Jedem, der diesen Thread liest, wird empfohlen, diese Version zu verwenden, um Endlosschleifen zu vermeiden:

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
Luke Davis
quelle
2
Ich weiß, dass dies eine alte Frage ist, aber ich habe sie erst vor einem Moment auf der Titelseite gesehen. Ich möchte nur erwähnen, dass mein neues Plugin-Match-up genau dafür ausgelegt ist: robuster: github.com/andymass/vim-matchup (zusammen mit vielen anderen Verbesserungen gegenüber Matchit).
Messe
Sieht wirklich nützlich aus, danke dafür! Ich werde es ausprobieren.
Luke Davis

Antworten:

12

Ich fand diese Idee interessant und habe sie ausprobiert. Dies ist besonders nützlich in dichten Dateien wie HTML.

Linien abgleichen

Mit dem folgenden Skript können Sie einfach das matchit.vimtun, was es tut, während Sie die Zeilennummern aufzeichnen. Erklärungen finden Sie in den Kommentaren des Skripts.

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

Ich mag das allerdings nicht wirklich CursorMoved. Ich denke, es ist besser als eine Schlüsselkarte, die verwendet werden kann, wenn ich sie brauche:

nnoremap <silent> <leader>l :<c-u>call <sid>hl_matching_lines()<cr>
Tommy A.
quelle
Sie matchaddposkönnen stattdessen die Funktion verwenden. Es ist etwas schneller und wenn Sie trotzdem die gesamte Linie hervorheben, wird es die Dinge ein wenig vereinfachen.
Karl Yngve Lervåg
1
@ KarlYngveLervåg Guter Punkt. Ich vermeide es unbewusst, weil es immer noch eine relativ neue Funktion ist (v7.4.330, glaube ich) und mich einmal in den Arsch gebissen hat. Ich werde die Antwort aktualisieren, um sie zu verwenden.
Tommy A
Das ist absolut perfekt, vielen Dank! Gute Vimscript-Praxis auch; werde versuchen, jede Zeile zu verstehen. Ich kann mir vorstellen, dass dies sehr beliebt sein könnte, wenn Sie als erster diese Art von Dienstprogramm schreiben.
Luke Davis
@LukeDavis Daraus ergibt sich ein unerwünschter Effekt, der mir aufgefallen ist: Er wird die Sprungliste durcheinander bringen. Ich habe mir eine Möglichkeit ausgedacht, das Problem zu beheben, indem ich die Häufigkeit verwendet habe, mit <c-o>der eine Übereinstimmung gefunden wurde, und die in gewisser Weise funktioniert. Das Problem ist, dass es in matchit.vim einen Fehler gibt, der die oberste Zeile des Fensters zur Sprungliste hinzufügt. Es wurde anerkannt , aber es scheint keine Eile zu geben, es zu beheben.
Tommy A
@ TommyA Hey, nochmals vielen Dank für dieses Dienstprogramm. Ich finde auf meinem Computer tatsächlich, dass die Verzögerung mit dem CursorMove-Autocmd ziemlich vernachlässigbar ist. Ich habe Ihre Funktion aktualisiert s:get_match_lines(line), um mich vor Endlosschleifen zu schützen, was in bestimmten seltsamen Kontexten zu einem großen Problem für mich wurde. Ist leider matchit.vimvoller Mängel. Sehen Sie sich meine Bearbeitung oben an und lassen Sie mich wissen, wenn Sie Vorschläge haben. Ich bin ein Vimscript-Anfänger.
Luke Davis