phatskat
phatskat

Reputation: 1815

How to prevent search highlight during when executing a mapping

When writing mappings in nvim, I'm sometimes using a search/replace, for instance in this mapping to creating headings that are the same length as the current line (for markdown etc):

nnoremap <leader>= 0Vyp0v$:s/./=/g<cr>:nohls<cr>

While this clears the search highlighting with :nohls, it still creates the "flash" of the search/replace.

Upvotes: 2

Views: 243

Answers (3)

Ingo Karkat
Ingo Karkat

Reputation: 172658

General solution

I would make use of :help function-search-undo and extract the commands into a :function. This won't clobber the current search pattern, and therefore also doesn't affect search highlighting. To be fully neutral, you just have to remove the used substitution pattern from the search history (via histdel()):

function! MakeHeading()
    normal! Vyp
    s/./=/g
    call histdel('search', -1)
endfunction
nnoremap <leader>= :call MakeHeading()<CR>

Note that I've also simplified the visual selection handling: As V always selects the entire line, you don't need to go to the first column (^), neither is the reselection necessary; we can just let :substitute work on the current (pasted) line.

Alternative implementation

That reminds me that the canonical implementation of this functionality uses the :help v_r command, and this indeed requires a re-selection:

nnoremap <leader>= Vyp0v$r=

As there's no pattern involved here, search highlighting is totally unaffected by it :-)

Upvotes: 3

Ralf
Ralf

Reputation: 1813

Based on your own answer, I would propose the following:

nnoremap <leader>= :set nohlsearch<cr>0Vyp0v$:s/./=/g<cr>:let @/=''<cr>:set hlsearch<cr>

This just sets the search register to an empty string. So no highlighting. You could even reset it to the previous search string:

nnoremap <leader>= :let olds=@/<cr>0Vyp0v$:s/./=/g<cr>:let @/=olds<cr>

And BTW: Wouldn't yyp:s/./=/g be easier.


I personally have hlsearch off by default and only switch it on, when I need it. To toggle it I have the following mapping in my vimrc:

" Switch on/off higlighting of search string
noremap  <F8>   :set invhlsearch hlsearch?<CR>

Upvotes: 1

phatskat
phatskat

Reputation: 1815

While researching :h :s and :h s_flags`, and doing more looking around here, part of @Ein's answer stuck out to me:

whenever you run the command :set hlsearch there are two effects: It sets the option AND it makes vim forget if you've ever typed :nohlsearch. In other words, changing 'hlsearch' (either on or off) will force the current "highlight visibility" to logically match.

With a combination of using :set nohls and the e flag (:h s_e), I ended up with:

nnoremap <leader>= :set nohlsearch<cr>0Vyp0v$:s/./=/g<cr>:s/thanks@Ein//e<cr>:set hlsearch<cr>

" Broken out
" Turn off highlighting
:set nohlsearch

" Yank the whole line, duplicate it, and replace `.` with `=`
0Vyp0v$:s/./=/g

" Do a replace with something I'll never find in a document (probably), with `/e` to suppress errors.
:s/thanks@Ein//e

" Finally, reenable highlighting
:set hlsearch

Any more elegant solutions are welcome. I think I'll be refactoring some of this into a function soon at least, to allow for using other characters like - for subheadings.

Upvotes: 0

Related Questions