Question

I know about :nohl and use it all the time, I also use easy motion so the highlight is not in my way when just moving to the search location. It gets in my way after pressing n or N.

I am looking for a way to disable the search highlight after 3 seconds of pressing n or N, also for completeness sake I would like a way to also disable it after searching e.g. /search_word<CR>.

Finally, it has to be a non-blocking command.

Thanks, I am slowly getting into vimscript but this one is out of my league since I haven't seen many examples of commands with timeouts out there.

EDIT:

After some of the comments and online research there are lots of indications there isn't a good way to do this with vimscript.

I am looking for a way to do this in a stable way with any language, e.g. Perl, Python, Ruby.

EDIT 2:

This is my solution based on @dhruva-sagar's response: (I marked his answer as correct because he gave me the skeleton for it).

augroup NoHLSearch
  au!
  autocmd CursorHold,CursorMoved * call <SID>NoHLAfter(4)
augroup END

function! s:NoHLAfter(n)
  if !exists('g:nohl_starttime')
    let g:nohl_starttime = localtime()
  else
    if v:hlsearch && (localtime() - g:nohl_starttime) >= a:n
      :nohlsearch
      redraw
      unlet g:nohl_starttime
    endif
  endif
endfunction
Was it helpful?

Solution

If you check :h :nohl, you will see that the command :nohl does not work within an autocmd, the reason being that vim saves & restores the search & search highlighting state after executing an autocmd. Hence technically it is not feasable to do so. The best way is to create a mapping like nnoremap <C-l> :nohlsearch<CR> and use it when you want to temporarily disable the search highlighting.

However there is a slight hack that i'd like to demonstrate that does work in a way like you expect by using set nohlsearch instead of nohlsearch, the downside of course is that it turns off search highlighting completely and you need to re-enable it using set hlsearch, so it isn't really a solution but it makes for a good example to demonstrate how one could perform time based operations within vim.

NOTE: This is more for educational purposes to demonstrate how you could do time based non-blocking tasks in vim. The performance of these could vary depending on what you do within the event triggered function.

augroup NoHLSearch
  au!

  autocmd CursorHold,CursorMoved * call <SID>NoHLAfter(3)
augroup END

function! s:NoHLAfter(n)
  if !exists('g:nohl_starttime')
    let g:nohl_starttime = localtime()
  else
    if v:hlsearch && (localtime() - g:nohl_starttime) >= a:n
      set nohlsearch
      unlet g:nohl_starttime
    endif
  endif
endfunction

OTHER TIPS

IMHO, a simpler and more predictable technique is the following:

noremap <silent><esc> <esc>:noh<CR><esc>

You're always hitting escape anyway, so it's a no-brainer to hit it when you want to clear hlsearch. In addition, you can choose to leave the matches highlighted if you want by not hitting an extra in normal mode.

The following will clear the search highlight after 'updatetime' milliseconds of inactivity. 'updatetime' defaults to 4000ms or 4s but I have set mine to 10s. It is important to note that 'updatetime' does more than just this so read the docs before you change it.

function! SearchHlClear()
    let @/ = ''
endfunction
autocmd CursorHold,CursorHoldI * call SearchHlClear()

Kevin Cox's answer was on the right track except for a couple problems.

  1. Modifying @/ is a heavy handed approach to disable highlighting of the existing search
  2. Vim saves/restores the search highlighting state before/after calling a function, so trying to change that in a function isn't very useful.

The solution is to simplify. There's no need for a function call.

autocmd CursorHold,CursorHoldI * let v:hlsearch = 0 | redraw

A little bit of necromancy, but I hope it's useful:

I tweaked @DhruvaSagar's answer to improve performance by deactivating the autocmd when it's not needed. Also I removed the CursorHold event: I like to look at my results in peace.

I'm using this together with the second answer from here to automatically deactivate the highlight after a while when I'm not searching (via / or n).

My code:

function! s:NoHLAfter(n)
  if (localtime() - g:nohl_starttime) >= a:n
    call <SID>Onnohl()
  endif
endfunction

function! s:Onnohl()
  set nohlsearch
  augroup AutoNohl
    au!
  augroup END
endfunction

function! s:Onsearch()
  set hlsearch
  nohlsearch
  let g:nohl_starttime = localtime()
  augroup AutoNohl
    au!
    " autocmd CursorHold,CursorMoved * call <SID>NoHLAfter(4)
    " only do it on CursorMoved: We sometimes 'hold' and look at the
    " findings.
    autocmd CursorMoved * call <SID>NoHLAfter(4)
  augroup END
endfunction

noremap n :call <SID>Onsearch()<cr>n
noremap N :call <SID>Onsearch()<cr>N
noremap / :call <SID>Onsearch()<cr>/
noremap ? :call <SID>Onsearch()<cr>?
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top