How to invert the selection in vim?

12

3

After selecting a range of lines with the V command, I would like to delete every line of the file that is NOT selected, so is a way to invert the selection -- select every line that is not selected?

Like how

:g!/FOO/d

deletes every line which does NOT contain FOO.

If I had a range in mind and wanted to use its inverse:

'a,'b

I would need to use the two ranges:

1,'a-1

and

'b+1,$

I suspect that this cannot be done in one step -- but it would be nice!

Kevin Panko

Posted 2009-11-19T15:44:53.817

Reputation: 6 339

so you want a "crop"-style operation? – quack quixote – 2009-11-19T16:10:35.590

Answers

7

First create the following mapping (for example bound to the <F4> key)

map <F4> :<C-U>1,'<-1:delete<CR>:'>+1,$:delete<CR>

then, after selecting a range in visual mode, just press <F4> to trigger the associated command. The command can be easily explained in parts:

  • ":" Enter command line mode.
  • "<C-U>" Remove all characters between the cursor position and the beginning of the line.
  • "1,'<-1" Specifiy the range from the first line of the file to the line before the start of current selection.
  • ":delete<CR>" Delete (the previously specified range of lines).
  • ":'>+1,$:delete<CR>" Delete the lines in the range "'>+1,$", i.e. from the line after the end of the selection to the end of the file.

mrucci

Posted 2009-11-19T15:44:53.817

Reputation: 8 398

2just to explain it: 1,'< - 1 is the range from line 1 upto the start of the selection. '> + 1,$ is the range from 1 line after the selection upto the end... – akira – 2009-11-19T17:13:01.843

Is there some way to do that with only one "delete" command? – Kevin Panko – 2009-11-19T18:34:59.837

1

@Kevin Panko: you'd need to combine the ranges into a single expression. i've looked at the docs and i don't think the range syntax supports such a thing. http://vimdoc.sourceforge.net/htmldoc/cmdline.html#cmdline-ranges ,,, http://vim.wikia.com/wiki/Ranges

– quack quixote – 2009-11-19T22:05:33.250

15

  1. select your text
  2. "*yggdG"*p which means ...

    "*y    " yank it to the selection register
    ggdG   " delete everything
    "*p    " and paste the selection again 
    

akira

Posted 2009-11-19T15:44:53.817

Reputation: 52 754

I would like just refer to akira and Kevin Panko answers (I cannot add comments). " [o]pposite [d]elete in (v)isual mode vmap od ygg"_dGP – Marcin Rogacki – 2015-01-16T13:29:15.857

Plugins like https://github.com/maxbrunsfeld/vim-yankstack make this approach easier. You don't have to worry as much about your yank register getting clobbered by the delete.

– Jack O'Connor – 2015-10-20T15:10:26.863

how can this be added as keyboard mapping in .vimrc ? I've tried a few attempts but haven't gotten it yet. My attempts were map <F4> n"*yggdG"*p and nmap <F4> "*yggdG"*p – Brad Parks – 2018-08-01T13:56:04.493

ahh.. found it ! This worked for me to map it to F4. Just add this to your .vimrc, map <F4> "*yggdG"*p – Brad Parks – 2018-08-01T14:02:58.937

9ygg"_dGP is the same but shorter. – Kevin Panko – 2009-11-19T17:56:26.483

1in the end you get the same text, true :) – akira – 2009-11-19T18:20:42.517

7

Just for posterity:

:v/\%V/d

That does an inverse global on lines that are not part of the selection. Note that :v is a line-based construct, so any line that contains any of the selection, be it line, stream, or block selection will be spared deletion.

Gary Fixler

Posted 2009-11-19T15:44:53.817

Reputation: 171

1

since 'inverting' means basically to create 'multiselections' (the area before and after the original selection) i searched the vimscripts again http://www.vim.org/scripts/script.php?script_id=953. try this.

 There are a number of operations to very
 easily manipulate selections such as modifying 
 the regions (add/delete/inverte/clear), hiding, 
 refreshing, saving and restoring etc."

akira

Posted 2009-11-19T15:44:53.817

Reputation: 52 754