How do I search for the selected text? - vim

How do I search for the selected (with v and y) string? I usually search with /, but I cannot paste the selected string after /.

In insert mode you can use CTRL-R to insert the contents of Vim registers. By default, copied text gets put in the unnamed register ", so to insert that text you would type <C-R>" in insert mode. The search prompt uses Command-line mode which has its own
CTRL-R that works almost identically to the one in Insert mode.
So if I just yanked the text foo, typing /<C-R>" would search for the text foo once I press enter.

:set hls
:vmap * y:let #/ = #"<CR>
set hls (hight light search)
v => hjkl (select something)
press *, copy selected text to reg "
set content of reg / as "
press n/N to navigate

I have this mapping defined in my vimrc, it maps * to defining the search pattern as what is currently highlighted (escaping all potential dangerous characters, and converting a space in what is highlighted to any sequence of spaces)
xnoremap * :<C-U>let old_reg=getreg('"')|let old_regtype=getregtype('"')<CR>gvy/<C-R><C-R>=substitute(substitute(escape(#", '/\.*$^~['), '\s\+', '\\s\\+', 'g'), '\_s\+', '\\_s*', 'g')<CR><CR>gV:call setreg('"', old_reg, old_regtype)<CR>:let v:searchforward=1<CR>
In order to use it, start visual mode with v, and then highlight what you want to search and press * not y.
Of course you can map # to search backwards (exactly the same except that v:searchforward should be set to 0.

If you only care about searches, you can use the cheat method I use. Yank a word via v or y+w, then issue the command
:%s//XYZ/gc
This will search for the last searched word. Then when you find it, it will ask for confirmation to replace with XYZ, and all you have to do is hit q to quit.

First yank the highlighted text using y. Then
/
Ctrl + r
"
Above commands will paste what you have yanked after the /. Then press ENTER

Related

Vim: Easy way to convert recorded macro into let

I want to save a certain macro permanently so that I can replay it in future sessions.
For instance, I record the macro which surrounds selected words with ** (like **this text is strong**):
Switch to the visual mode
Select some words
Start recording "a"
Press c, **, Ctrl-r, ", **, Ctrl-; (to switch to the normal mode); and
Stop recording.
From the next time, I can just select words and press #a to replay these actions.
Now I enter :reg a and see this output:
--- Registers ---
"a c**^R"**^[
How can I define this using the :let function so that I can add this to .vimrc and make this macro permanent?
:let #a='c**^R"**^['
didn't work.
The ^R and ^[ in the output of :reg a are literal control codes, not ^ followed by R or by [. Usually, Vim uses a special color to hint at that difference.
You can do either of two thingsā€¦
In your vimrc, type out the macro directly, using :help i_ctrl-v to insert the literal control codes. That is, press <C-v> then <C-r> to insert a literal ^R:
let #a = 'c** " type this out
<C-v><C-r> " press <C-v><C-r> to insert ^R
"** " type this out
<C-v><Esc> " press <C-v><Esc> to insert ^[
' " type this out
<Esc> " leave insert mode
In your vimrc, insert the register directly between the quotes with :help i_ctrl-r:
let #a = '
<C-r>a
'
<Esc>
Note that it doesn't protect the register in any way so #a can be overwritten accidentally. A mapping, the right hand side of which is a macro, seems safer to me:
" again, use <C-v><C-r> to insert `^R`
xnoremap <key> c**^R"**^[
" or use the angled brackets notation
xnoremap <key> c**<C-r>"**<Esc>

Vim - capture in between slashes?

Is there a motion for capturing text in between / or \? I know there is motions for other symbols ---
ci" - Capture 'text' inside "text"
vi( - Visual capture int var inside foo(int var)
di[ - Delete word [word] into []
The only workaround I can find is by using Vim Surround, and using it to change surrounding \ into " (cs\"), and then working from there. However, not only is it that kind of tedious, but the plugin only supports backslashes, not forward.
You could write your own text-object for this pretty easily.
onoremap <silent> i/ :<C-U>normal! T/vt/<CR> " inside /
onoremap <silent> a/ :<C-U>normal! F/vf/<CR> " around /
For it to work with visual mode :
xnoremap <silent> i/ :<C-U>normal! T/vt/<CR> " inside /
xnoremap <silent> a/ :<C-U>normal! F/vf/<CR> " around /
Similarly you could also do for \
Edit: Added info comments.
Here's one way to do it with a mapping:
nnoremap H mal??e+1<Enter>mb//<Enter>y`b`a
This mapping will yank everything between two occurrences of the last search pattern.
Place it in your .vimrc file to make it permanent.
Usage for your question:
search for forward slash: /\/ (note the backslash escape character)
position cursor between two slashes (or on second slash)
press H
Everything between the last / and the next / will get yanked.
Explanation:
nnoremap H mal??e+1<Enter>mb//<Enter>y`b`a
- nnoremap H map H in normal mode, ignoring other mappings
- ma place a mark (named a) at the current cursor location
- l move the cursor one char to the right
- ??e+1<Enter> move to 1 character after END of prev occurrence of last search pattern
- mb place a mark (named b) at the current cursor location
- //<Enter> go to the beginning of the next occurrence of the last search pattern
- y`b yank to the location of the mark named x (note: ` = "back tick")
- `a go to the mark named `a`
Example input:
This is a *funky* string
search for *
position cursor between two asterisks (or on 2nd asterisk)
press H
The word funky will be in the yank buffer.
You can use words as delimeters!
Example input:
<br>
Capture all this text.
<br>
search for <br>
press H in normal mode when between <br>s (or on 2nd <br>)
You can use regexes, too!
Example input:
<p>
Capture this paragraph.
</p>
search for <.\?p> (or <\/\{,1}p> to be more correct)
press H in normal mode when inside the paragraph (or on closing <p> tag)
...
A better approach might be to use a register to remember a delimiter, so you can use this mapping quickly and/or repeatedly. In other words, you could store / or \ or <\?p> in a register and use that to quickly capture text between your stored delimiter.
there is no built-in text object with slash. However there are plugins support customized text-object, like:
targets
A recently proposed Vim patch adds a text object for arbitrary matched pairs:
https://groups.google.com/d/topic/vim_dev/pZxLAAXxk0M/discussion

Creating a command that replaces the word under the cursor with another one?

I want to create a command that replaces the word under the cursor by another one, say I have the word have under my cursor and it replaces it with the word had and vice versa. How to accomplish that?
This could easily be accomplished by ciw and then entering the word that you would like to replace it with. Assuming that you want to replace words with different values.
Another solution is you could use a plugin like switch.vim. You would have to define the words/regular expressions you would want to replace.
If you actually want to do this with longer words, then this method may help. First, position the cursor on the word "had" and use yiw to yank (copy) it into the #0 register (and also the unnamed register, but we are about to overwrite that). Then move the cursor to "have" and use ciw<C-R>0<Esc> to replace it with the yanked word.
Do not type <C-R> as five characters: I mean hold down the CTRL key and type r. Similarly, <Esc> means the escape key. Do type each as five characters if you want to make a map out of it, for example
:nmap <F2> ciw<C-R>0<Esc>
If you want to replace all occurrences of the word under the cursor, you can add this into your _vimrc:
" search and replace all occurrences of word under cursor
:nnoremap <C-h> :%s/\<<C-r><C-w>\>/
:inoremap <C-h> <ESC>:%s/\<<C-r><C-w>\>/
Usage of this:
1) Press Ctrl+h (under the cursor is the word "have"), and Vim will enter this in the command line:
:%s/\<have\>/
2) Now just complete the replacing statement:
:%s/\<have\>/had/g
3) And press ENTER...
The SwapIt - Extensible keyword swapper allows you to configure sets of words (e.g. have and had) and toggle them via <C-a> / <C-x> mappings.

Search forward for the [count]'th occurrence of the text selected in visual mode

I want to search, like I do with the * command, for a pattern I have selected in visual mode.
I am aware of visual mode yanking, which fills the register 0 by default, and the possibility of just searching by / and then Ctrl-R (retrieving) the contents of register 0 (Ctrl-R, 0) to paste the pattern as a search.
Thing is, I do not want to YANK first, I already have something yanked, I just want to search for what's selected in visual mode now.
How can I do that, please? Can I do that without fiddling with different "yank to register N" tricks?
If you use gvim or console vim built with X support (check if 'guioption' is available) and a is present in your 'guioptions', then you can get current selection from * register. Otherwise, I'm afraid there is no easy way to do that without writing a VimL function, which will extract the selection based on values of < and > marks. That function then can be used with CTRL-R = in the search prompt.
Why don't you just combine all the steps you've outlined into a mapping? The only thing missing is saving and restoring the unnamed register, and a little bit of escaping.
" Atom \V sets following pattern to "very nomagic", i.e. only the backslash has special meaning.
" As a search pattern we insert an expression (= register) that
" calls the 'escape()' function on the unnamed register content '##',
" and escapes the backslash and the character that still has a special
" meaning in the search command (/|?, respectively).
" This works well even with <Tab> (no need to change ^I into \t),
" but not with a linebreak, which must be changed from ^M to \n.
" This is done with the substitute() function.
" gV avoids automatic reselection of the Visual area in select mode.
vnoremap <silent> * :<C-U>let save_unnamedregister=##<CR>gvy/\V<C-R><C-R>=substitute(escape(##,'/\'),"\n",'\\n','ge')<CR><CR>:let ##=save_unnamedregister<Bar>unlet save_unnamedregister<CR>gV
Here's the solution that works for me to make * work with [count] in visual mode:
vnoremap * :call <SID>VisualSearch()<cr>:set hls<cr>
fun! s:VisualSearch() range
let unnamed = #"
let repeat = v:count
exe 'norm gv"zy' | let #/ = #z
for x in range(repeat)
call search(#/, 'ws')
endfor
let #" = unnamed
endfun
You change the "z"s on line five to whatever registers you never use.

Need script/function/command to surround text with other text

I'm new to scripting in Vim. I need to write a script that surrounds a piece of text with other text. For example:
\surroundingtext{surrounded text}
(yes it is for LaTeX). I want to either highlight "surrounded text" and issue the command, or have "surrounded text" the result of a regular expression command.
I guess the question is, how to put this in a function?
Thanks,
Jeremy
Here's what I do:
vnoremap <buffer> <leader>sur "zc\surroundingtext{<C-R>z}<Esc>
This creates a visual-mode mapping where you can characterwise-visual select (v) the text that you want to surround, type \sur (assuming a default mapleader of \) and the text will be surrounded by the text you specified.
"z specifies register 'z'
c tells vim to change the visually selected text, placing the original text in register 'z'
\surroundingtest is the left-side
<C-R>z tells Vim to paste register 'z'
} is the right-side
<Esc> puts you back in normal-mode
I also take it a step further and create normal-mode and insert-mode mappings as well:
nnoremap <buffer> <leader>sur i\surroundingtext{}<Esc>i
inoremap <buffer> <leader>sur \surroundingtext{}<Esc>i
You could place these mappings in your ~/.vimrc file but they would be mapped for every filetype.
A better place for them would be your ~/.vim/after/ftplugin/tex.vim file so they're only mapped when your filetype is tex. Create the parent directories if they don't already exist.
This assumes that the filetype is correctly set to tex and you have filetype plugins enabled:
filetype plugin on
I asked a very similar question a few weeks ago. How to repeatedly add text on both sides of a word in vim? There are good starting points in the answers.
I would recommend using visual selection since you need to surround arbitrary chunks of text instead of a single word. Enter visual selection mode by pressing v, then select the text you wish to surround. Next record a macro with the desired modification using the following key strokes:
qa " record a macro in buffer a
x " cut the selected text
i " enter insert mode
prefix " type the desired prefix
<esc> " exit insert mode
p " paste the cut text
a " enter insert mode after the pasted text
postfix " type the desired postfix
<esc> " exit insert mode
q " stop recording
To reuse the macro simply visually select the next block you would like to modify and press #a.
This may be too cumbersome if the surrounding text varies frequently, or if you want this to persist across editing sessions. In that case you would probably want to write a vim script function to handle it in a more robust way.

Resources