It turns out that this works:
:g/
/,+1s//
The :global
will match every line in the buffer (or in the range, if you pass it a range.)
The /
/
is being used as a regex that will match every line, in this case, on the line break itself. We could have used something like /^/
(or perhaps /./
or /S/
to match non-empty or non-blank lines), here we're using /
/
since we want to use that pattern in the following :s
, so we can omit it there to use the same pattern.
Then, for each line processed by :g
, we use a range of that line up to line +1
. That means two lines, in this case, current line and next one. Since we want to join three lines, we want to replace the line break on two lines, so from current line up to line +1
. (You could generalize that to using +
the number of lines in the blocks you want to join, minus two.)
Finally, we perform the substitution s//
, which is equivalent to s/
//
(using an empty pattern will match the previously used on, in this case the one passed to :g
.) This :substitute
will replace the matched line breaks with a tab character, effectively joining lines where it matches. Since we're using ranges of two lines, it will only do so two lines at a time, effectively replacing two line breaks, which will join three lines.
This works because the way :global
works when there are edits on the affected lines. It first "marks" the lines that should be acted on, but then if the line is no longer there, it will skip it. So while it will first mark every line, when the :s
joins every second and third line to the first in a block, the marks on them will no longer be there, so the end result is that :g
will not try to process this line again and will move on to the next "marked" line, which will then become the start of the next block.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…