Vim Tips Wiki
(Major reword + new versions of scripts + see also (need to check))
(Fixed some bugs; needs more checking)
Line 49: Line 49:
 
" to copy all lines containing hits (whole lines).
 
" to copy all lines containing hits (whole lines).
 
" The pattern may extend over multiple lines.
 
" The pattern may extend over multiple lines.
  +
" The 'normal! $' attempts to avoid copying the same line more than once.
  +
" FIX: For some patterns, it could miss a second hit?
 
function! CopyMatchingLines()
 
function! CopyMatchingLines()
 
let posinit = getpos(".")
 
let posinit = getpos(".")
Line 54: Line 56:
 
let cnt = 0
 
let cnt = 0
 
let hits = []
 
let hits = []
 
let snum = search(@/, 'cW')
while 1
 
let snum = search(@/, '', line("$"))
+
while snum > 0
if snum == 0
+
let enum = search(@/, 'ceW')
break
 
endif
 
let enum = search(@/, 'e', line("$"))
 
 
call extend(hits, getline(snum, enum))
 
call extend(hits, getline(snum, enum))
 
let cnt += 1
 
let cnt += 1
  +
normal! $
  +
let snum = search(@/, 'W')
 
endwhile
 
endwhile
 
if cnt > 0
 
if cnt > 0
Line 80: Line 81:
   
 
<pre>
 
<pre>
0+y0
+
0"+y0
 
:g//call CopyMatches()
 
:g//call CopyMatches()
 
</pre>
 
</pre>
   
 
<pre>
 
<pre>
" Use 0+y0 to clear the clipboard, then
+
" Use 0"+y0 to clear the clipboard, then
 
" :g/pattern/call CopyMatches()
 
" :g/pattern/call CopyMatches()
 
" to copy all hits (just the text which matches pattern).
 
" to copy all hits (just the text which matches pattern).
Line 92: Line 93:
 
let idx = 0
 
let idx = 0
 
while idx >= 0
 
while idx >= 0
let @+ .= matchstr(lin, '' . @/, idx) . "\n"
+
let @+ .= matchstr(lin, @/, idx) . "\n"
let xEnd = matchend(lin, '' . @/, idx)
+
let xEnd = matchend(lin, @/, idx)
let idx = match(lin, '' . @/, xEnd)
+
let idx = match(lin, @/, xEnd)
 
endwhile
 
endwhile
 
endfunction
 
endfunction
Line 102: Line 103:
   
 
<pre>
 
<pre>
" Use 0+y0 to clear the clipboard, then
+
" Use 0"+y0 to clear the clipboard, then
 
" :g/pattern/call CopyMultiMatches()
 
" :g/pattern/call CopyMultiMatches()
 
" to copy all multiline hits (just the matching text).
 
" to copy all multiline hits (just the matching text).
 
" This is for when the match extends over multiple lines.
 
" This is for when the match extends over multiple lines.
 
" Only the first match from each line is found.
 
" Only the first match from each line is found.
  +
" BUG: When searching for "^function.*\_s*let" the '.*' stops at the end
  +
" of a line, but it greedily skips "\n" in the following (we copy too much).
 
function! CopyMultiMatches()
 
function! CopyMultiMatches()
 
let text = join(getline(".", "$"), "\n") . "\n"
 
let text = join(getline(".", "$"), "\n") . "\n"
let @+ .= matchstr(text, '' . histget("/"), 0) . "\n"
+
let @+ .= matchstr(text, @/) . "\n"
 
endfunction
 
endfunction
 
</pre>
 
</pre>
Line 120: Line 123:
 
==Comments==
 
==Comments==
 
{{Todo}}
 
{{Todo}}
  +
*Have fixed some bugs, but checking shows the problems mentioned in the comments. If the code doesn't work reliably, maybe we shouldn't include it?
*Check above! (I've done a lot of work on this; all scripts are new. No energy left to check them again at the moment.)
 
 
*Probably merge [[VimTip1063]] in to here.
 
*Probably merge [[VimTip1063]] in to here.

Revision as of 11:19, 7 July 2008

Tip 478 Printable Monobook Previous Next

created May 22, 2003 · complexity basic · author JAS · version 7.0


Several methods allow you to capture all search hits. Usually, you want to copy each line which contains text matching your search pattern, but you can also copy just the matching text. We'll start with methods to easily list search hits, without copying them.

Search within a file

To search, press / then type what you want to find, or press * to search for the current word.

To list all lines matching your search pattern, use the following. The first command lists lines matching your last search. The second lists lines matching pattern.

:g/
:g/pattern

To view a window of search results, see Find in files within Vim. You can use % for the file path to search only the current file, for example:

" Save file, search it for 'pattern', and open a clickable list.
:w
:vimgrep /pattern/ %
:copen

To view only the parts of a file that match your pattern, see Folding with Regular Expression. You can fold away non-matching lines, and use zr to reveal more context around the search hits.

Copying lines containing search hits

You can copy matching lines to the clipboard, so they can be pasted into another application.

To copy all lines containing a search pattern, use the following (from Power of g). The first command clears register a. The second appends all matching lines to that register. The third copies register a to the clipboard (register +) for easy pasting into another application. Replace pattern with what you want to search for.

0"ay0
:g/pattern/y A
:let @+ = @a

The above procedure captures only the first line of each match. If your pattern matches more than one line, use the following.

" Use /pattern to search for something, then
"   :call CopyMatchingLines()
" to copy all lines containing hits (whole lines).
" The pattern may extend over multiple lines.
" The 'normal! $' attempts to avoid copying the same line more than once.
" FIX: For some patterns, it could miss a second hit?
function! CopyMatchingLines()
  let posinit = getpos(".")
  call cursor(1, 1)
  let cnt = 0
  let hits = []
  let snum = search(@/, 'cW')
  while snum > 0
    let enum = search(@/, 'ceW')
    call extend(hits, getline(snum, enum))
    let cnt += 1
    normal! $
    let snum = search(@/, 'W')
  endwhile
  if cnt > 0
    let @+ = join(hits, "\n") . "\n"
  endif
  call cursor(posinit[1], posinit[2])
  echomsg cnt 'lines (or blocks) were appended to the clipboard.'
endfunction

Copying only the matching text

A search pattern may use a regular expression. For example, the following finds all words that begin with 'a':

/\<a\w*\>

The following procedures allow you to copy just the text which matches a pattern. Source the CopyMatches() function, and perform the search above. To copy all matching text to the clipboard, enter the following. The first command clears the clipboard. The second appends matching text to the clipboard (since no pattern is given, the last search is used).

0"+y0
:g//call CopyMatches()
" Use 0"+y0 to clear the clipboard, then
"   :g/pattern/call CopyMatches()
" to copy all hits (just the text which matches pattern).
function! CopyMatches()
  let lin = getline(".")
  let idx = 0
  while idx >= 0
    let @+ .= matchstr(lin, @/, idx) . "\n"
    let xEnd = matchend(lin, @/, idx)
    let idx = match(lin, @/, xEnd)
  endwhile
endfunction

The following alternative is to copy matches which extend over more than one line.

" Use 0"+y0 to clear the clipboard, then
"    :g/pattern/call CopyMultiMatches()
" to copy all multiline hits (just the matching text).
" This is for when the match extends over multiple lines.
" Only the first match from each line is found.
" BUG: When searching for "^function.*\_s*let" the '.*' stops at the end
" of a line, but it greedily skips "\n" in the following (we copy too much).
function! CopyMultiMatches()
  let text = join(getline(".", "$"), "\n") . "\n"
  let @+ .= matchstr(text, @/) . "\n"
endfunction

See also

Comments

 TO DO 

  • Have fixed some bugs, but checking shows the problems mentioned in the comments. If the code doesn't work reliably, maybe we shouldn't include it?
  • Probably merge VimTip1063 in to here.