Bagaimana saya bisa menyorot nama "%" yang cocok (mis. Jika / end, untuk / end) ditentukan oleh matchit.vim pada pilihan?

10

Saat ini Vim saya menyoroti tanda kurung, tanda kurung, tanda kutip, dll. Dengan latar belakang Cyan dan latar depan putih - kursor dapat dipindahkan di antaranya %. Berkat matchit.vim saya, saya juga bisa beralih dengan %antara if / end, for / end, dll - namun ini tidak disorot pada pilihan.

Bagaimana saya bisa secara otomatis menyorot pasangan yang cocok ini pada seleksi, seperti dilakukan secara otomatis dengan tanda kurung?

Lebih lanjut, bagaimana saya bisa memodifikasi warna latar belakang yang digunakan untuk pasangan ini menggunakan :highlight?

Terima kasih sebelumnya.


Saya telah memperbarui jawaban oleh @Tommy A di bawah ini untuk memperhitungkan matchit.vimkelompok yang tidak ditentukan dengan baik , dan situasi lain di mana %operator tidak mengembalikan kursor ke posisi semula. Periksa perbedaan dalam loop "sementara". Siapa pun yang membaca utas ini disarankan untuk menggunakan versi ini, untuk menghindari loop tak terbatas:

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
sumber
2
Saya tahu ini adalah pertanyaan lama, tetapi saya baru saja melihatnya muncul di halaman depan beberapa saat yang lalu. Hanya ingin menyebutkan bahwa pencocokan plugin baru saya dirancang untuk melakukan hal ini, dengan cara yang lebih kuat: github.com/andymass/vim-matchup (bersama dengan banyak perbaikan lainnya pada matchit).
Misa
Terlihat sangat berguna, terima kasih sudah membuat ini! Saya akan mencobanya.
Luke Davis

Jawaban:

12

Saya pikir ide ini menarik, jadi saya mencobanya. Ini akan sangat berguna dalam file padat, seperti HTML.

mencocokkan garis

Script berikut hanya memungkinkan matchit.vimmelakukan apa yang dilakukannya saat merekam nomor baris. Penjelasan ada di komentar skrip.

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

Tapi aku tidak suka ini terjadi CursorMoved. Saya pikir lebih baik sebagai peta kunci yang dapat digunakan saat saya membutuhkannya:

nnoremap <silent> <leader>l :<c-u>call <sid>hl_matching_lines()<cr>
Tommy A
sumber
Anda bisa menggunakan matchaddposfungsi sebagai gantinya. Ini sedikit lebih cepat dan jika Anda tetap menyorot seluruh baris, itu akan menyederhanakan hal-hal sedikit.
Karl Yngve Lervåg
1
@ KarlYngveLervåg Poin bagus. Saya secara tidak sadar menghindarinya karena itu masih merupakan fungsi yang relatif baru (v7.4.330 saya pikir) dan itu menggigit saya sekali. Saya akan memperbarui jawaban untuk menggunakannya.
Tommy A
Ini sangat sempurna, terima kasih banyak! Praktek Vimscript yang baik juga; akan mencoba memahami setiap baris. Saya membayangkan ini bisa sangat populer jika Anda yang pertama menulis utilitas semacam ini.
Luke Davis
@LukeDavis Ada efek yang tidak diinginkan yang berasal dari ini yang saya perhatikan: itu akan mengacaukan daftar lompatan. Saya menemukan cara untuk mengatasinya dengan menggunakan <c-o>berapa kali kecocokan ditemukan dan berfungsi dengan cara. Masalahnya adalah ada bug di matchit.vim yang menambahkan baris atas jendela ke daftar lompatan. Sudah diakui , tetapi sepertinya tidak ada terburu-buru untuk memperbaikinya.
Tommy A
@TommyA Hei, terima kasih sekali lagi atas utilitas ini. Saya benar-benar menemukan di komputer saya penundaan dengan autocmd CursorMove cukup diabaikan. Saya memperbarui fungsi Anda s:get_match_lines(line)untuk membantu menjaga dari loop tak terbatas, yang menjadi masalah besar bagi saya dalam konteks aneh tertentu. Sayangnya matchit.vimpenuh dengan kekurangan. Lihat hasil edit saya di atas dan beri tahu saya jika Anda memiliki saran; Saya seorang pemula vimscript.
Luke Davis