Vim Tips Wiki
(Insert TipProposed template + minor manual clean)
(→‎See also: link to target of merged link)
 
(5 intermediate revisions by 2 users not shown)
Line 1: Line 1:
  +
{{TipNew
{{TipProposed
 
|id=0
+
|id=1557
|previous=0
+
|previous=1556
|next=0
+
|next=1558
|created=April 22, 2008
+
|created=2008
 
|complexity=basic
 
|complexity=basic
 
|author=Niels AdB
 
|author=Niels AdB
 
|version=7.0
 
|version=7.0
 
|subpage=/200804
 
|subpage=/200804
  +
|category1=
  +
|category2=
 
}}
 
}}
  +
You may want to list all lines in the current buffer that match a pattern, for example, list all lines containing "Warning". The following script copies all matching lines to a scratch (temporary) buffer. You can then examine the list, or save it to a file.
This is a little function you can use to quickly filter a whole buffer for a term, with a convenient shortcut for the term you just searched for (available in register <tt>@/</tt>). It's similar to the search function in e.g. mutt or mocp, only the output is written to a scratch buffer rather than modifying the current buffer. If you want the former behaviour, use an Ex command like <tt>:v/EXP/d</tt>, which deletes all lines that don't match <tt>EXP</tt>.
 
  +
  +
Create a file called (for example) filter.vim containing:
   
 
<pre>
 
<pre>
 
" Gather search hits, and display in a new scratch buffer.
function! Gather( line_pattern )
+
function! Gather(pattern)
if empty(a:line_pattern)
+
if !empty(a:pattern)
return
 
 
let save_cursor = getpos(".")
 
let orig_ft = &ft
  +
" append search hits to results list
 
let results = []
 
execute "g/" . a:pattern . "/call add(results, getline('.'))"
 
call setpos('.', save_cursor)
 
if !empty(results)
 
" put list in new scratch buffer
 
new
 
setlocal buftype=nofile bufhidden=hide noswapfile
 
execute "setlocal filetype=".orig_ft
 
call append(1, results)
  +
1d " delete initial blank line
 
endif
 
endif
 
endif
 
" fill gather list, return if there are no results
 
let gather_list = []
 
let l:orig = getpos(".")
 
let l:orig_ft = &ft
 
execute "g/" . a:line_pattern . "/call insert(gather_list, getline(\".\"))"
 
call setpos(".", l:orig)
 
if empty(gather_list)
 
return
 
endif
 
 
" create new scratch buffer
 
new
 
setlocal buftype=nofile
 
setlocal bufhidden=hide
 
setlocal noswapfile
 
execute "setlocal filetype=".l:orig_ft
 
 
" copy all results in the new scratch buffer
 
for line in gather_list
 
call append(0, line)
 
endfor
 
normal ddgg
 
unlet gather_list
 
 
endfunction
 
endfunction
</pre>
 
   
  +
" Delete the current buffer if it is a scratch buffer (any changes are lost).
This function can be used to quickly close a scratch buffer. I mapped it to <Esc> in normal mode, so that's the keystroke this function defaults to if the current buffer is not a scratch buffer. We don't want to close "real" buffers that easily. You might want to change that line to the key you're mapping this function onto.
 
 
<pre>
 
 
function! CloseScratch()
 
function! CloseScratch()
 
if &buftype == "nofile" && &bufhidden == "hide" && !&swapfile
 
if &buftype == "nofile" && &bufhidden == "hide" && !&swapfile
 
" this is a scratch buffer
 
" this is a scratch buffer
 
bdelete
 
bdelete
 
return 1
else
 
" this is not a scratch buffer
 
normal! "<Esc>"
 
 
endif
 
endif
  +
return 0
 
endfunction
 
endfunction
  +
 
nnoremap <silent> <Leader>f :call Gather(input("Search for: "))<CR>
 
nnoremap <silent> <Leader>F :call Gather(@/)<CR>
 
nnoremap <silent> <Esc> :call CloseScratch()<CR>
 
</pre>
 
</pre>
   
  +
In Vim, the command <code>:source filter.vim</code> will execute the script.
And finally some key mappings to make it all available. I'm using <tt>,</tt> as a mapleader and find using "generic" binding such as <tt>execute "nmap" g:mapleader."f :call Whatever()<CR>"</tt> not very readable in my vimrc. Adjust as needed.
 
   
  +
Assuming the default leader key (backslash), you can now:
  +
*Type <code>\f</code> and enter a pattern when prompted.
  +
*Type <code>\F</code> to filter on the last search pattern.
  +
*Press Escape to close the scratch buffer listing the search hits.
  +
  +
For example, you could put the cursor on a word and press <code>*</code> to search for the next occurrence of that word. If you now type <code>\F</code> a new window will open with a list of all lines that contain the word you searched for. Press Escape to close the window.
  +
  +
==Alternative procedures==
  +
A simple procedure to list all lines matching a pattern is:
 
<pre>
 
<pre>
  +
" Print all lines that contain "pattern".
nmap ,f :call Gather( input("Filter on term: ") )<CR>
 
  +
:g/pattern/p
nmap ,F :call Gather( @/ )<CR>
 
  +
" Following is equivalent.
nmap <Esc> :call CloseScratch()<CR>
 
  +
:g/pattern
 
</pre>
 
</pre>
   
  +
The following will delete all lines that do not contain a pattern, leaving only the search hits. You could then press <code>u</code> to undo the changes.
In this case, <tt>,f</tt> asks the user for input, <tt>,F</tt> re-uses the search register.
 
 
<pre>
  +
:v/pattern/d
 
</pre>
   
 
==See also==
 
==See also==
 
*[[Folding with Regular Expression]] to fold away lines without a search pattern rather than modifying it or using a scratch buffer
 
*[[Folding with Regular Expression]] to fold away lines without a search pattern rather than modifying it or using a scratch buffer
*[[Search for lines not containing pattern]] for some simple techniques to display lines of interest
+
*[[Search_for_lines_not_containing_pattern_and_other_helpful_searches#Using_the_:v_command]] for some simple techniques to display lines of interest
  +
*[[VimTip478|Copy the search results into clipboard]] to copy matching patterns (not lines)
  +
*[[VimTip1063|Redirect g search output]] uses <code>:redir</code> with <code>g//p</code> for a limited one-line version of this tip
  +
*[[VimTip1141|List lines with current search pattern highlighted]] defines command <code>PP</code> to highlight matches displayed with <code>:g//PP</code>
   
 
==Comments==
 
==Comments==

Latest revision as of 15:25, 1 July 2013

Tip 1557 Printable Monobook Previous Next

created 2008 · complexity basic · author Niels AdB · version 7.0


You may want to list all lines in the current buffer that match a pattern, for example, list all lines containing "Warning". The following script copies all matching lines to a scratch (temporary) buffer. You can then examine the list, or save it to a file.

Create a file called (for example) filter.vim containing:

" Gather search hits, and display in a new scratch buffer.
function! Gather(pattern)
  if !empty(a:pattern)
    let save_cursor = getpos(".")
    let orig_ft = &ft
    " append search hits to results list
    let results = []
    execute "g/" . a:pattern . "/call add(results, getline('.'))"
    call setpos('.', save_cursor)
    if !empty(results)
      " put list in new scratch buffer
      new
      setlocal buftype=nofile bufhidden=hide noswapfile
      execute "setlocal filetype=".orig_ft
      call append(1, results)
      1d  " delete initial blank line
    endif
  endif
endfunction

" Delete the current buffer if it is a scratch buffer (any changes are lost).
function! CloseScratch()
  if &buftype == "nofile" && &bufhidden == "hide" && !&swapfile
    " this is a scratch buffer
    bdelete
    return 1
  endif
  return 0
endfunction

nnoremap <silent> <Leader>f :call Gather(input("Search for: "))<CR>
nnoremap <silent> <Leader>F :call Gather(@/)<CR>
nnoremap <silent> <Esc> :call CloseScratch()<CR>

In Vim, the command :source filter.vim will execute the script.

Assuming the default leader key (backslash), you can now:

  • Type \f and enter a pattern when prompted.
  • Type \F to filter on the last search pattern.
  • Press Escape to close the scratch buffer listing the search hits.

For example, you could put the cursor on a word and press * to search for the next occurrence of that word. If you now type \F a new window will open with a list of all lines that contain the word you searched for. Press Escape to close the window.

Alternative procedures[]

A simple procedure to list all lines matching a pattern is:

" Print all lines that contain "pattern".
:g/pattern/p
" Following is equivalent.
:g/pattern

The following will delete all lines that do not contain a pattern, leaving only the search hits. You could then press u to undo the changes.

:v/pattern/d

See also[]

Comments[]