Copy the search results into clipboard
From Vim Tips Wiki
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 start with methods to easily list search hits, without copying them.
Contents[show] |
edit 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
On some systems, at the "Press ENTER or type command to continue" prompt, you can select displayed text with the mouse then press Ctrl-Y to copy the selection to the clipboard. :help press-enter
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.
edit 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 (see Power of g). The first command clears register a (:help q). The second appends all matching lines to that register (:help quotea). The third copies register a to the clipboard (register +) for easy pasting into another application. Replace pattern with what you want to search for.
qaq :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. " BUG: 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
edit 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 procedure allows you to copy just the text which matches a pattern. Source the CopyMatches command and function, then perform the search above. To copy all matching text to the clipboard, enter the following.
:CopyMatches
The command can also copy matches from a range of lines, and can copy into a register other than the clipboard. For example, the first of the following copies all matches in lines 1 to 10 inclusive to register a, and the second copies matches from the current line (.) to the default register ("):
:1,10CopyMatches a :.CopyMatches "
The script includes let end += 1 to handle searches with a pattern like .\{-}\ze, which matches characters (as few as possible) up to, but not including, a comma. It is necessary to increment end to get past the comma.
" Copy matches of the last search to a register (default is the clipboard). " Accepts a range (default is whole file). " 'CopyMatches' copy matches to clipboard (each match has \n added). " 'CopyMatches x' copy matches to register x (clears register first). " 'CopyMatches X' append matches to register x. " We skip empty hits to ensure patterns using '\ze' don't loop forever. command! -range=% -register CopyMatches call s:CopyMatches(<line1>, <line2>, '<reg>') function! s:CopyMatches(line1, line2, reg) let hits = [] for line in range(a:line1, a:line2) let txt = getline(line) let idx = match(txt, @/) while idx >= 0 let end = matchend(txt, @/, idx) if end > idx call add(hits, strpart(txt, idx, end-idx)) else let end += 1 endif if @/[0] == '^' break " to avoid false hits endif let idx = match(txt, @/, end) endwhile endfor if len(hits) > 0 let reg = empty(a:reg) ? '+' : a:reg execute 'let @'.reg.' = join(hits, "\n") . "\n"' else echo 'No hits' endif 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
edit See also
- Redirect g search output to redirect g// output to a new window or a file
- Filter buffer on a search result to create a scratch buffer with matching lines
- Find in files within Vim for a clickable list of search hits
- Folding with Regular Expression to fold away non-matching lines
edit Comments
TO DO
- The code for multiline matching needs fixing (see 'BUG').