Deselecting matching strings after search-and-replace in Vim - vim

I've got a file (LaTeX) which contains lines I wish to comment out.
The regex that I use after visually-selecting the relevant block is :s/^/%/g, which works fine. However, vim then highlights every matching occurrence of the first part of the regular expression used in the replace, (highlights the first character on the beginning of every line).
The selection changes if I do another search, or another search-and-replace, but I can't work out how to turn it off without doing a 'useless' search.
It's particularly annoying if I search for whitespace (because having every '' highlighted in a text file is visually annoying).
How do I de-select the matching strings after the search-and-replace has been completed?

:nohlsearch will stop highlighting it but keep it as the active search pattern. (It will start being highlighted on n etc.)
:let #/="" will clear the search pattern register (so that n etc. won't work).
A common thing I've seen in Vim is map <Leader><Space> :noh<CR>; this has the result that (assuming the default leader, backslash) \Space will stop highlighting the current match.

Just search for a string that is not on the page:
/poop

:nohlsearch will remove highlighting from the current search. Highlighting will return on your next search.
:set nohlsearch will disable highlighting for your current vim session.
If you want to disable highlighting completely, add :set nohlsearch to your .vimrc

Add that to your vimrc, and once done - press in my case <,> + enter to stop highlighting
map <silent> <leader><cr> :noh<cr>

Related

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.
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 :-)
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>
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.

Search for word under cursor

When I use g* or * or g# it will trigger a search for the word under the cursor. However, the cursor moves to the next/previous occurrence of that word. Is there a way to search for the current word without having the cursor moving away?
It is annoying because often I want to press
*
:.,+5s/foo/bar/g
But this problem forces me to do
*
then shift+* (I want to skip this)
my search and replace.
Is there a way to search for the current word without having the cursor moving away?
The whole point of *, #, and friends is made pretty clear in the documentation: "search forward" or "search backward". Your problem seems to be that you use those commands not for their intended purpose but for a side effect, presumably highlighting all occurrences of the word under the cursor.
Since there's no built-in command for that you will need to map it yourself:
nnoremap <key> *``
nnoremap <anotherkey> #``
...
Instead of pressing * to fill the search pattern copy the word directly to command line using CTRL-R CTRL-W. I.e.:
:.,+5s/<C-R><C-W>/bar/g
Changing the functionality of * / # / g* etc. to not jump (especially without a given [count]) is a frequent request. Therefore, a plethora of plugins changes Vim's default behavior, often together with other search-related commands. My SearchHighlighting plugin is one such plugin. (The plugin page has links to many alternative plugins that could also try out.)
#romainl's accepted answer is a minimal solution with some drawbacks (e.g. flickering of the screen, possible change of window viewport) that most plugins will avoid.
I use the below mapping to search the current word and keep cursor's posistion:
nnoremap <expr> * ':%s/'.expand('<cword>').'//gn<CR>``'
The extra benefit is we got matches count too.
You could map:
nnoremap # #N
nnoremap * *N
noremap * :let #/ = "\\<<C-r><C-w>\\>"<cr>:set hlsearch<cr>
It simply sets the search pattern to the whole word under the cursor and then triggers an update to the search highlighting

Highlighting arbitrary lines in VIM

During the implementation process of a program I generally insert many append code lines, mainly with print command, to help me understand and debug the implemented program. Unfortunately, it is common to me to forget which lines are from the code and with were appended and should be deleted some time after. This problem gets worst with large programs.
Well, I found this article that teaches how to keep one arbitrary user selected line highlighted (see section: Highlighting that stays after cursor moves). The solution given by the article is to include in .vimrc the following code:
:nnoremap <silent> <Leader>l ml:execute 'match Search /\%'.line('.').'l/'<CR>
So, every time when I press \l the current line is highlighted and kept so, and the previous highlighted line, if there are one, is unhighlighted.
This isn't the behavior that I would like. Instead, I would like to be able to highlight as many arbitrary lines as I want without unhighlighting the previous highlighted lines. And if it is possible, with a unique command like \l.
Someone knows a solution for this?
Thanks in advance.
EDITED:
The command proposed by yolenoyer solved the initial problem. But, now other problem raised. The following command:
:call clearmatches()
proposed to clean the highlighted lines cleans all lines and I would like to be able to clean specific highlighted lines, instead off all of them at once. Is it possible?
I program in C quite alot, and when debugging tend to pepper the code with debug prints.
I use the vim command
:syntax match Error /\<debug_printf\>/
to ensure the word 'debug_printf' is highlighted in the default 'Error' colors for the particular colorscheme.
This doesn't help you bookmarking a series of lines, but for that you should check out the 'bookmark' plugin which allows you to create and remove bookmarks throughout the file.
VIM Bookmarks Plugin
:match accepts only one match.
Use the matchadd({highlight-group}, {pattern}) function instead, for example:
nnoremap <silent> <leader>l :call matchadd('Search', '\%'.line('.').'l')<cr>
To clear the matches you added, run :call clearmatches().
I used the answers here to come up with this combo, which I think is nice:
" \l to highlight a line
nnoremap <silent> <leader>l :call matchadd('Search', '\%'.line('.').'l')<CR>
" \L to remove highlighted line
nnoremap <silent> <leader>L :
\for m in filter(getmatches(), { i, v -> has_key(l:v, 'pattern') && l:v.pattern is? '\%'.line('.').'l'} )
\<BAR> :call matchdelete(m.id)
\<BAR> :endfor<CR>
I think your first paragraph, which explains your problem, has nothing to do with vim, so maybe you don't need to use vim to solve your problem.
What about not debugging with regular print statements, but with a function that wraps print? That would be really easy to search for program wide and also file wide (just search with * or # for all occurrences of your debug printing function).

Highlight searches in Vim but not substitutions?

I know it's possible to stop Vim from highlighting on any search, but is there a way to make it highlight on regular searches but not, for instance, substitutions?
I will often highlight a block of text then do something like:
:s/^/#/
to comment out the whole block. But then I have an ugly yellow bar running up and down the left side of my screen and I have to :noh every time to clear it.
I want highlighting to remain on regular /searches. Is this possible?
This doesn't answer your question fully but for me having the same problem it helped: I added this command to easily deactivate the highlighting after a search or a search-and-replace
nnoremap <esc> :noh<return><esc>
(from Vim clear last search highlighting)
My solution: put this in your vimrc file
set nohlsearch
noremap * :set hlsearch<CR>:nohlsearch<CR>*
noremap / :set hlsearch<CR>:nohlsearch<CR>/
noremap ? :set hlsearch<CR>:nohlsearch<CR>?
nnoremap <F4> :set invhlsearch<CR>
inoremap <F4> <ESC>:set invhlsearch<CR>gi
nnoremap <CR> :set nohlsearch<CR>
What it does:
Searches always enable highlights.
Use Enter to turn off highlights until the next search, but not the next substitute. Pressing Enter again will not turn them back on though.
Use F4 to turn off highlights until the next search, but not next substitute. Pressing F4 again will toggle the highlights for the last search pattern --- search OR substitute --- if there was one.
Some notes on highlights that are never really explained well:
When the 'hlsearch' option is on, all future searches/substitutes will turn on "highlight visibility". The current "highlight visibility" is not really an option you can directly query or set independently, but you can independently turn OFF highlight visibility with the command :nohlsearch (this is not the same as :set nohlsearch, because the next search will enable visibility again).
In addition, 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.

Pressing "Home" in Vim on an Indented Line

I have a bad habit of using the 'home' key to go back to the beginning of a line. As I recently started using vim I noticed that when I press the home key on a lined that is indented, it returns me to the very beginning of the line. In Notepad++ (the editor I used to use) it would return me to the beginning of the code on that line, right after the indent.
Is there some way to replicate this behavior in vim? Usually, when I'm pressing home it's in the Insert mode for me to (usually) stick a variable there.
I have set smartindent in my vimrc, with set noautoindent as a "tips" page told me to make sure to disable autoindent (although it didn't seem to be enabled in the first place - perhaps that option is extraneous.)
There are two usual ways to go to the "beginning" of a line in Vim:
0 (zero) go to the first column of text
^ go to the first non-whitespace on the line
I find that using 0w is usually the most convenient way for me to go to the first nonblank character on a line, it's the same number of keys as ^ and is easier to reach. (Of course, if there are no leading spaces on the line, don't press w.)
You could remap Home to be the same as ^ (the docs say Home's default function is equivalent to the movement command 1|):
:map <Home> ^
:imap <Home> <Esc>^i
Which should make the insert mode mapping be equivalent to escaping out of insert mode, pressing ^ and then returning to insert mode. I don't know about the best method of mapping a motion command for use inside insert mode, so this may break something, but it seems to work.
As to your indentation settings, they shouldn't have an effect on movement controls, but I also think you probably would prefer to have them set differently. autoindent just keeps your current indentation for new lines (so if you place 4 spaces at the beginning of a line, after you press return your new line will also have 4 spaces placed in front of it). I don't know why you wouldn't want that, since it's pretty useful in pretty much any programming language, or even just freeform text. smartindent on the other hand implements a couple of hard-coded lightly C-ish indentation rules, like indenting after an opening {, and deindenting after a closing }, but doesn't automatically carry over indentation from previous lines. The docs recommend keeping autoindent on if you use smartindent.
However, smartindent is useless for languages that don't meet its hard-coded rules, or even actively harmful (like when it automatically removes indentation from any line starting with a '#', which it thinks is a preprocessor directive but is wrong for python programmers trying to write an indented comment).
So vim also includes a more advanced indentation mode, filetype indentation, which allows flexible indentation rules on a per-language/filetype basis and is the preferred indentation mode for most people (even for C-like languages). If you do use filetype indentation, it's best to turn off smartindent (otherwise it can interfere with the filetype indentation, like moving all comment lines to column 0 in python files).
Personally, I always have autoindent on, use filetype when available, and never use smartindent. My .vimrc includes:
set autoindent " doesn't interfere with filetype indents, and is useful for text
if has("autocmd")
" Enable file type detection and indentation
filetype plugin indent on
set nosmartindent
endif
I imagine there's something you could do to have smartindent turned on only when filetype indenting doesn't exist for a filetype, if you're editing that many different C-like languages with no filetype indentation available.
Here’s what I have in my .vimrc. This maps Home to move to the beginning of the
text if you are anywhere in the line, and column 0 if you are at the beginning
of the text.
function ExtendedHome()
let column = col('.')
normal! ^
if column == col('.')
normal! 0
endif
endfunction
noremap <silent> <Home> :call ExtendedHome()<CR>
inoremap <silent> <Home> <C-O>:call ExtendedHome()<CR>
Note: I am using a keyboard layout that maps Home to Alt Gr+A, that why I’m using this. If you have to leave the letter field of your keyboard to reach Home, you should probably go to normal mode instead.
You could also use _ in Normal mode to go to the first non-whitespace character of the current line. You can also use a count with this motion.
_ <underscore> [count] - 1 lines downward,
on the first non-blank character linewise.
Try pressing 0 (also see :help 0)
also, this might help:
:imap <C-Home> <esc>0a

Resources