1

I need to create regex in VIM (for plugin purpose) which would work as follows:

Expected behavior:

|| characters indicate current cursor position, bold words indicate matching words


Example nr 1:

  1. foo bar foo bar
  2. foo b|a|r foo bar
  3. foo bar foo bar

Two bars from first line match. First bar from the second line does not match because the cursor is currently placed on it. Second bar in the second line do match. Two bars from third line match.


Example nr 2:

  1. foo bar foo bar
  2. foo bar foo bar
  3. fo|o| bar foo bar

Two foos from first line match. Two foos from the second line match. First foo from the third line does no match as the cursor is currently placed on it. Second foo from the third line do match.


So I was tinkering a bit with it and I managed to create the regex which will match all words like one under the cursor:

" putting word under cursor into variable
let current_word = expand('<cword>')
" regex matching all words like one under cursor
'\k*\<\V'.current_word.'\m\>\k*'

I can not figure out how to exclude word under cursor from matches.

I found this special character \%# which according to VIM help

Matches with the cursor position. (...)

Yet I couldn't figure out how to use it in my case. Any ideas?

1 Answer 1

2

\%# will always track the cursor's position, but it will only work when matching text in the window. If that's what you want, this is the pattern to use:

\%(\k*\%#\k*\)\@!\<bar\>

It matches any bar, but excludes any word that's under the cursor. Using this in a / search will jump to the first match, which will seem strange if the cursor is currently over bar.

You can use this pattern in :match if you just want to highlight all occurrences of <cword> that aren't under the cursor:

autocmd CursorMoved * execute 'match Error /\%(\k*\%#\k*\)\@!\<' . expand('<cword>') . '\>/' 

If you want to match <cword> at the time of the search, you will need to create a more complicated pattern:

function! s:search_allbut_cword() abort
  let p1 = searchpos('\<.', 'nbcW')
  let p2 = searchpos('.\>', 'ncW')
  return '/\%(\%' . p1[0] . 'l'
        \. '\%>' . (p1[1] - 1) . 'c'
        \. '\%<' . (p2[1] + 1) . 'c\)'
        \. '\@!\<' . expand('<cword>') . '\>' . "\<cr>"
endfunction

nnoremap <expr> <leader>* <sid>search_allbut_cword()

p1 is the position at the beginning of <cword> and p2 is the end. With those, it creates a pattern that matches <cword> except on the current line between two columns. This slightly flawed since it doesn't accurately account for changes made in the excluded region.

1

Your Answer

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

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