Vim: tip, of the iceberg, of the day
Imagine you have a big file, you want to keep only few lines of it and delete everything else quickly, all that in Vim.
The user-level goal is:
- Select some lines
- Delete everything except the selected lines
OK, it is dead easy to create a new file, copy the interesting lines to it and delete the old file, but let's try to do this in-place, as an exercise, just to learn something more about Vim.
It is not generally possible to have an “inverse selection” concept in text editors because the selection is usually assumed to be Connected, and I am pretty sure this holds for Vim as well; so if we can't have holes in selections, like in graphic editors, we have to work around this.
By expanding the user view of the problem we can discover (or invent? This is meat for another post...) a possible very simple algorithm which solves the problem:
- Select some text
- Store it somewhere
- Delete the whole file content
- Restore the previously stored selection
Easy, Easn't it? Ehm, isn't it? :)
Let's translate each step in Vim talk:
- Enter visual mode with either v, V or CTRL-v and select some text
- Save the selection in register x: "xy
Delete the whole file: gg dG that is:
- Go to the beginning of the file: gg
- Delete up to the end of the file: dG
- Enter linewise-visual mode and paste register x before current line: V"xP
- Optionally we could restore the selection as it was before: gv
Now, summing up all the steps, our
unselected) command in visual mode is defined with:
:vmap du "xyggdGV"xPgv
Entering linewise-visual mode before pasting is a trick to avoid pasting before or after a line, we can call that a paste here command.
We can also do things in a slightly different way, using the default register to store the selection, completely discarding the deleted content:
- Save the selection: y
- Delete the whole file, sending the deleted stuff to the
black hole register
"_: gg "_dG
- Paste in visual mode: VP
- Optionally we could restore the selection: gv
So the new, more compact, command is defined by: :vmap du ygg"_dGVPgv
As a bonus feature the two commands above work also with blockwise selections.
If you really don't want to use registers (because of infantile traumas or the like) there's at least another way to achieve our goal using more exotic cursor-motions, but this solution doesn't work with blockwise selections, I am putting it here just as a reference on motions:
- Select some text
- Exit visual mode (the selection boundaries will stay memorized somewhere, tho): vv
- Go to the beginning of the file and delete up to the beginning of the selection: gg d`<
- Go after the end of the selection and delete up to the end of the file: `>+ dG
- Optionally, select all: ggVG
We have: :vmap du vvggd`<`>+dGggVG very understandable, ain't it? :q