Vim Tips Wiki
(more wikify and minor tweaks)
(start cleaning comments; replace script with something rather nice)
Line 45: Line 45:
   
 
The last member of the set is <tt>\_.</tt>, which matches any character in the buffer, including line-ends. <tt>\_.*</tt> matches the rest of the buffer from the current position. Use this with caution, because it can easily match much more than you want or slow down your search considerably. Consider using a non-greedy search (<tt>\_.\{-}</tt>) instead.
 
The last member of the set is <tt>\_.</tt>, which matches any character in the buffer, including line-ends. <tt>\_.*</tt> matches the rest of the buffer from the current position. Use this with caution, because it can easily match much more than you want or slow down your search considerably. Consider using a non-greedy search (<tt>\_.\{-}</tt>) instead.
  +
  +
==See also==
  +
*[[VimTip171|Search for visually selected text]] to search for selected text; finds targets on multiple lines
   
 
==References==
 
==References==
Line 51: Line 54:
 
==Comments==
 
==Comments==
 
{{todo}}
 
{{todo}}
  +
*Fix TOC (put a short intro at top with a new heading for the bulk of the tip).
*Sort out following mess. A very quick scan suggests some later comments fix problems/questions in earlier comments.
 
  +
*Check following.
*What is the Python script at the bottom? Surely way over-the-top?
 
  +
*Re "search for html comments": I quickly merged this without much thought, and there is more to do. There is sure to be one good regex to do what is wanted.
Haven't got time to look now. [[User:JohnBeckett|JohnBeckett]] 22:48, November 6, 2009 (UTC)
 
  +
*Re blanksearch: I replaced the Python code (and omitted the link to some Vim script), and renamed the function to SearchMultiLine.
----
 
  +
*After checking, need to put following into tip.
To seek out HTML comments over ''multiple'' lines, for example:
 
 
With a little more work, this might be the next featured tip. <tt>:S!</tt> is very clever. [[User:JohnBeckett|JohnBeckett]] 04:24, November 8, 2009 (UTC)
  +
 
===Search for HTML comments that cover multiple lines===
  +
The following search finds HTML comments that cover one or more lines:
 
<pre>
 
<pre>
<!-- foobar does
+
/<!--\_p\{-}-->
not exist -->
 
 
</pre>
 
</pre>
   
  +
Example comment:
Use the search:
 
 
<pre>
 
<pre>
/<!--\_p\{-}-->
+
<!-- This comment
  +
covers multiple lines. -->
 
</pre>
 
</pre>
   
Line 79: Line 86:
 
This can slow things down on large files with complex highlighting. {{help|:syn-sync}}
 
This can slow things down on large files with complex highlighting. {{help|:syn-sync}}
   
  +
Comments that include tab characters (for example, as indents) are not found by the above because <tt>\_p</tt> matches printable characters and newline, but not tab).
----
 
For some reason <tt>&lt;!--\_p\{-}--></tt> doesn't work if your comments are indented (with opening and closing comment tag indented).
 
   
 
Here's another way to highlight HTML comments using conventional regex:
 
Here's another way to highlight HTML comments using conventional regex:
 
<pre>
 
<pre>
/<\!--\(.\|\n\)*-->
+
/<\!--\(.\|\n\)\{-}-->
 
</pre>
 
</pre>
   
  +
===Search for words over multiple lines===
However, this one will spill over to the next comment if there's more than one so it's not too useful.
 
  +
The script below defines command <tt>:S</tt> that will search for a phrase, even when the words are on different lines. Examples:
   
  +
;<tt>:S hello world</tt>
----
 
  +
:Searches for "hello" followed by "world", separated by whitespace including newlines.
The Tab character is among the control chars, thus not matched with <tt>\p</tt> per default.
 
  +
;<tt>:S! hello world</tt>
  +
:Searches for "hello" followed by "world", separated by any non-word characters (whitespace, newlines, punctuation).
   
  +
After entering the command, press <tt>n</tt> or <tt>N</tt> to search for the next or previous occurrence.
----
 
The script attached to http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=256743 offers a convenient way to address this issue, you can type ":S foo bar" and it is translated to "/sfoo\_s\+bar"
 
   
  +
Put the following in your [[vimrc]] (or in file <tt>searchmultiline.vim</tt> in your plugin directory):
This works even better for me. Put the following into file <tt>~/.vim/project/blanksearch.vim</tt>:
 
 
<pre>
 
<pre>
  +
" Search for the ... arguments separated with whitespace (if no '!'),
:py <<EOF
 
  +
" or with non-word characters (if '!' added to command).
import vim
 
  +
function! SearchMultiLine(bang, ...)
def MySearch(*args):
 
  +
if a:0 > 0
s="\\_s\\+".join(args)
 
  +
let sep = (a:bang) ? '\_W\+' : '\_s\+'
vim.command("/"+s)
 
  +
let @/ = join(a:000, sep)
EOF
 
  +
endif
command -nargs=* -complete=tag S :py MySearch(<f-args>)
 
  +
endfunction
 
command! -bang -nargs=* -complete=tag S call SearchMultiLine(<bang>0, <f-args>)|normal! /<C-R>/<CR>
 
</pre>
 
</pre>
 
Note the tab (not spaces!) in the two indented lines.
 
 
The advantage of this version is that <tt>N</tt> and <tt>n</tt> work afterwards.
 
   
 
----
 
----

Revision as of 04:24, 8 November 2009

Tip 242 Printable Monobook Previous Next

created 2002 · complexity intermediate · author vim_power · version 6.0


One of the most uncelebrated features of Vim is the ability to span a search across multiple lines.

All of the following match line beginnings or endings anywhere in the search pattern, unlike ^ and $.

\n the newline character itself
\_^ the beginning of a line
\_$ the end of a line but before any newline character
\_s a space, tab character, or newline character

For example, /{\_s finds { followed by a whitespace or newline character.

Some of these can be confusing to work with. For example, this works as expected:

end one line\_^begin the next

\_$ is not equivalent. It also is a zero-length marker, but that means the end-of-line characters remain between it and the next line. The following never matches, because u doesn't match the end-of-line character.

end one line\_$um

This does what you want:

end one line\nnext line

\_s is a different kind of beast. You can insert the underscore in any of the character-class atoms to include line-ends in the class. In this case the match position moves past a line-end when it matches. This means you can search for things like \_S\+ to match any sequence of NON-whitespace characters, even across multiple lines, or \_[abc] to match sequences of characters containing only the letters a, b, or c, that can span multiple lines.

The last member of the set is \_., which matches any character in the buffer, including line-ends. \_.* matches the rest of the buffer from the current position. Use this with caution, because it can easily match much more than you want or slow down your search considerably. Consider using a non-greedy search (\_.\{-}) instead.

See also

References

Comments

 TO DO 

  • Fix TOC (put a short intro at top with a new heading for the bulk of the tip).
  • Check following.
  • Re "search for html comments": I quickly merged this without much thought, and there is more to do. There is sure to be one good regex to do what is wanted.
  • Re blanksearch: I replaced the Python code (and omitted the link to some Vim script), and renamed the function to SearchMultiLine.
  • After checking, need to put following into tip.

With a little more work, this might be the next featured tip. :S! is very clever. JohnBeckett 04:24, November 8, 2009 (UTC)

Search for HTML comments that cover multiple lines

The following search finds HTML comments that cover one or more lines:

/<!--\_p\{-}-->

Example comment:

<!-- This comment
 covers multiple lines. -->

We used \{-} the "few as possible" operator rather than * which is too greedy when there are many such comments in the file.

The key is of course \_p which is printable characters including EOL end-of-lines.

However, the highlighting is very erratic when the span over number of lines exceeds, say, 30. And highlighting is rather spotty when there are shifts in screen views. This is due to the default that improves highlighting performance.

If you want to ensure the most accurate highlighting, try:

:syntax sync fromstart

This can slow things down on large files with complex highlighting. :help :syn-sync

Comments that include tab characters (for example, as indents) are not found by the above because \_p matches printable characters and newline, but not tab).

Here's another way to highlight HTML comments using conventional regex:

/<\!--\(.\|\n\)\{-}-->

Search for words over multiple lines

The script below defines command :S that will search for a phrase, even when the words are on different lines. Examples:

:S hello world
Searches for "hello" followed by "world", separated by whitespace including newlines.
:S! hello world
Searches for "hello" followed by "world", separated by any non-word characters (whitespace, newlines, punctuation).

After entering the command, press n or N to search for the next or previous occurrence.

Put the following in your vimrc (or in file searchmultiline.vim in your plugin directory):

" Search for the ... arguments separated with whitespace (if no '!'),
" or with non-word characters (if '!' added to command).
function! SearchMultiLine(bang, ...)
  if a:0 > 0
    let sep = (a:bang) ? '\_W\+' : '\_s\+'
    let @/ = join(a:000, sep)
  endif
endfunction
command! -bang -nargs=* -complete=tag S call SearchMultiLine(<bang>0, <f-args>)|normal! /<C-R>/<CR>