Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vim join lines for matching brackets

Tags:

vim

I have a tool which produces output like this -

(check (= Start
   (+ (if (<= takeA giveA) 0 1)
      (if (<= takeB giveB) 0 1)
      (if (<= takeC giveC) 0 1)
      (if (<= takeD giveD) 0 1))))
(check (and (>= takenBefore_A 0) (<= takenBefore_A 4)))
(check (and (>= givenBefore_A 0) (<= givenBefore_A 4)))
(check (= risk_A
   (+ Start 1 (- takenBefore_A givenBefore_A))))
(check (= takenBefore_A
   (+ (if (<= takeB takeA) 1 0)
      (if (<= takeC takeA) 1 0)
      (if (<= takeD takeA) 1 0))))
(check (= givenBefore_A
   (+ (if (<= giveA takeA) 1 0)
      (if (<= giveB takeA) 1 0)
      (if (<= giveC takeA) 1 0)
      (if (<= giveD takeA) 1 0))))
(check (and (>= takenBefore_B 0) (<= takenBefore_B 4)))
(check (and (>= givenBefore_B 0) (<= givenBefore_B 4)))
(check (= risk_B
   (+ Start 1 (- takenBefore_B givenBefore_B))))
(check (= takenBefore_B
   (+ (if (<= takeA takeB) 1 0)
      (if (<= takeC takeB) 1 0)
      (if (<= takeD takeB) 1 0))))
(check (= givenBefore_B
   (+ (if (<= giveA takeB) 1 0)
      (if (<= giveB takeB) 1 0)
      (if (<= giveC takeB) 1 0)
      (if (<= giveD takeB) 1 0))))
(check (and (>= takenBefore_C 0) (<= takenBefore_C 4)))
(check (and (>= givenBefore_C 0) (<= givenBefore_C 4)))
(check (= risk_C
   (+ Start 1 (- takenBefore_C givenBefore_C))))

And I would like to have the output like this -

(check (= Start (+ (if (<= takeA giveA) 0 1) (if (<= takeB giveB) 0 1) (if (<= takeC giveC) 0 1) (if (<= takeD giveD) 0 1))))
(check (and (>= takenBefore_A 0) (<= takenBefore_A 4)))
(check (and (>= givenBefore_A 0) (<= givenBefore_A 4)))
(check (= risk_A (+ Start 1 (- takenBefore_A givenBefore_A))))
(check (= takenBefore_A (+ (if (<= takeB takeA) 1 0) (if (<= takeC takeA) 1 0) (if (<= takeD takeA) 1 0))))
(check (= givenBefore_A (+ (if (<= giveA takeA) 1 0) (if (<= giveB takeA) 1 0) (if (<= giveC takeA) 1 0) (if (<= giveD takeA) 1 0))))
(check (and (>= takenBefore_B 0) (<= takenBefore_B 4)))
(check (and (>= givenBefore_B 0) (<= givenBefore_B 4)))
(check (= risk_B (+ Start 1 (- takenBefore_B givenBefore_B))))
(check (= takenBefore_B (+ (if (<= takeA takeB) 1 0) (if (<= takeC takeB) 1 0) (if (<= takeD takeB) 1 0))))
(check (= givenBefore_B (+ (if (<= giveA takeB) 1 0) (if (<= giveB takeB) 1 0) (if (<= giveC takeB) 1 0) (if (<= giveD takeB) 1 0))))
(check (and (>= takenBefore_C 0) (<= takenBefore_C 4)))
(check (and (>= givenBefore_C 0) (<= givenBefore_C 4)))
(check (= risk_C (+ Start 1 (- takenBefore_C givenBefore_C))))

I used the following command in VIM to produce the necessary output, depending on how many lines I want to join -

:.,+3join

I am wondering, if I can automatically do this rather than doing it manually. The keypoint here is that, on each line the number of brackets opened will be equal to number of brackets closed.

like image 524
Raj Avatar asked Apr 17 '13 13:04

Raj


People also ask

How do I match parentheses in Vim?

You can easily use the % key to jump to a matching opening or closing parenthesis, bracket or curly brace. You can also set the option showmatch . The cursor will briefly jump to the matching bracket, wen you insert one.

How do I join lines in Vim?

When you want to merge two lines into one, position the cursor anywhere on the first line, and press J to join the two lines. J joins the line the cursor is on with the line below. Repeat the last command ( J ) with the . to join the next line with the current line.

How do I convert multiple lines to one line in Vim?

The easiest way I've found to split lines in Vim is the normal mode command gq (type both letters in quick succession in normal or visual mode). In visual mode, it will split whatever is selected, in normal mode, you follow gq with a motion. For example, gql will split one line to the currently set width.


2 Answers

My take:

 qqqqqv%:join
 j@qq@q

Using join instead of J solves the problem of single lines in Daan's answer.

Step by step:

  • qqq to clear the 'q' macro (to avoid getting tangled with previous macro definitions)
  • q to start recording
  • q to state that it's the 'q' macro we're recording
  • v for visual marking
  • % to jump to matching brace
  • : for command mode, acting on currently marked area
  • join (plus ENTER) for joining the lines
  • j to go down one line
  • @q to call 'q' macro (recursion) (if we hadn't cleared it first, we'd be calling the old definition here, which is not what we want)
  • q to end recording
  • @q to execute the macro, which will stop at end-of-file (when the j move errors)

Excuse the abundance of q's. I admit putting this on j would be more intuitive, but I always use q for fire-and-forget macros like this, because it makes the initial clear-and-record (qqqqq) so easy to remember (and because most other keys already have macros on them). :-)

Edit: Scratch that last paragraph. I just like hammering at the same key repeatedly like a madman. ;-)

like image 169
DevSolar Avatar answered Oct 03 '22 03:10

DevSolar


This would be one way to do it using a macro:

qjo<ESC>k0v%Jjq100@j

The basic idea here is that you can use v%J to select and join all lines in the (...) area. The only caveat is that it won't work for single line statements, thus we make sure to always add an extra line (o<ESC>). Finally we wrap it all up in a macro and it works!

like image 30
Daan Bakker Avatar answered Oct 03 '22 04:10

Daan Bakker