How to toggle Vim's search highlight visibility without disabling it
Asked Answered
M

13

23

What I'd like is to map one key, e.g. F4, so that pressing F4 will toggle the visibility of search highlights, and so that starting a new search enables visibility no matter the current visibility.

What I've tried:

  1. Mapping F4 to :nohlsearch temporarily disables highlight visibility without turning the hlsearch setting off, but it does not toggle visibility back again.
  2. Mapping F4 to :set hlsearch! does toggle on/off, but I don't want to toggle the hlsearch setting off, just the visibility setting. If hlsearch is off then it doesn't come back automatically with a new search.

There doesn't seem to be an opposite form of :nohlsearch and the command itself has problems being called from a function.

I've found similiar questions, but they don't provide an answer.

Update:
The first comment provides exactly what I was asking for, reproduced below:

let hlstate=0
nnoremap <F4> :if (hlstate == 0) \| nohlsearch \| else \| set hlsearch \| endif \| let hlstate=1-hlstate<cr>

(N.B. for anyone using this --- cramming the map onto one line instead of using a function is necessary since you can't effect a change on highlighting from inside a function.)

Related question for slightly different functionality: https://mcmap.net/q/584342/-highlight-searches-in-vim-but-not-substitutions

Mcdaniel answered 29/1, 2012 at 16:42 Comment(5)
Here's the answer: Line 1: " ctrl+c to toggle highlight., Line 2: let hlstate=0. Line 3: nnoremap <c-c> :if (hlstate%2 == 0) \| nohlsearch \| else \| set hlsearch \| endif \| let hlstate=hlstate+1<cr>. Now just press ctrl+c to toggle highlight.Jeuz
Excellent! If you repost the comment as an answer I'll accept it. As far as I can tell, the question isn't marked as a duplicate anymore.Mcdaniel
Okay, there it is. :)Jeuz
Thanks for the inspiration. You might want to add <silent> between nnoremap and <F4>, to prevent littering of the statusline.Perineuritis
It took me a while to note that hlsearch doesn't work in function. Any idea why?Marcos
J
13
" ctrl+c to toggle highlight.
let hlstate=0
nnoremap <c-c> :if (hlstate%2 == 0) \| nohlsearch \| else \| set hlsearch \| endif \| let hlstate=hlstate+1<cr>

Now just press ctrl+c to toggle highlight. Only quirk is you gotta press it twice after a search to toggle off highlight because searching doesn't increment the counter.

Jeuz answered 24/5, 2013 at 8:42 Comment(2)
I've linked to another SO question which shows how to make a better toggle. However it requires accepting a different functionality for when highlights are automatically enabled: in it, only searches will automatically enable highlights, and not substitutes (and this is a limitation of the method). But I think I actually like that a bit better.Mcdaniel
Cool, thanks for sharing! With some effort, maybe a third solution can be made. :DJeuz
V
27

Note, recent Vims (7.4.79) have the v:hlsearch variable available. This means you can improve your mapping to:

:nnoremap <silent><expr> <Leader>h (&hls && v:hlsearch ? ':nohls' : ':set hls')."\n"
Valaria answered 22/10, 2014 at 10:2 Comment(8)
This is the best option because any search operation like /, ?, n, N, etc. re-enables highlighting, and it doesn't require remapping any of them.Artifice
How to map ctrl-l without losing its original function?Illusive
@Illusive Use the :redraw command and append the hls command.Valaria
How your command differ from this one? nmap <F4> :let &hls=(&hls == 1 ? 0 : 1)<cr> Because this one does not uses ` v:hlsearch` and does not uses <expr>. And if possible I would like to include a redraw because I want to use <ctrl-l>, it is faster pressing it instead of <leader>h.Illusive
@Illusive v:hlsearch gives the correct state, whether matches are highlighted or not, hls does not, it just enables this option, but it could still be disabled because of :nohls.Valaria
@ChristianBrabandt could you expand your answer and provide the actual solution with <F4>? @Artifice and you say is the best solution but it's not clear what to put in <silent>, <expr> or <Leader>.Airwaves
@jocerfranquiz I am not sure what your problem is. If you want to use <F4> instead of <Leader>h, simply replace <Leader>h by <F4>.Valaria
@jocerfranquiz If I'm reading you correctly, you've interpreted <silent>, etc. as placeholders. They aren't, they're literal text with the angle brackets giving the words within them special meaning in vimscript.Artifice
J
13
" ctrl+c to toggle highlight.
let hlstate=0
nnoremap <c-c> :if (hlstate%2 == 0) \| nohlsearch \| else \| set hlsearch \| endif \| let hlstate=hlstate+1<cr>

Now just press ctrl+c to toggle highlight. Only quirk is you gotta press it twice after a search to toggle off highlight because searching doesn't increment the counter.

Jeuz answered 24/5, 2013 at 8:42 Comment(2)
I've linked to another SO question which shows how to make a better toggle. However it requires accepting a different functionality for when highlights are automatically enabled: in it, only searches will automatically enable highlights, and not substitutes (and this is a limitation of the method). But I think I actually like that a bit better.Mcdaniel
Cool, thanks for sharing! With some effort, maybe a third solution can be made. :DJeuz
S
12

What I'd like is to map one key, e.g. F4, so that pressing F4 will toggle the visibility of search highlights, and so that starting a new search enables visibility no matter the current visibility.

Just tried this and seems to do the trick:

" switch higlight no matter the previous state
nmap <F4> :set hls! <cr>
" hit '/' highlights then enter search mode
nnoremap / :set hlsearch<cr>/
Superload answered 1/2, 2012 at 7:0 Comment(0)
A
6

You can toggle with :set invhlsearch

Angelita answered 1/3, 2019 at 5:36 Comment(0)
K
5

From Highlight all search pattern matches, we can map a key to toggle the highlighting states. Unlike trusktr's answer, here we do use a variable to store the state.

"If you want to be able to enable/disable highlighting quickly, you can map a key to toggle the hlsearch option":

" Press F4 to toggle highlighting on/off, and show current value.
:noremap <F4> :set hlsearch! hlsearch?<CR>

"Or, press return to temporarily get out of the highlighted search":

:nnoremap <CR> :nohlsearch<CR><CR>
Kola answered 29/7, 2014 at 14:53 Comment(0)
V
2

Other answer need to toggle highlight search, this is not so good.

Actually you only need to

let @/ = ''

I write a little function to implement this feature, and highlight current word (just like * star key), but not jump to next matched word, and not touch jumplist.

function! HLtoggle()
    if (@/ == '')
        let @/ = expand("<cword>")
    else
        let @/ = ''
    endif
endfunc

it's simple, but i'm not find it in google.

Have fun with vim! :)

Variorum answered 22/10, 2014 at 9:21 Comment(0)
S
1

Okay, try this:

:map <F12> :set nohls<CR>:let @/ = ""<CR>:set hls<CR>

Then if you hit F12, it turns of the higlighting, then sets the last search string to an empty one (that is: clears it), and turns back on the highlighting.

Or if you want to save the search string, then you can do something like:

:map <F12> :set nohls<CR>:let @s = @/<CR>:let @/ = ""<CR>:set hls<CR>
:map <SHIFT><F12> :let @/=@s<CR>

Now after pressing SHIFTF12 the original searchstring will be set back and highlighted.

If that still not satisfy you, you can still do it like:

:map <F12> :highlight Search term=None ctermfg=None ctermbg=None guifg=None guibg=None<CR>
:map <SHIFT><F12> :highlight Search term=OV1 ctermfg=OV2 ctermbg=OV3 guifg=OV4 guibg=OV5<CR>

Where OVx are the original values which you can write down when you issue a :highlight Search<CR>. This way it can be turned off then set back on, but with two keyboard shortcuts. If you want it with one, you should create a function for that which toggles it, then create a mapping for that function.

Sundried answered 29/1, 2012 at 22:3 Comment(3)
This is effectively the same as attempt 1) in that it will nicely turn off highlighting and make sure it nicely comes back on my next search. The problem is that if there isn't a next search I want the button to turn off and on the highlighting on whatever my last search is, so we can't go clearing the @/ variable.Mcdaniel
See my updated answer, on setting it back, and/or using the highlight command.Sundried
@Mcdaniel The solution is simple (perhaps it didn't work in vim back in Jan 2012) but to "hide" the highlight, do :nohl, and to "unhide" the highlight, just do :set hls. Your search term will be rememebered the whole time. Just make a mapping that executes either command based on a variable counter modded by 2.Jeuz
I
0

Hmm, isn't :set hlsearch the opposite of :nohlsearch?

The first one turns matches highlighting on, the second one turns matches highlighting off temporarilly.

I don't understand what you mean by "I don't want to toggle the 'hlsearch' setting itself, just the visibility setting.": :set hlsearch and its pendant only deal with the visibility ("highlighting") of search matches, nothing else.

If you want to have matches highlighted each time you do a search just add :set hlsearch to your ~/.vimrc.

If you want the ability to turn highlighting off after a search just map F4 to :nohlsearch, highlighting will be back at your next search.

Invasive answered 29/1, 2012 at 20:53 Comment(7)
To answer your question, try this in vim :set hlsearch? to verify it is on, perform a search, perform :nohlsearch (which turns off visibility, if any), then perform :set hlsearch? again. This will reveal that hlsearch is still on. The significance is if you perform a second search then highlight visibility will come back. In contrast if you perform :set nohlsearch then visibility will never come back until you undo the setting.Mcdaniel
With regards to the last sentence, mapping F4 to :nohlsearch only lets me toggle highlights off. I want to be able to toggle the same search on and off and have it always come back on at my next search.Mcdaniel
That's the point of :nohlsearch: it's temporary. Highlighting will be back at your next search, isn't that what you want?Invasive
Yes and no. I want it off temporarily, yes. But I don't want that temporary time to be "until the next time I perform a new search". Rather, I want it to be off temporarily "until the next time I either press F4 or perform a new search"Mcdaniel
I too want to toggle it, without having to do a new search.Jeuz
Zsolt Botykai points out in his answer that to make the search visible, simply do :set hlsearch, which makes it visible again. The hlsearch setting is already on, so :set hlsearch just does the opposite of :nohlsearch, while the whole time the hlsearch setting is on. Make sense?Jeuz
Since this question is closed as duplicate and I can't post an answer, I've posted my solution as a comment to the original question. Take a look above.Jeuz
R
0

I use this slightly improved version from trusktr. Note that ctrl+c as used in the example from trusktr is already mapped to Escape by default which is very handy.

" Toggle highlight search
let hlstate=0
nnomap <Leader>b :if (hlstate%2 == 0) \| nohlsearch \| else \| set hlsearch \| endif \| let hlstate=hlstate+1<CR>:echo "toggled visibility for hlsearch"<CR>
inomap <Leader>b <ESC>:if (hlstate%2 == 0) \| nohlsearch \| else \| set hlsearch \| endif \| let hlstate=hlstate+1<CR>:echo "toggled visibility for hlsearch"<CR>a
Renaterenato answered 18/8, 2013 at 15:46 Comment(2)
What does <Leader> mean? Is it a key?Airwaves
Could you provide the link to the source that you mention? (Who is this "trusktr"?) 🤨Airwaves
V
0

In order to accomplish this, I added this unsophisticated line in my .vimrc:

nmap <LEADER>h /xxxxx<CR>
Vacua answered 10/6, 2019 at 20:58 Comment(1)
Made me laugh out loud :)Gar
A
0

I use the following:

augroup onsearch                                                                                                                    
    autocmd!                                                                                                                          
    autocmd VimEnter * set hlsearch                                                                                                   
augroup END

nnoremap <leader>/ :set hlsearch!<CR>

The autogroup ensure's that highlighting is enabled when entering vim, but not switched on when re-sourcing your vimrc file(s). The mapping toggles it on and off.

Achorn answered 7/4, 2020 at 8:12 Comment(0)
B
0

If anyone is looking to do this in neovim (in lua) this is a simple command that I wrote:

HLSTATE = vim.opt.hlsearch
function TOGGLE_SEARCH_HIGHLIGTING()
  if HLSTATE == true then
    vim.opt.hlsearch = false
    HLSTATE = false
  else
    vim.opt.hlsearch = true
    HLSTATE = true
  end
end
vim.api.nvim_create_user_command('HighlightToggle', 'lua TOGGLE_SEARCH_HIGHLIGTING()', {})

You can then run it with the command :HighlightToggle (and assign in a keymap if you want).

Berberine answered 2/7, 2022 at 16:11 Comment(0)
C
0

I use this mapping in my vimrc:

nnoremap <silent> <leader>a :let v:hlsearch=(&hls && !v:hlsearch)<CR>

Basically if hlsearch is off, the mapping is no-op (v:hlsearch is always false). If it's on, then \a toggles search highlight without changing the hlsearch setting. (Not exactly what OP asked, but I really don't like the idea of switching hlsearch on every time new search starts.)

Concentre answered 16/6, 2023 at 6:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.