Vim connect lines to match brackets

I have a tool that produces output as follows:

(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 the result to be 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 generate the required output, depending on how many lines I want to join -

 :.,+3join 

I am wondering if I can do this automatically and not do it manually. The key point here is that on each line the number of open brackets will be equal to the number of brackets closed.

+4
source share
4 answers

My welcome:

  qqqqqv%:join j@qq @q 

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

Step by step:

  • qqq to clear the q macro (to avoid confusion with previous macro definitions)
  • q to start recording
  • q to indicate that this is the macro 'q' that we write
  • v for visual marking
  • % to go to the corresponding bracket
  • : for command mode operating on the currently marked area
  • join (plus ENTER) to join strings
  • J to go one line
  • @q to invoke the macro 'q' (recursion) (if we did not clear it first, we would name the old definition here, which we don’t want)
  • q to complete recording
  • @q execute a macro that will stop at the end of the file (when move J errors)

Sorry abundance q . I assume that including this parameter in J would be more intuitive, but I always use q for fire-and-forget macros like this, because it makes the initial clear record ( qqqqq ) easy to remember (and therefore that most other keys already have macros). :-)

Edit: Scratch the last paragraph. I just wanted him to repeat the same key like a madman .; -)

+7
source

I think this line :s will work for you:

 :%s/\v\n\s+(\()/\1/ 

also for example in your question, this also works .. (but leave the 1st line blank)

 :%j|s/(check/\r&/g 

EDIT

just now i have not put 1d there. now he comes:

if you want to delete the 1st empty line, try the following:

 :%j|s/(check/\r&/g|1d 

EDIT2

Thanks to Nikita Kouveda for pointing out the problem with spaces. also a fix (see comments below) I just neglected the space created by: join.

I would add another short line that also works without worrying about spaces:

 :g/^(/.,/\n\ze(\|\%$/j 
+3
source

This will be one way to do this with a macro:

 qjo<ESC>k0v% Jjq100@j 

The main idea here is that you can use v%J to select and combine all the rows in the scope (...) . The only caveat is that it will not work for single-line statements, so we will always add an extra line ( o<ESC> ). Finally, we wrap it all up in a macro and it works!

+2
source

If the last line of your file was empty, you can use:

 :g/^(/,/^(\|^$/-1j 

which consists of:

find the line starting with the bracket:

 g/^(/ 

from there to the next line starting with a bracket or an empty line

 ,/^(\|^$/ 

go back to the line before

 -1 

append these lines:

 j 

If you want to do this at a time, go to the first open bracket and v% j (enter visual, select the appropriate bracket, attach the selected block)

+1
source

All Articles