Reputation: 1492
Is it possible to have a vim binding that turns multi-line if-statements into single-line if-statements and vice-versa?
turn this
if () {
statement_1;
statement_2;
} else if () {
statement_3; statement_4;
} else if () {
statement_5;
} else {
}
into this
if () { statement_1; statement_2 }
else if () { statement_3; statement_4; }
else if () { statement_5; }
else { }
or anything close to the above behavior? I was thinking of having the command execute upon visually selecting the block to convert and then use searches for else if
and entering new lines, etc. But my problem was determining how many else if
were in the code
Upvotes: 1
Views: 1425
Reputation: 27822
Join all the lines to a single line by selecting them in visual mode V
and pressing J
; then add a newline before every else
with :s/else/\relse/
. You'll end up with:
if () { statement_1; statement_2; }
else if () { statement_3; statement_4; }
else if () { statement_5; }
else { }
The \r
in the replacement pattern is a newline (you need to use \n
and search and \r
in replace; don't ask me why).
Next step is to put all the start braces in the same column. I'd use the tabular plugin for this, which makes that very easy:
:%Tabularize /{/
With %
we operate on the entire buffer, in a "real" file you'll probably want to use a more restrictive range or visual mode. There are some other plugins which do something similar as well.
You should now have the output you want.
If you don't want to use a plugin, you can use the column
command:
:%!column -ts{ -o{
If you want a "Vim-only" solution, then it's a bit more complex:
:let b:column = 10
:%s/^\(.\{-}\) {/\=submatch(1) . repeat(' ', b:column - len(submatch(1))) . ' {'/
Breaking that down:
I used the b:column
variable to specify the column to align to. You don't need this but it make it a bit easier to edit this number later on.
^\(.\{-}\) {
puts everything before {
in a subgroup.
\=
). See :help sub-replace-\=
.if ...
back with submatch(1)
repeat(' ', b:column - len(submatch(1)))
{
back.I told you it was a bit more complex ;-) If you don't want tabular. Personally, I'd just start insert mode to insert spaces, which will be a lot faster than writing & debugging this (relevant xkcd).
Note that I didn't make some "magic" command which re-arranges all the text with just a stroke of a key. I don't think such a command would be a good idea. In practice there will be a lot of edge cases that such a command won't handle. Fully "parsing" a programming language with ad-hoc editing commands and/or regexps doesn't really work all that great.
Where Vim really shines is giving the user powerful text editing commands, which can be applied and combined with minimal effort, which is exactly what I did above. There are several other ways one can use to get the same effect.
But if you really want to, you can of course combine all of the above in a command:
fun! s:reformat(line1, line2)
" Remember number of lines for later
let l:before = line('$')
" Join the lines
execute 'normal! ' . (a:line2 - a:line1 + 1) . 'J'
" Put newline before else
:s/else/\relse/
" Run tabular; since the number of lines change we need to calculate the range.
" You could also use one of the other methods here, if you want.
let l:line2 = a:line2 - (l:before - line('$'))
execute a:line1 . ',' . l:line2 . 'Tabularize /{/'
endfun
command! -range Reformat :call s:reformat(<line1>, <line2>)
Upvotes: 3