FANDOM


(Insert TipProposed template + minor manual clean)
(Reword to clarify purpose, and improve script)
Line 9: Line 9:
 
|subpage=/200804
 
|subpage=/200804
 
}}
 
}}
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>.
+
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:
   
 
<pre>
 
<pre>
function! Gather( line_pattern )
+
" Gather search hits, and display in a new scratch buffer.
if empty(a:line_pattern)
+
function! Gather(pattern)
return
+
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
 
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>
 
   
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.
+
" Delete the current buffer if it is a scratch buffer (any changes are lost).
 
<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
else
+
return 1
" 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>
   
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.
+
In Vim, the command <tt>:source filter.vim</tt> will execute the script.
   
  +
Assuming the default leader key (backslash), you can now:
  +
*Type <tt>\f</tt> and enter a pattern when prompted.
  +
*Type <tt>\F</tt> 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 <tt>*</tt> to search for the next occurrence of that word. If you now type <tt>\F</tt> 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>
nmap ,f :call Gather( input("Filter on term: ") )<CR>
+
" Print all lines that contain "pattern".
nmap ,F :call Gather( @/ )<CR>
+
:g/pattern/p
nmap <Esc> :call CloseScratch()<CR>
+
" Following is equivalent.
  +
:g/pattern
 
</pre>
 
</pre>
   
In this case, <tt>,f</tt> asks the user for input, <tt>,F</tt> re-uses the search register.
+
The following will delete all lines that do not contain a pattern, leaving only the search hits. You could then press <tt>u</tt> to undo the changes.
  +
<pre>
  +
:v/pattern/d
  +
</pre>
   
 
==See also==
 
==See also==

Revision as of 09:49, May 9, 2008

Proposed tip Please edit this page to improve it, or add your comments below (do not use the discussion page).

Please use new tips to discuss whether this page should be a permanent tip, or whether it should be merged to an existing tip.
created April 22, 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

Community content is available under CC-BY-SA unless otherwise noted.