Vim Tips Wiki
Explore
Main Page
All Pages
Community
Interactive Maps
Community portal
To do
FANDOM
Fan Central
BETA
Games
Anime
Movies
TV
Video
Wikis
Explore Wikis
Community Central
Start a Wiki
Don't have an account?
Register
Sign In
FANDOM
Explore
Current Wiki
Start a Wiki
Don't have an account?
Register
Sign In
Sign In
Register
Vim Tips Wiki
1,649
pages
Explore
Main Page
All Pages
Community
Interactive Maps
Community portal
To do
Editing
Search for visually selected text
Back to page
Edit
Edit source
View history
Talk (0)
Edit Page
Search for visually selected text
We recommend that you
log in
before editing. This will allow other users to leave you a message about your edit, and will let you track edits via your
Watchlist
.
Creating an account
is quick and free.
The edit appears to have already been undone.
Anti-spam check. Do
not
fill this in!
{{TipImported |id=171 |previous=168 |next=172 |created=2001 |complexity=basic |author=Raymond Li |version=6.0 |rating=83/28 |category1=Searching |category2= }} With this tip, you can select some text, then press a key to search for the next occurrence of the text. Two alternative methods are presented. ==Simple== Nothing is needed if you want to search for the word under the cursor, just [[Searching|press <code>*</code>]]. To search for visually selected text, put this line in your [[vimrc]]: <pre> vnoremap // y/\V<C-R>=escape(@",'/\')<CR><CR> </pre> To use the mapping, visually select the characters that are wanted in the search, then type <code>//</code> to search for the next occurrence of the selected text. Then press <code>n</code> to search for the next occurrence. The <code>:vnoremap</code> () command maps <code>//</code> in visual mode to copy the visually selected text into the <code>"</code> buffer, then start a search command and paste an escaped version of the copied text into the line. <code><C-R></code> represents [[Paste registers in search or colon commands instead of using the clipboard|Ctrl-R]] and <code><CR></code> represents carriage return (Enter). The search uses <code>\V</code> ({{help|/\V}}) for "very no-magic" mode, and <code>escape()</code> ({{help||tag = escape()}}) to escape <code>/</code> and <code>\</code> characters (the only ones that aren't literals with <code>\V</code>). ==Advanced== The following is a more advanced implementation, with more robust functionality than the above map. '''Features''' *Press <code>*</code> to search forwards for selected text, or <code>#</code> to search backwards. *As normal, press <code>n</code> for next search, or <code>N</code> for previous. *Handles multiline selection and search. *Whitespace in the selection matches ''any'' whitespace when searching (searching for "hello world" will also find "hello" at the end of a line, with "world" at the start of the next line). *Each search is placed in the search history allowing you to easily repeat previous searches. *No registers are changed. Place the following mappings in your [[vimrc]]: <pre> " Search for selected text, forwards or backwards. vnoremap <silent> * :<C-U> \let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR> \gvy/<C-R>=&ic?'\c':'\C'<CR><C-R><C-R>=substitute( \escape(@", '/\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR> \gVzv:call setreg('"', old_reg, old_regtype)<CR> vnoremap <silent> # :<C-U> \let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR> \gvy?<C-R>=&ic?'\c':'\C'<CR><C-R><C-R>=substitute( \escape(@", '?\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR> \gVzv:call setreg('"', old_reg, old_regtype)<CR> </pre> Following is an alternative version with some extra features: *A global variable (<code>g:VeryLiteral</code>) controls whether selected whitespace matches any whitespace (by default, VeryLiteral is off, so any whitespace is found). *Type <code>\vl</code> to toggle VeryLiteral to turn whitespace matching off/on (assuming the default backslash leader key). *When VeryLiteral is off, any selected leading or trailing whitespace will not match newlines, which is more convenient, and avoids false search hits. Create file (for example) <code>~/.vim/plugin/vsearch.vim</code> (Unix) or <code>$HOME/vimfiles/plugin/vsearch.vim</code> (Windows) with contents: <pre> " Search for selected text. " http://vim.wikia.com/wiki/VimTip171 let s:save_cpo = &cpo | set cpo&vim if !exists('g:VeryLiteral') let g:VeryLiteral = 0 endif function! s:VSetSearch(cmd) let old_reg = getreg('"') let old_regtype = getregtype('"') normal! gvy if @@ =~? '^[0-9a-z,_]*$' || @@ =~? '^[0-9a-z ,_]*$' && g:VeryLiteral let @/ = @@ else let pat = escape(@@, a:cmd.'\') if g:VeryLiteral let pat = substitute(pat, '\n', '\\n', 'g') else let pat = substitute(pat, '^\_s\+', '\\s\\+', '') let pat = substitute(pat, '\_s\+$', '\\s\\*', '') let pat = substitute(pat, '\_s\+', '\\_s\\+', 'g') endif let @/ = '\V'.pat endif normal! gV call setreg('"', old_reg, old_regtype) endfunction vnoremap <silent> * :<C-U>call <SID>VSetSearch('/')<CR>/<C-R>/<CR> vnoremap <silent> # :<C-U>call <SID>VSetSearch('?')<CR>?<C-R>/<CR> vmap <kMultiply> * nmap <silent> <Plug>VLToggle :let g:VeryLiteral = !g:VeryLiteral \\| echo "VeryLiteral " . (g:VeryLiteral ? "On" : "Off")<CR> if !hasmapto("<Plug>VLToggle") nmap <unique> <Leader>vl <Plug>VLToggle endif let &cpo = s:save_cpo | unlet s:save_cpo </pre> ==Explanation== The first suggested mapping was: <pre> vnoremap <silent> * :<C-U> \let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR> \gvy/<C-R><C-R>=substitute( \escape(@", '/\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR> \gV:call setreg('"', old_reg, old_regtype)<CR> </pre> When in visual mode, pressing <code>*</code> will then perform these commands: <pre> :<C-U> let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR> gvy /<C-R><C-R>= substitute( escape(@", '/\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR> gV :call setreg('"', old_reg, old_regtype)<CR> </pre> <code>:<C-U></code> enters command mode and deletes (Ctrl-u) the <code>'<,'></code> range automatically inserted due to the visual selection. The unnamed register (<code>@"</code>) is saved and later restored. <code>gvy</code> reselects then yanks the visual selection (copy to <code>@"</code>). <code>/<C-R><C-R>=</code> starts a search, then substitutes the expression register (<code>@=</code>) literally {{help|c_CTRL-R_CTRL-R}}. The result of the following expression is inserted into the command line. <code>escape()</code> inserts a backslash before each <code>/\.*$^~[</code> character found in <code>@"</code>. The <code>/</code> must be escaped because we are using a <code>/</code> command. The other characters need to be escaped because they have a special meaning in a regular expression. <code>substitute()</code> replaces every sequence of one or more whitespace characters (space, tab, newline) with an escaped regular expression that will search for any similar sequence. <code>gV</code> allows the mappings to work in <code>--SELECT--</code> mode as well as <code>--VISUAL--</code>. Without <code>gV</code>, searching for text in select mode would not move the cursor because the selection is automatically reselected after the mapping. ===Readable equivalent=== The principle is to get selection in to use it in search. There are multiple ways to get visually selected text. Here is a simple one, which does not distinguish between v and V selections. <pre> function! s:getSelectedText() let l:old_reg = getreg('"') let l:old_regtype = getregtype('"') norm gvy let l:ret = getreg('"') call setreg('"', l:old_reg, l:old_regtype) exe "norm \<Esc>" return l:ret endfunction vnoremap <silent> * :call setreg("/", \ substitute(<SID>getSelectedText(), \ '\_s\+', \ '\\_s\\+', 'g') \ )<Cr>n vnoremap <silent> # :call setreg("?", \ substitute(<SID>getSelectedText(), \ '\_s\+', \ '\\_s\\+', 'g') \ )<Cr>n </pre> ==Paste matching text of last search== When using <code>^r/</code> in INSERT mode what one most of the time wants is to paste the matched text not the regex used to search the text. Example: after using * on a word, <code>^r/</code> will paste the word with <code>\<</code> prepended and <code>\></code> appended, not what we want. Similarly after a visual search we don't want the <code>\V</code> prepended. The following map takes care of these issues: <source lang="vim"> function! Del_word_delims() let reg = getreg('/') " After * i^r/ will give me pattern instead of \<pattern\> let res = substitute(reg, '^\\<\(.*\)\\>$', '\1', '' ) if res != reg return res endif " After * on a selection i^r/ will give me pattern instead of \Vpattern let res = substitute(reg, '^\\V' , '' , '' ) let res = substitute(res, '\\\\' , '\\', 'g') let res = substitute(res, '\\n' , '\n', 'g') return res endfunction inoremap <silent> <C-R>/ <C-R>=Del_word_delims()<CR> cnoremap <C-R>/ <C-R>=Del_word_delims()<CR> </source> For more complicated patterns, it's better to act on the text matched with the last search, using the {{help|prefix=no|gn}} object. So, you could also accomplish insertion of a search match using <code>maygn`ap</code> in normal mode. I.e. <code>ma</code> to drop a mark to return to later, <code>y</code> to yank the <code>gn</code> object, then <code>`a</code> to jump back where you were (because the yank will leave you on the text copied), finally <code>p</code> to paste. When starting from insert mode, you don't even need a mark: you can use the <code>gi</code> command to start again from where you left off. For example: <pre> :inoremap <F3> <Esc>ygngi<C-R>0 </pre> Here, <code>ygn</code> is as before, but <code>gi</code> is used to go back to insert mode in the same place you left off, then <code><C-R>0</code> inserts the copied text. ==See also== * [[Script:2944|visualstar.vim]] ==Comments== {{Todo}} Tips related to visual searching (need to merge): *[[VimTip1011|1011 Mappings and commands for visual mode]] *[[VimTip1151|1151 Search visually]] This mapping forms a substitute command with the selected text: <pre> vnoremap <C-r> "hy:%s/<C-r>h//gc<left><left><left> </pre> Found on [http://stackoverflow.com/questions/676600/vim-replace-selected-text Stack Overflow: Vim replace selected text]. To auto escape certain characters (e.g. slash and backslash), one can use: <pre> vnoremap <C-h> ""y:%s/<C-R>=escape(@", '/\')<CR>//g<Left><Left> </pre> The 'readable equivalent' remap of '#' doesn't work for me. I get error <pre>```E345: Invalid register name: '?'```</pre>Answering to the above comment, for the 'readable equivalent' code to work, try<syntaxhighlight lang="vim"> vnoremap <silent> # :call setreg("/", \ substitute(<SID>getSelectedText(), \ '\_s\+', \ '\\_s\\+', 'g') \ )<Bar>let v:searchforward = 0<Cr>n </syntaxhighlight><br />
Summary:
Please note that all contributions to the Vim Tips Wiki are considered to be released under the CC-BY-SA
Cancel
Editing help
(opens in new window)
Templates used on this page:
Template:Help
(
view source
)
Template:Navigation
(
view source
)
Template:TipImported
(
view source
)
Template:Todo
(
view source
)
Follow on IG
TikTok
Join Fan Lab