3

While doing some updates to my .vimrc file today, I stumbled across this for condensing blank lines (really empty lines) into a single empty line.

:map ;b   GoZ<Esc>:g/^$/.,/./-j<CR>Gdd

That actually comes directly from the vim help files for the collapse help. I also know that the :g has this pattern :g/pat/{cmd}. So, the .,/./-j is the {cmd}. After some digging, I know that it's just joining, -j, sequences of empty lines. What I don't fully understand is, what does the .,/./ do?

I've read up on the . and , commands. The . is well known to me: repeat last change. The , was new: repeat last f, F, t or T command, but none of these are being used. So, kindly, what exactly do the .,/. mean in this context?

1 Answer 1

4

The . and , here are not Normal-mode commands for repeating last change and repeating last line motion...

Instead, the command executed by a :g is actually an Ex command, same as those you type in the command line after a :.

In this case, the :.,/./- part is called a range and it determines upon which lines the next command (j for :join) will act. (Note that the - is actually part of the range and not part of the :join command.)

A range is typically formed by two line addresses separated by a comma. In that context, . specifies the current line (which will happen in the context of :g, so this will match the current line for each line that matches the :g pattern.)

Then /./ will match the first non-empty line following the current line (. in a regex matches any character, so effectively this is matching a line with any character in it), and then a - (which is a shorthand for -1) will select the line that just precedes it, in other words, the last blank line in this block.

You can run this same command outside of the :g, which might help you see how it works. Just move the cursor to the first blank line in a block, and use the following command:

: . , /./-1 join

It will condense that specific block. You can also type the range only, which will result in Vim moving to the last line in the range (last blank line in the block):

: . , /./-1

See :help :range for more details.

3
  • 1
    I had no idea that :g could take a range as well as the initial matching pattern! This is so useful! +1
    – mattb
    Dec 30, 2021 at 11:51
  • 1
    Thank you much! This is very helpful. I wasn't looking at them as ranges, but this makes sense. I often use .,'a or similar. I didn't see that. Thank you for the concise explanation. To bad I can up-vote only once. Dec 30, 2021 at 15:39
  • 1
    Actually, I learned in this that there is a :// command. I've used vi/vim now for 25+ years and have never made use of // or ?? as ex commands: only the normal mode commands. Thanks for that bit of education too. Dec 30, 2021 at 15:59

Your Answer

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

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