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
Related
I currently use the following mapping to substitute the result of the last search pattern with a new word in the entire buffer:
nnoremap <Leader>sa :%s///g<left><left>
What I would like is to put the result of the last search pattern where the new word goes.
Example:
suppose my cursor is standing on the word "hello"
Then I press *
Then I invoke the mapping with <Leader>sa
At this point, my command line is filled with :%s///g. What I would like to have is :%s//hello/g.
I tried the mapping below, but it adds the whole word delimeters (\< and \>) which I don't want.
nnoremap <Leader>sa :%s///g<left><left><C-r>/
--- EDIT ---
After some much needed clarification, I think that the simplest approach is to use :help s/\& in the replacement part of your substitution:
nnoremap <key> :%s//&/g<left><left>
If you really need a more visually explicit method, you can trim the \< and the \>, like this:
nnoremap <key> :%s//<C-r>=substitute(#/,'\\<\\|\\>','','g')<CR>/g<left><left>
which should get you something like this:
:%s//hello/g
with the cursor after hello, ready for further editing.
--- ENDEDIT ---
In command-line mode, :help c_ctrl-r_ctrl-w inserts the word under the cursor:
nnoremap <key> :%s///g<left><left><C-r><C-w>
<cword> gets the word under the cursor, but you have to call expand and send a carriage return
nnoremap <Leader>sa :%s///g<left><left><C-r>=expand("<cword>")<CR>
One way to support visual selections and multiple words is to yank the text you want to replace then search for it with <C-r>"
nnoremap <Leader>sa :%s///g<left><left><C-r>"
You would make a visual selection, press y, then <leader>sa to replace, or /<C-r>" to search.
Edit
After reading the clarifications above, here is a different way to do (almost) the same thing:
Make a visual selection
Press *
Type cgn<C-r>"2 (e.g. change "ThisIsAVeryLongVariable" to "ThisIsAVeryLongVariable2")
Each press of . will repeat the substitution
I am using easymotion plugin (https://github.com/easymotion/vim-easymotion) with vim.
If you use f/F motions in VIM (with easymotion plugin), easy motion highlights all possible positions when there are multiple matches, that way you can easily jump to the position you want.
But it doesn't work with y/c/d commands, how can I achive that ?
I have provided an example below for clarification:
This is some line.
Say I am working on the above line in vim and the cursor is at the i in "This". If I do "yfs" in vim, I would like easy motion to mark the three "s"s present to the right of the cursor. That way, I can easily yank/change/delete upto the s I want.
Thanks in advance !
You can, use something like this in your .vimrc:
" Find next occurence of a char using easymotion
map <Leader>f <Plug>(easymotion-bd-f)
nmap <Leader>f <Plug>(easymotion-overwin-f)
Now you can do something like y<Leader>fs and it will highlight the three s-characters. Selecting one will then yank from your cursor's position to that character.
If this does not work
This means that there are other key bindings that are using the same combination. You can check this with :map and then look for the key combination you are trying to map to the easy-motion. Removing that keybinding from your .vimrc or removing the plugin that created the binding should solve the problem.
If it's the YankRing plugin that's hijacking the y/c/d keystrokes, you can add the following to your vimrc to prevent it from doing that (Check :h yankring for more info):
let g:yankring_zap_keys = ''
Ok so basically the way Vim highlights searches displeases me. Basically you do a search, then you have to type /asdf or have a shortcut like this in your vimrc:
nn <silent> <leader><space> :noh<CR>
Which is what I have. But it's still too much mental work. Basically, when I do a search, I want highlighting to enable (like it does now) but if I do anything other than cycle through the searches (with n/N) then I want highlighting to turn off. That's basically my workflow, so I'm wondering if I can automate it. Also if I search, do something other than n/N (which should turn highlighting off) and then press n/N again, it should re-enable.
Any ideas?
That's difficult. One idea is
:autocmd CursorHold * call feedkeys(":noh\<CR>")
(One needs to use feedkeys() because :nohlsearch is ineffective in functions and autocmds.) This clears the highlighting whenever you pause the cursor for some seconds. You can add other triggers like InsertEnter or CursorHoldI.
What does not work is CursorMoved, because the searches and n / N jump as well. You would need to overload those commands, store the cursor position after the jump, and modify the autocmd to only clear the highlighting when the position is different.
What I do: I have Enter mapped to :nohlsearch; it's quick and easy to reach.
you can turn it on or off with:
:set hls
or
:set nohls
I have F7 mapped to set hls!:
noremap <F7> :set hls!<CR>
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>
When I'm on Windows, I use notepad++, and on Linux I use vim. I really like vim. But there is at least one thing I find really interesting in notepad++. You can double-click on a word and it highlights all occurrences of that word automatically. I was wondering if I could do something like that with vim? So the question is how to highlight all occurrences of a word when you double click on the word in vim.
Obviously, I don't want to search for that word, or change my cursor position, just highlighting. My :set hlsearch is also on.
probably you may want to avoid the mouse in vim, but I make an exception here :).
I know that * does the same job, but what about mouse?
If you want to highlight the word under the cursor like *, but do not want to move the cursor then I suggest the following:
nnoremap <silent> <2-LeftMouse> :let #/='\V\<'.escape(expand('<cword>'), '\').'\>'<cr>:set hls<cr>
Basically this command sets the search register (#/) to the current word and turns on 'hlsearch' so the results are highlighted. By setting #/ the cursor is not moved as it is with * or #.
Explanation:
<silent> - to not show the command once executed
<2-LeftMouse> - Double click w/ the left mouse button
#/ is the register used for searching with / and ?
expand('<cword>') get the current word under the cursor
escape(pattern, '\') escape the regex in case of meta characters
\V use very-non-magic mode so everything meta character must be escaped with /
\< and \> to ensure the current word is at a word boundary
set hls set 'hlsearch' on so highlighting appears
If setting the #/ register is not your cup of tea than you can use :match instead like so:
nnoremap <silent> <2-leftMouse> :exe 'highlight DoubleClick ctermbg=green guibg=green<bar>match DoubleClick /\V\<'.escape(expand('<cword>'), '\').'\>/'<cr>
To clear the matches just use:
:match none
You can map * to double-click by a simple mapping:
:map <2-LeftMouse> *
If you want to use said functionality in insert-mode you can use this mapping:
:imap <2-LeftMouse> <c-o>*
Without (Ctrl-o) the * would be printed
[EDIT]
As ZyX pointed out, it is always a good idea to use noremap respectively inoremap if you want to make sure that if * or <c-o> will be mapped to something else, that this recursive mapping won't be expanded.