TL;DR For those in a hurry, not interested in the process/context, etc...jump to the last two code blocks, augroup procsearch
and function ProcSearch
. Copy those to your vimrc for a complete solution that works seamlessly with native search (as demonstrated in the GIF).
Haven't considered this before but I think I have the seed of a solution...
If you run this command after you've started the search then the match that the cursor is on should be highlighted differently (I've tested that this is so while cycling through matches with n
/N
)...
:exec 'match HI /\%#' . @/ . '/'
The key is \%#
which is pattern representing cursor position. (Note: if you enable 'ignorecase'
I think you'll need to add \c
to the beginning of this pattern.)
Replace HI
with whatever highlight group you prefer. (For testing with something highly visible you can try Error
.)
Disable the behavior with
:match none
Obviously you don't want to type that all in whenever you need it. The easiest thing to do is map it. Something like
:nnoremap <leader>n exec 'match HI /\%#' . @/ . '/'<CR>
Okay so we've established that you want this behavior every time you do a search. We need to overload the search operation so that the match command is invoked immediately after the usual business.
...
I removed my previous attempts at a solution since I've got a much better approach and this thing had gotten too long. Feel free to look at the history...if you're so inclined. ;)
...
Though I earlier bemoaned the lack of an autocommand event for search turns out there is such a thing it's just more general: CmdLineEnter
/CmdLineLeave
. And there is a way, once those events trigger, to distinguish between :
commands and search commands (/
or ?
) using special string <afile>
.
So now all we need is an autocommand that will call a function each time a search command is completed:
augroup procsearch
autocmd!
au CmdLineLeave * let b:cmdtype = expand('<afile>') | if (b:cmdtype == '/' || b:cmdtype == '?') | call timer_start(200, 'ProcessSearch') | endif
augroup END
I did the call asynchronously (timer_start()
) because otherwise the /
register wasn't set yet.
Here's the callback that calls the :match
command per usual, including proper 'ignorecase'
handling:
function! ProcessSearch(timerid)
let l:patt = '\%#' . @/
if &ic | let l:patt = '\c' . l:patt | endif
exe 'match SpellRare /' . l:patt . '/'
endfunc
And you can unmap <leader>/
...we don't need it anymore.
I don't always use the functional enhancements that I post as answers in my own config but this is useful enough that I believe I will. :)

Note: next steps would be to make this a little more robust. For instance, the event is triggered even when user aborts out of search with, e.g. Ctrl-C
, so we should check for that. Also, using a delay before calling the function is a little sketchy so that could be tightened up a bit. I'll probably leave these to readers...StackExchange is not about posting production-ready code it's about providing specific answers to specific question, IMO.