I came up with a vimscript solution which seems to work (at least according to my quick tests). This is a workaround and it clearly has a lot of place for improvements.
- It changes the color of the status line using the
:highlight
command so obviously you need to have set laststatus=2
.
- It uses some global variables, theirs scope could be limited and I think they could even be eliminated.
- It also uses the autocommand events
CmdlineEnter
and CmdlineLeave
which are included only in recent vim version.
- I haven't tested the code with complex searches I don't know how well it behaves with complex regexes and escaped characters.
Anyway the idea was mainly to create a proof of concept, not a complete feature.
Add this to your vimrc
(actually you should put the function in an autoload directory but that's not the point of the question):
function! HighlightSearch(timer)
" When it is the first call to the function we save the current status of
" the StatusLine HL group so that we can restore it when we are done searching
if (g:firstCall)
let g:originalStatusLineHLGroup = execute("hi StatusLine")
let g:firstCall = 0
endif
if (exists("g:searching") && g:searching)
" The variable g:searching is set to 1, we are in the search command line
" make the highlighting and call the function again after a delay
let searchString = escape(getcmdline(), ' \')
let newBG = search(searchString) != 0 ? "green" : "red"
execute("hi StatusLine ctermbg=" . newBG)
let g:highlightTimer = timer_start(300, 'HighlightSearch')
else
" The variable g:searching is either not set or set to 0, we stopped searching
" restore the hightlighting and stop calling the function
let originalBG = matchstr(g:originalStatusLineHLGroup, 'ctermbg=\zs[^ ]\+')
execute("hi StatusLine ctermbg=" . originalBG)
if exists("g:highlightTimer")
call timer_stop(g:highlightTimer)
endif
endif
endfunction
" Define an autocmd to call the HighLightSearch function when we enter the search command line
" And a second one to stop the function when we are done searching
augroup betterSeachHighlighting
autocmd!
autocmd CmdlineEnter * if (index(['?', '/'], getcmdtype()) >= 0) | let g:searching = 1 | let g:firstCall = 1 | call timer_start(1, 'HighlightSearch') | endif
autocmd CmdlineLeave * let g:searching = 0
augroup END
The idea is to create two autocommands:
- The first one is triggered when you enter the command line, it test if you are searching for something (
/
or ?
in opposition to :
), it sets two variables used by the function and call the function.
- The second one is triggered when you leave the command line, it is used to unset a variable which is used by the function.
The function does three things:
- It keeps in memory the original highlighting group of the status line to be able to restore it (Using this answer).
- If you are searching for something it looks for a match, updates the background of the status line accordingly and set a timer to call itself again a few milliseconds later to update the background again.
- If you are not searching for something anymore it resets the status line highlighting.
Here are some relevant help topic (I'll try to upload a gif of the code in action when I can):