ฉันจะไฮไลต์ชื่อการจับคู่“%” (เช่น if / end, for / end) ที่กำหนดโดย matchit.vim ในการเลือกได้อย่างไร


10

ปัจจุบัน Vim ของฉันเน้นการจับคู่วงเล็บ, เครื่องหมายคำพูด, ฯลฯ ด้วยพื้นหลังสีฟ้าและพื้นหน้าสีขาว - เคอร์เซอร์สามารถเลื่อนไปมาระหว่างสิ่งเหล่านี้%ได้ ขอบคุณ matchit.vim ของฉันฉันยังสามารถสลับกับ%ระหว่าง if / end for / end ฯลฯ - อย่างไรก็ตามสิ่งเหล่านี้ไม่ได้เน้นที่การเลือก

ฉันจะไฮไลต์คู่จับคู่เหล่านี้โดยอัตโนมัติเมื่อเลือกได้อย่างไรเช่นจะทำในวงเล็บโดยอัตโนมัติ

นอกจากนี้ฉันจะแก้ไขสีพื้นหลังที่ใช้สำหรับคู่เหล่านี้ได้:highlightอย่างไร

ขอบคุณล่วงหน้า.


ฉันได้อัปเดตคำตอบโดย @Tommy A ด้านล่างเพื่อบัญชีสำหรับmatchit.vimกลุ่มที่ระบุไม่ดีและสถานการณ์อื่น ๆ ที่%ผู้ประกอบการไม่ได้กลับเคอร์เซอร์ไปที่ตำแหน่งเดิมเคย ตรวจสอบความแตกต่างในการวนรอบ "ในขณะที่" ใครก็ตามที่อ่านหัวข้อนี้ควรใช้เวอร์ชั่นนี้เพื่อหลีกเลี่ยงการวนซ้ำไม่ จำกัด :

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 Yngve Lervåg

1
@ KarlYngveLervågจุดที่ดี ฉันหลีกเลี่ยงโดยไม่รู้ตัวเพราะมันยังคงเป็นฟังก์ชั่นที่ค่อนข้างใหม่ (ฉันคิดว่า v7.4.330) และมันทำให้ฉันรู้สึกอึดอัดใจในครั้งเดียว ฉันจะอัปเดตคำตอบเพื่อใช้งาน
Tommy 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.