Dane O'Connor
Dane O'Connor

Reputation: 77278

Vim: delete empty lines around cursor

Suppose I'm editing the following document (* = cursor):

Lions
Tigers


Kittens
Puppies


*


  Humans

What sequence can I use to delete the surrounding white space so that I'm left with:

Lions
Tigers


Kittens
Puppies
*
  Humans

Note: I'm looking for an answer that handles any number of empty lines, not just this exact case.

EDIT 1: Line numbers are unknown and I only want to effect the span my cursor is in.

EDIT 2: Edited example to show I need to preserve leading whitespace on edges

Thanks

Upvotes: 12

Views: 1810

Answers (6)

Lorkenpeist
Lorkenpeist

Reputation: 1495

I know this question has already been resolved, but I just found a great solution in "sed & awk, 2nd Ed." (O'Reilly) that I thought was worth sharing. It does not use vim at all, but instead uses sed. This script will replace all instances of one or more blank lines (assuming there is no whitespace in those lines) with a single blank line. On the command line:

sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile

Keep in mind that sed does not actually edit the file, but instead prints the edited lines to standard output. You can redirect this input to a file:

sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile > tempfile

Be careful though, if you try to write it directly to myfile, it will just delete the entire contents of the file, which is clearly not what you want! After you write the output to tempfile, you can just mv tempfile myfile and tada! All instances of multiple blank lines are replaced by a single blank line.

Even better:

cat -s myfile > temp
mv temp myfile

cat is awesome, yes?

Bestest:

If you want to do it inside vim, you can replace all instances of multiple blank lines with a single blank line by using vim's handy feature of executing shell commands on a range of lines within vim.

:%!cat -s

That's all it takes, and your entire file is reformatted all nice!

Upvotes: 0

glts
glts

Reputation: 22684

Easy. In normal mode, dipO<Esc> should do it.

Explanation:

  • dip on a blank line deletes it and all adjacent blank lines.
  • O<Esc> opens a new empty line, then goes back to normal mode.

Even more concise, cip<Esc> would roll these two steps into one, as suggested by @Lorkenpeist.

Upvotes: 14

Peter Rincker
Peter Rincker

Reputation: 45087

A possible solution is to use the :join command with a range:

:?.?+1,/./-1join!

Explanation:

  • [range]join! will join together a [range] of lines. The ! means with out inserting any extra space.
  • The starting point is to search backwards to the first character then down 1 line, ?.?+1
  • As the 1 in +1 can be assumed this can be abbreviated ?.?+
  • The ending point is to search forwards to the next character then up 1 line, /./-1
  • Same as before the 1 can be assumed so, /./-
  • As we are using the same pattern only searching forward the pattern can be omitted. //-
  • The command :join can be shorted to just :j

Final shortened command:

:?.?+,//-j!

Here are some related commands that might be handy:

1) to delete all empty lines:

  • :g/^$/d
  • :v/./d

2) Squeeze all empty lines into just 1 empty line:

  • :v/./,//-j

For more help see:

:h :j
:h [range]
:h :g
:h :v

Upvotes: 7

Lorkenpeist
Lorkenpeist

Reputation: 1495

Short Answer: ()V)kc<esc>

In normal mode, if you type () your cursor will move to the first blank line. ( moves the cursor to the beginning of the previous block of non-blank lines, and ) moves the cursor to the end (specifically, to the first blank line after said block). Then a simple d) will delete all text until the beginning of the next non-blank line. So the complete sequence is ()d).

EDIT: You're right, that deletes the whitespace at the beginning of the next non-blank line. Instead of d) try V)kd. V puts you in visual line mode, ) jumps to the first non-blank line (skipping the whitespace at the beginning of the line), k moves the cursor up one line. At this point you've selected all the blank lines, so d deletes the selection.

Finally, type O (capital O) followed by escape to crate a new blank line to replace the ones you deleted. Alternatively, replacing dO<Escape> with c<Escape> does the same thing with one less keystroke, so the entire sequence would be ()V)kc<Esc>.

Upvotes: 3

Kent
Kent

Reputation: 195029

I didn't test so much, but it should work for your examples. There maybe more elegant solutions.

function! DelWrapLines()
    while match(getline('.'),'^\s*$')>=0
        exe 'normal kJ'
    endwhile
    exe 'silent +|+,/./-1d|noh'
    exe 'normal k'
endfunction

source it and try :call DelWrapLines()

Upvotes: 1

Conner
Conner

Reputation: 31040

These answers are irrelevant after the updated question:

This may not be the answer you want to hear, but I would make use of ranges. Take a look at the line number for the first empty line (let's say 55 for example) and the second to last empty line (perhaps 67). Then just do :55,67d.

Or, perhaps you only want there to ever be one empty line in your whole file. In that case you can match any occurrence of one or more empty lines and replace them with one empty line.

:%s/\(^$\n\)\+/\r/

This answer works:

If you just want to use normal mode you could search for the last line with something on it. For instance,

/.<Enter>kkVNjd

Upvotes: 1

Related Questions