Vim Tips Wiki
(Thanks Inkarkat; will fix later)
(Change <tt> to <code>, perhaps also minor tweak.)
(10 intermediate revisions by 6 users not shown)
Line 1: Line 1:
  +
{{TipNew
__NOTOC__
 
 
|id=1597
{{TipProposed
 
 
|previous=1596
|id=0
 
 
|next=1598
|previous=0
 
 
|created=2008
|next=0
 
|created=July 31, 2008
 
 
|complexity=basic
 
|complexity=basic
 
|author=[[User:JohnBeckett|John Beckett]]
 
|author=[[User:JohnBeckett|John Beckett]]
Line 12: Line 11:
 
|category2=
 
|category2=
 
}}
 
}}
When searching, you may want to operate on the text found by the search. Typically, you want to copy the search hit, or change it (delete the hit, and enter insert mode so you can type in new text).
+
While searching, you may want to operate on the text found by a search. Typically, you want to copy a search hit, or change it (delete the hit, and enter insert mode so you can type in new text). Often one of the standard commands can be used (for example, if you searched for a complete word, the command <code>cw</code> may be sufficient to change it).
   
  +
A more general approach comes from the fact that <code>//e</code> can be used to repeat the last search (because no new search pattern was entered), with the <code>e</code> search offset to move the cursor to the end of the search hit. {{help|search-offset}}
For example, search for all words that start with 'a' and end with 'e':
 
  +
  +
For example, after searching, you may want to change the hit. Without implementing this tip, you could type <code>c//e</code> and press Enter. Then enter the replacement text and press Escape.
  +
 
==A search text object==
  +
With this tip, after searching you can:
 
*Type <code>ys</code> to copy the search hit.
 
*Type <code>"+ys</code> to copy the hit to the clipboard.
 
*Type <code>cs</code> to change the hit.
 
*Type <code>gUs</code> to convert the hit to uppercase.
 
*Type <code>vs</code> to visually select the hit. If you type another <code>s</code> you will extend the selection to the end of the next hit.
  +
  +
For example, search for 'File' and change it to 'Data' (<code>cs</code> = change search):
 
<pre>
 
<pre>
  +
/File
/\<a\w*e\>
 
  +
csData<Esc>
" Words to search: area are above is active and alive to amaze
 
  +
" Sample to search: GetFileDir GetFileId GetFilePos MyFile BackupFile
 
</pre>
 
</pre>
   
Enter the search command, then press <tt>n</tt> or <tt>N</tt> for the next or previous hits. After implementing this tip, you could:
+
Then press <code>n</code> to find the next occurrence and press <code>.</code> to repeat the change.
*Type <tt>ys</tt> to copy the search hit.
 
*Type <tt>"+ys</tt> to copy the hit to the clipboard.
 
*Type <tt>cs</tt> to change the hit.
 
*After <tt>cs</tt>, press <tt>n</tt> for the next hit, then <tt>.</tt> to repeat the change.
 
*Type <tt>gUs</tt> to convert the hit to uppercase.
 
*Type <tt>vs</tt> to visually select the hit. If you type another <tt>s</tt> you will extend the selection to the end of the next hit.
 
   
 
Put the following in your [[vimrc]]:
 
Put the following in your [[vimrc]]:
 
<pre>
 
<pre>
 
" Make a simple "search" text object.
 
" Make a simple "search" text object.
vnoremap s //e<CR>
+
vnoremap <silent> s //e<C-r>=&selection=='exclusive'?'+1':''<CR><CR>
 
\:<C-u>call histdel('search',-1)<Bar>let @/=histget('search',-1)<CR>gv
nnoremap n //<CR>
 
nnoremap N ??<CR>
 
 
omap s :normal vs<CR>
 
omap s :normal vs<CR>
 
</pre>
 
</pre>
   
 
==Explanation==
 
==Explanation==
This tip implements a simple search text object identified as "s". When in visual mode, the <tt>vnoremap</tt> command translates "<tt>s</tt>" to "<tt>//e</tt>" which is an empty search (search for the next hit), with the "e" flag (position at the end of the match).
+
This tip implements a simple search text object identified as "s". When in visual mode, <code>s</code> is mapped to find the end of the last search pattern (<code>//e</code>). When in operator-pending mode (for example, after pressing <code>y</code> in normal mode), <code>s</code> is mapped to normal-mode <code>vs</code> which starts visual mode (assuming <code>v</code> has not been mapped) and invokes the <code>s</code> visual-mode mapping.
   
  +
The <code><C-r>=</code> evaluates the following expression which tests the <code>'selection'</code> option. If exclusive selection is used, the result is <code>'+1'</code>, otherwise the result is an empty string. Accordingly, the visual-mode map becomes <code>//e+1</code> or <code>//e</code>. {{help|search-offset}}
The two <tt>nnoremap</tt> commands mean <tt>n</tt> will search forwards, with no search flag (to position the cursor at the start of the next hit), and similarly, <tt>N</tt> will search backwards. If these mappings are not used, <tt>n</tt> will repeat the search, including the "e" flag, which would position the cursor at the end of the next match.
 
   
  +
The visual-mode mapping continues with <code>:<C-u></code> to enter the command line while removing the visual range automatically inserted by Vim. The <code>histdel</code> function removes the last (<code>-1</code>) item from the search history (<code>'//e+1'</code> or <code>'//e'</code>). The <code>let</code> statement assigns the previous search item to <code>@/</code> (the search register) so pressing <code>n</code> or <code>N</code> will search for the next or previous instance.
The <tt>omap</tt> command translates "<tt>s</tt>" when it is pressed in operator-pending mode (for example, after pressing <tt>y</tt> for the yank operator). The command <tt>:normal vs</tt> performs <tt>vs</tt> in normal mode. Provided <tt>v</tt> has not been mapped, the command will start visual mode. Then the <tt>s</tt> will be translated by the <tt>vnoremap</tt>, as described earlier.
 
   
 
In {{help|todo}} we see a plan for a future version of Vim:
 
In {{help|todo}} we see a plan for a future version of Vim:
:Add text object for current search pattern: "<tt>a/</tt>" and "<tt>i/</tt>". Makes it possible to turn text highlighted for <tt>'hlsearch'</tt> into a Visual area.
+
:Add text object for current search pattern: "<code>a/</code>" and "<code>i/</code>". Makes it possible to turn text highlighted for <code>'hlsearch'</code> into a Visual area.
   
 
This tip prefers the simple "s" for a search hit, with no attempt to implement "a" and "i" text objects. Instead, "s" selects from the current position to the end of the next search hit.
 
This tip prefers the simple "s" for a search hit, with no attempt to implement "a" and "i" text objects. Instead, "s" selects from the current position to the end of the next search hit.
  +
  +
The default for visual mode in Vim is that you can press <code>c</code> or <code>s</code> to change a selected area. Using the mapping suggested in this tip, you would no longer be able to press <code>s</code> to change a visual area (use <code>c</code> instead).
  +
  +
==Limitations==
  +
The tip can be helpful to reduce distractions while editing because you can always press <code>ys</code> to yank the hit, or <code>cs</code> to change it (you don't have to think about an alternative method). However, the tip has several limitations:
  +
*Pressing <code>.</code> to repeat a change will change the same ''number'' of characters that were previously changed (so you can only repeat a change when the search hit is a fixed length).
  +
*The text object fails when the search hit is a single character, and when search wraps around the end of the buffer.
  +
*Suppose you use <code>:set selection=exclusive</code> and search for 'abc'. If you find 'abc' at the end of a line, operations such as <code>ys</code> or <code>cs</code> will include the line break.
   
 
==See also==
 
==See also==
Line 57: Line 70:
   
 
==Comments==
 
==Comments==
  +
Might be worth adding these mappings from vim_use. Type <code>,n</code> to search for the next hit and visually select it. For example, searching for <code>\w\+</code> will find the next word, and can then type <code>,n</code> to search for and select the next word after that.
I tried some elaborate schemes to implement a "proper" search text object, however I failed to find anything that worked as well as this simple tip. The tip has some glitches (for example, it's a bit ugly when the search wraps around), and it uses "s" for search, while Vim uses "is" for "inner sentence" and "as" for "a sentence".
 
 
This tip is short enough to be included elsewhere, but it is really useful and might warrant a separate tip. Also, I'm anticipating that someone might enhance it. It would nice if <tt>n</tt> and <tt>N</tt> were not mapped.
 
 
----
 
Why do n and N need mappings? How is this different from the default behavior of n and N?
 
:It's to reverse the effect of the "e" flag. I added a sentence to try and explain that.
 
::You can also solve this by removing the <tt>//e</tt> search from the search history and restoring the previous search pattern. That way, the n/N mappings aren't needed and the text object doesn't clutter the search history. -- [[User:Inkarkat|Inkarkat]] 08:30, 1 August 2008 (UTC)
 
 
<pre>
 
<pre>
 
:nnoremap ,n //b<CR>v//e<CR>
" Make a simple "search" text object.
 
vnoremap s //e<CR>:<C-U>call histdel('search', -1)<Bar>let @/=histget('search', -1)<CR>gv
+
:vnoremap ,n <Esc>//b<CR>v//e<CR>
omap s :normal vs<CR>
 
 
</pre>
 
</pre>
  +
[[User:JohnBeckett|JohnBeckett]] 02:06, July 21, 2011 (UTC)
 
----
 
----
  +
How do these play with surround.vim?
The text object is off by one if you have <tt>set selection=exclusive</tt> or <tt>behave mswin</tt>. Change <tt>//e</tt> into <tt>//e+1</tt>, or use the general (but more complex) following line: -- [[User:Inkarkat|Inkarkat]] 08:30, 1 August 2008 (UTC)
 
<pre>
 
vnoremap s //e<C-R>=&selection=='exclusive'?'+1':''<CR><CR>
 
</pre>
 
   
  +
Also, I actively use visualstar.vim and often create long search patterns from visual selections; the developer uses \V if this is relevant. I often get my vim frozen after typing c//e. Does this tip play any better with visualstar.vim?
==Alternative==
 
Thanks Inkarkat. I hope to think about this more in a couple of days. I've put the following alternative (your suggestion) in my vimrc. Works well so far, although a little ugly. Perhaps I'll end up by replacing the main part of the tip with two alternatives: the following plus a version omitting the check for <tt>&selection</tt>. Also, I plan to replace my example search because instead of <tt>cs</tt> you could just use <tt>cw</tt> (I'll come up with an example where <tt>cs</tt> and <tt>ys</tt> are actually helpful). --[[User:JohnBeckett|JohnBeckett]] 04:29, 4 August 2008 (UTC)
 
 
<pre>
 
vnoremap <silent> s //e<C-R>=&selection=='exclusive'?'+1':''<CR><CR>:<C-U>call histdel('search', -1)<Bar>let @/=histget('search', -1)<CR>gv
 
omap s :normal vs<CR>
 
</pre>
 
 
I note that a few characters can be saved with following trick (but doesn't seem worthwhile):
 
<pre>
 
" Instead of this part:
 
//e<C-R>=&selection=='exclusive'?'+1':''<CR><CR>
 
" could use this:
 
//e+<C-R>=&sel=='exclusive'<CR><CR>
 
</pre>
 

Revision as of 07:56, 11 July 2012

Tip 1597 Printable Monobook Previous Next

created 2008 · complexity basic · author John Beckett · version 7.0


While searching, you may want to operate on the text found by a search. Typically, you want to copy a search hit, or change it (delete the hit, and enter insert mode so you can type in new text). Often one of the standard commands can be used (for example, if you searched for a complete word, the command cw may be sufficient to change it).

A more general approach comes from the fact that //e can be used to repeat the last search (because no new search pattern was entered), with the e search offset to move the cursor to the end of the search hit. :help search-offset

For example, after searching, you may want to change the hit. Without implementing this tip, you could type c//e and press Enter. Then enter the replacement text and press Escape.

A search text object

With this tip, after searching you can:

  • Type ys to copy the search hit.
  • Type "+ys to copy the hit to the clipboard.
  • Type cs to change the hit.
  • Type gUs to convert the hit to uppercase.
  • Type vs to visually select the hit. If you type another s you will extend the selection to the end of the next hit.

For example, search for 'File' and change it to 'Data' (cs = change search):

/File
csData<Esc>
" Sample to search: GetFileDir GetFileId GetFilePos MyFile BackupFile

Then press n to find the next occurrence and press . to repeat the change.

Put the following in your vimrc:

" Make a simple "search" text object.
vnoremap <silent> s //e<C-r>=&selection=='exclusive'?'+1':''<CR><CR>
    \:<C-u>call histdel('search',-1)<Bar>let @/=histget('search',-1)<CR>gv
omap s :normal vs<CR>

Explanation

This tip implements a simple search text object identified as "s". When in visual mode, s is mapped to find the end of the last search pattern (//e). When in operator-pending mode (for example, after pressing y in normal mode), s is mapped to normal-mode vs which starts visual mode (assuming v has not been mapped) and invokes the s visual-mode mapping.

The <C-r>= evaluates the following expression which tests the 'selection' option. If exclusive selection is used, the result is '+1', otherwise the result is an empty string. Accordingly, the visual-mode map becomes //e+1 or //e. :help search-offset

The visual-mode mapping continues with :<C-u> to enter the command line while removing the visual range automatically inserted by Vim. The histdel function removes the last (-1) item from the search history ('//e+1' or '//e'). The let statement assigns the previous search item to @/ (the search register) so pressing n or N will search for the next or previous instance.

In :help todo we see a plan for a future version of Vim:

Add text object for current search pattern: "a/" and "i/". Makes it possible to turn text highlighted for 'hlsearch' into a Visual area.

This tip prefers the simple "s" for a search hit, with no attempt to implement "a" and "i" text objects. Instead, "s" selects from the current position to the end of the next search hit.

The default for visual mode in Vim is that you can press c or s to change a selected area. Using the mapping suggested in this tip, you would no longer be able to press s to change a visual area (use c instead).

Limitations

The tip can be helpful to reduce distractions while editing because you can always press ys to yank the hit, or cs to change it (you don't have to think about an alternative method). However, the tip has several limitations:

  • Pressing . to repeat a change will change the same number of characters that were previously changed (so you can only repeat a change when the search hit is a fixed length).
  • The text object fails when the search hit is a single character, and when search wraps around the end of the buffer.
  • Suppose you use :set selection=exclusive and search for 'abc'. If you find 'abc' at the end of a line, operations such as ys or cs will include the line break.

See also

References

Comments

Might be worth adding these mappings from vim_use. Type ,n to search for the next hit and visually select it. For example, searching for \w\+ will find the next word, and can then type ,n to search for and select the next word after that.

:nnoremap ,n //b<CR>v//e<CR>
:vnoremap ,n <Esc>//b<CR>v//e<CR>

JohnBeckett 02:06, July 21, 2011 (UTC)


How do these play with surround.vim?

Also, I actively use visualstar.vim and often create long search patterns from visual selections; the developer uses \V if this is relevant. I often get my vim frozen after typing c//e. Does this tip play any better with visualstar.vim?