I have the following function in a vim plugin:

fu! HOLSelect(l,r)
  let l:cursor = getpos(".")
  if search(a:l,"Wbc") == 0
  normal v
  if search(a:r,"W") == 0
    normal <ESC>
    call setpos('.', l:cursor)
  call search(a:r,"ce")

I am trying to understand it without a deep vimscript knowledge.

When it is called the following way:

nn <silent> <LocalLeader>a :call HOLSelect('Triviality\\|Theorem','Proof')<CR>-Vo+

It visually selects the region between (not including) the lines Triviality or Theorem and Proof. These stand on their own in the file:

  ∀ P. P ==> P
    rw []

I see two search calls but it is not clear how it selects the region between the two endpoints.

Could you explain how this function selects the region's two endpoints between Theorem and Proof and passes it on?

  • 2
    3 search calls, and one normal v (that should really be normal! for portability though)
    – D. Ben Knoble
    Mar 18, 2021 at 13:31
  • Probably worth noting for future readers that :normal <ESC> is a bug.
    – Rich
    Mar 18, 2021 at 14:58
  • Seems like an overly complicated way to go about things. search() returns line number. Store the first line number in variable start and the second in end and then you could just do exe start+1 | exe "normal V" | exe end-1 or equivalent....to name just the first idea that came to mind. But perhaps I'm missing some nuance or something not shown here.
    – B Layer
    Mar 19, 2021 at 2:46
  • I meant, "normal! V", of course.
    – B Layer
    Mar 19, 2021 at 2:54

1 Answer 1


There are a few tricky bits here so lets break this down into components.


This will search for the pattern backwards (b flag). It uses the W to prevent wrapping around the file and c to accept a search at the current position. This will in affect find the beginning of the pattern and move the cursor there. e.g. Theorem in this case with the cursor on the T


This will search for the pattern forwards and put the cursor at the start of the match. The W flag to prevent wrapping around the file. e.g. Proof in this case with the cursor on the P.

call search(a:r,"ce")

This will move the cursor to the end of a match (e flag) and accept a match at the current position (c flag). e.g. Set the cursor on top of the f in Proof

With these searches together we can find the start and the end of the patterns. It uses :normal v to make a visual selection.

The next trick is how it selects the part in-between the matches. The mapping is what does this via -Vo+

  • - go to the start of the previous line
  • V use visual-line mode
  • o switch to the other end of the visual selection. The start in this case
  • + go the the start of the next line

The rest of the code and flow control is designed to handle errors when a pattern is not found

  • What made this hard to understand was that it had used visual selection twice, once in the function and once after the function.
    – Gergely
    Mar 18, 2021 at 13:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.