Vim多线If-Statements为单行If语句

时间:2017-05-06 05:51:08

标签: vim reformatting

是否可以使用vim绑定将多行if语句转换为单行if语句,反之亦然?

转过来

if () {
    statement_1;
    statement_2;
} else if () {
    statement_3; statement_4;
} else if () {
    statement_5;
} else {

}

进入这个

if ()      { statement_1; statement_2 }
else if () { statement_3; statement_4; }
else if () { statement_5; }
else       { }

或接近上述行为的任何事情?我正在考虑让命令执行时直观地选择要转换的块,然后使用else if搜索并输入新行等。但我的问题是确定代码中有多少else if

1 个答案:

答案 0 :(得分:2)

通过在视觉模式V中选择并按J,将所有行连接到一行;然后在else :s/else/\relse/之前添加换行符。你最终会得到:

if () { statement_1; statement_2; } 
else if () { statement_3; statement_4; }
else if () { statement_5; } 
else { }

替换模式中的\r是换行符(您需要使用\n并搜索并替换\r;不要问我原因。)

下一步是将所有开始大括号放在同一列中。我为此使用了tabular plugin,这非常简单:

:%Tabularize /{/

使用%我们对整个缓冲区进行操作,在" real"文件你可能想要使用更严格的范围或视觉模式。还有其他一些插件可以做类似的事情。

您现在应该拥有所需的输出。

如果您不想使用插件,可以使用column命令:

:%!column -ts{ -o{

如果你想要一个"仅限Vim"解决方案,然后它有点复杂:

:let b:column = 10
:%s/^\(.\{-}\) {/\=submatch(1) . repeat(' ', b:column - len(submatch(1))) . ' {'/

打破这一点:

  • 我使用b:column变量指定要对齐的列。您不需要这一点,但以后可以更轻松地编辑此号码。

  • ^\(.\{-}\) {{之前的所有内容放入子组中。

  • 在替换中,我们使用了一个表达式(如\=所示)。见:help sub-replace-\=
  • 首先我们将if ...放回submatch(1)
  • 然后我们使用repeat(' ', b:column - len(submatch(1)))
  • 插入所需数量的空格
  • 最后我们将文字{插回。

我告诉过你这有点复杂;-)如果你不想要表格。就个人而言,我只是开始插入模式来插入空格,这比编写和写入更快。调试这个(relevant xkcd)。

请注意,我没有制作一些魔法"只用一个键的笔划重新排列所有文本的命令。我不认为这样的命令是个好主意。在实践中,会有很多边缘情况,这样的命令不会处理。完全"解析"一种带有特殊编辑命令和/或正则表达式的编程语言并不能真正发挥作用。

Vim真正发光的地方在于为用户提供强大的文本编辑命令,可以轻松应用和组合,这正是我上面所做的。可以使用其他几种方法来获得相同的效果。

但如果你真的想,你当然可以在命令中结合以上所有内容:

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>)