62

Is there a way to hide all lines that did not match, while going through the list of result lines?

In a long file, I would like to search for a pattern that will match roughly 200 lines or so. The matched lines are in random places in the file.
When a line matches, only the line itself is relevant, no context above or below.

Normally, I would search with / and jump through the matches with n.
But that means there are only one or two relevant lines on the screen at a time.

A brute force approach would be to delete all non-matching lines, and undo that deletion later. But that's ugly in various ways, even if it would not end up in persistent undo.

7 Answers 7

65
:vimgrep pattern %
:cwindow

vimgrep will search for your pattern in the current file (%), or whatever files you specify.

cwindow will then open a buffer in your window that will only show the desired lines. You can use pretty much any navigating/search command within the cwin buffer. Press return to jump to the line under your cursor in the source file.

For help:
:help vimgrep
:help cwindow

6
  • 2
    :vimgrep can be abbreviated to :vim
    – D. Ben Knoble
    Jun 11, 2018 at 14:51
  • 1
    how do i get back to the buffer again?
    – pasha
    Dec 2, 2018 at 12:19
  • also how do i close the buffer? thanks in advance
    – pasha
    Dec 2, 2018 at 12:23
  • 1
    From the quickfix (cwindow) buffer you can hit return on any line to jump to that location in the original buffer. You can can close the cwindow buffer from anywhere with :ccl[ose] or however you normally close a buffer (e.g., switch to it and :bd). You can reopen the quickfix buffer by running :cw[indow] again, and it will use your last vimgrep results. Mar 23, 2019 at 12:59
  • :vim YOUR_SEARCH % and :cw, use ctrl_w,ctrl_w to switch between frames
    – sjas
    Mar 5, 2022 at 14:18
40

You can list all matching lines with

:g/{pattern}

(The :print command can be omitted; it is the default for :g.)

5
  • 2
    This is the "original grep" (g/REgexp/p) ... Problem is that you can't easily jump to one of the matches, though... Feb 28, 2015 at 19:44
  • @Carpetsmoker: You're right; for that, I have a plugin, see my other answer. Feb 28, 2015 at 20:00
  • That could be useful for many cases. Can the output be redirected to a new buffer? That would allow to still have syntax highlighting on the lines. (Hmm... that raises another question, wait a second...) Feb 28, 2015 at 20:18
  • @IngoKarkat what is the meaning the g. I assume that it is a global pattern. I usually do VI search with a slash /pattern and this would find all occurrences. One can navigate to them by pressing the letter n Jun 13, 2019 at 8:23
  • 1
    @AlexanderCska: No, it's not a modifier for search, but a separate command :g[lobal] that takes a pattern as an argument. You'll find all details at :help :global. Jun 13, 2019 at 9:41
23

[d]elete all lines not(!) matching patterns:

:g!/pattern/d

or even simpler (thanks for the comments by 'B Layer'):

:v/pattern/d
2
  • 1
    Yeah, but it's more conventional to use the equivalent :v rather than :g!. (I don't remember the last time I saw the latter used, TBH!)
    – B Layer
    Jun 12, 2018 at 4:06
  • If I wasn't used to v being "invert" thanks to the grep (shell) command, I'd find :g! much easier to remember than :v. So as a general recommendation I think :g! works better.
    – Sundar R
    Oct 10, 2021 at 7:43
17

You can use the foldmethod and foldexpr options to fold away irrelevant lines.

After searching, the last search is stored in the @/ register. So, you can readily fold away everything that doesn't match like this (for one-line matches only):

:setlocal foldexpr=getline(v:lnum)=~@/?0:1 foldmethod=expr

More advanced methods, like adding multiple levels of folding for context lines you can show or hide, or matching multiple lines, can be found on the Vim Tips Wiki.

5
  • Seems like there is a set foldlevel=0 needed? But maybe that's default. Feb 28, 2015 at 3:16
  • 1
    Yeah the default is zero, but if it doesn't work without, adding it can't hurt. :-)
    – Ben
    Feb 28, 2015 at 3:18
  • But now... how to switch it back again, with no traces? Feb 28, 2015 at 3:23
  • in normal mode, you can use 'zi' to toggle folding off and on.
    – John O'M.
    Feb 28, 2015 at 4:04
  • Most of the time when I do this I first :tab sp to get a new throwaway view on the file. Then going back is as simple as :close or any other way to kill the tab.
    – Ben
    Feb 28, 2015 at 17:49
10

If order doesn't matter then just move the lines.

:g/pat/m0

For more help see:

:h :g
:h :m
1
  • 2
    And :g/pat/m$ (move the matched lines to the end) is also OK, Sep 28, 2016 at 9:05
3

If you want to list all matching lines (as in my other answer), and then jump to one particular match, my FindOccurrence plugin provides a [/ mapping for that (and [n for the last search pattern, instead of querying for one). [/pattern lists like :g/pattern, but then asks for the number of the match to jump to.

1

Another way is to use :h :ilist, i use it to get an overview of man page. it's result looks like this:

~/find.~
  1:    3 NAME
  2:    6 SYNOPSIS
  3:    9 DESCRIPTION
  4:   18 OPTIONS
  5:   93 EXPRESSION
  6:  779 EXAMPLES
  7:  877 HISTORY
  8:  931 BUGS

Here is a small function that let you choose to go to the result line by index:

function! s:select_ilist(ilist_result)
  if empty(a:ilist_result) || a:ilist_result =~# '^\_s*Error'
    return
  endif

  let select = input(a:ilist_result . "\ngoto : ")
  if empty(select) | return | endif

  " ilist result starts with '\nfilename\n', filename can be empty
  let lines = split(a:ilist_result[stridx(a:ilist_result, "\n", 1) : ], "\n")
  if select <= 0 || select > len(lines) | return | endif

  exec matchstr(lines[select-1], '^\v\s*\d+\:\s+\zs\d+')
endfunction

It can be used like this:

command! -buffer Section call s:select_ilist(execute('silent! ilist /\v\C^[A-Z][^a-z]+$/'))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.