PPrint: A tricky case to process nest with ending parentheses

I would like to print a list of fun’s like the following, if space permits:

(fun1(); fun2(); fun3())

We may notice that:

  • there is not SPACE between the first ( with fun1
  • there is not SPACE between the last ) with fun3()

When space is not enough, we should see:

(
  fun1();
  fun2();
  fun3()
)

We may notice that both the first ( and last ) are the only element in their line.

Here’s my demo:

open PPrint

let document =
  hardline
  ^^ group
       (string "("
       ^^ nest 2
            (break 1
            ^^ group (string "fun1();" ^/^ string "fun2();" ^/^ string "fun3()")
            )
       ^/^ string ")")
  ^^ hardline

let document2 =
  hardline
  ^^ group
       (string "("
       ^^ nest 2
            (break 0
            ^^ group (string "fun1();" ^/^ string "fun2();" ^/^ string "fun3()")
            )
       ^^ string ")")
  ^^ hardline

  let document3 =
    hardline
    ^^ group
         (string "("
         ^^ nest 2
              (break 0
              ^^ group (string "fun1();" ^/^ string "fun2();" ^/^ string "fun3()")
              )
         ^/^ string ")")
    ^^ hardline  

let () =
  ToChannel.pretty 0.5 20 stdout document;
  flush stdout;
  ToChannel.pretty 0.5 60 stdout document;
  flush stdout;
  ToChannel.pretty 0.5 20 stdout document2;
  flush stdout;
  ToChannel.pretty 0.5 60 stdout document2;
  flush stdout;
  ToChannel.pretty 0.5 20 stdout document3;
  flush stdout;
  ToChannel.pretty 0.5 60 stdout document3;
  flush stdout  

It outputs as follows:

# document
(
  fun1();
  fun2();
  fun3()
)

( fun1(); fun2(); fun3() )

# document2
(
  fun1();
  fun2();
  fun3())

(fun1(); fun2(); fun3())

# document3
(
  fun1();
  fun2();
  fun3()
)

(fun1(); fun2(); fun3() )

The results:

  • document: There’re additional space between ( and fun1().
  • document2: fun3()), the last ) should in next line.
  • document3: There’s additional space between fun3() and the last )
1 Like

I haven’t used PPrint before, so this was an occasion to read the doc and try some things out.
Here’s what I understand:

  • In document, you’re using break 1, which gives you a space in flat mode.
  • In document2 you’re using ^^ before the last ')' which cannot break.
  • In document3, you’re using (^/^) before the last ')', which is fun x y -> x ^^ break 1 ^ y.

In fact, I think you just want a break 0, so something like this:

let document3 =
    hardline
    ^^ group
         (string "("
         ^^ nest 2
              (break 0
              ^^ (string "fun1();" ^/^ string "fun2();" ^/^ string "fun3()")
              )
         ^^ (break 0 ^^ string ")"))
    ^^ hardline;;
1 Like