(experimental) two_columns ds
is a document that lays out the documents in ds
in two columns by inserting spaces between the two columns in each row.
Note that this is not quite a table layout, because:
- In each row, the right column will start at the same line as the last line of the left column. The
print_doc_let_nl 33
example below demonstrates this. - The restriction to not exceed the column separator only applies to the last line of the left column. The prior lines can freely exceed the column separator. The
print_doc_let_nl 33
example below demonstrates this. - The right column's non-first lines can flow back to the beginning of the left column (use
align
to restrict the right column content from flowing back). The print_doc_match 54
example below demonstrates this.
Also note that some rows may overflow the column separator anyway (e.g. in order to avoid the global overflow over the page width limit).
The cost of the overflow over the column separator can be adjusted via CostFactory.two_columns_overflow
(this particularly can be used to strongly discourage overflow over the column separator). The cost to prefer the leftmost column separator can be adjusted via CostFactory.two_columns_bias
. Meanwhile, the cost for the inserted spaces between the two columns is always fixed to CostFactory.text 0 0
.
The indentation level is set to the initial current column position (in the same manner as align
) so that on entering a new line, the left column of the next row starts at the right position.
Unlike fill
or fillBreak
from Wadler/Leijen's pretty printer, which requires users to specify a fixed position of the column separator, two_columns
will find the position automatically, and will find a "fitting" one.
This document is expensive. Internally, it expands to a very large document. Don't use it if the input list is long!
Examples:
The types
example is taken from https://hackage.haskell.org/package/wl-pprint-1.2.1/docs/Text-PrettyPrint-Leijen.html#v:fill
# let types = [ "empty", "Doc";
"nest", "Int -> Doc -> Doc";
"linebreak", "Doc" ];;
val types : (string * string) list =
[("empty", "Doc"); ("nest", "Int -> Doc -> Doc"); ("linebreak", "Doc")]
# let print_doc_let w =
let cf = Printer.default_cost_factory ~page_width:w () in
let module P = Printer.Make (val cf) in
let open P in
let d = text "let " ^^
two_columns (List.map
(fun (n, t) -> text n, text " :: " ^^ text t)
types) in
pretty_format_debug d |> print_endline;;
val print_doc_let : int -> unit = <fun>
# print_doc_let 34;;
1234567890123456789012345678901234
let empty :: Doc │
nest :: Int -> Doc -> Doc│
linebreak :: Doc │
is_tainted: false
cost: (0 0 2)
- : unit = ()
# print_doc_let 33;;
123456789012345678901234567890123
let empty :: Doc │
nest :: Int -> Doc -> Doc │
linebreak :: Doc │
is_tainted: false
cost: (0 4 2)
- : unit = ()
# print_doc_let 28;;
1234567890123456789012345678
let empty :: Doc │
nest :: Int -> Doc -> Do│c
linebreak :: Doc │
is_tainted: false
cost: (1 6 2)
- : unit = ()
# let print_doc_let_nl w =
let cf = Printer.default_cost_factory ~page_width:w () in
let module P = Printer.Make (val cf) in
let open P in
let d = text "let " ^^
two_columns (List.map
(fun (n, t) ->
text n ^^ group break,
text " :: " ^^ text t)
types) in
pretty_format_debug d |> print_endline;;
val print_doc_let_nl : int -> unit = <fun>
# print_doc_let_nl 34;;
1234567890123456789012345678901234
let empty :: Doc │
nest :: Int -> Doc -> Doc│
linebreak :: Doc │
is_tainted: false
cost: (0 0 2)
- : unit = ()
# print_doc_let_nl 33;;
123456789012345678901234567890123
let empty :: Doc │
nest :: Int -> Doc -> Doc │
linebreak │
:: Doc │
is_tainted: false
cost: (0 0 3)
- : unit = ()
# print_doc_let_nl 28;;
1234567890123456789012345678
let empty │
:: Doc │
nest │
:: Int -> Doc -> Doc │
linebreak │
:: Doc │
is_tainted: false
cost: (0 0 5)
- : unit = ()
# let table = [ "[]", "false";
"hd :: _ when hd = to_find", "true";
"_ :: tl", "find_member to_find tl" ];;
val table : (string * string) list =
[("[]", "false"); ("hd :: _ when hd = to_find", "true");
("_ :: tl", "find_member to_find tl")]
# let print_doc_match w =
let cf = Printer.default_cost_factory ~page_width:w () in
let module P = Printer.Make (val cf) in
let open P in
let d = text "let rec find_member to_find xs =" ^^
nest 2 (
nl ^^ text "match xs with" ^^ nl ^^
two_columns
(List.map
(fun (n, t) ->
(text "| " ^^ text n,
text " ->" ^^ group (nest 2 nl) ^^
text t))
table)) in
pretty_format_debug d |> print_endline;;
val print_doc_match : int -> unit = <fun>
# print_doc_match 55;;
1234567890123456789012345678901234567890123456789012345
let rec find_member to_find xs = │
match xs with │
| [] -> false │
| hd :: _ when hd = to_find -> true │
| _ :: tl -> find_member to_find tl│
is_tainted: false
cost: (0 0 4)
- : unit = ()
# print_doc_match 54;;
123456789012345678901234567890123456789012345678901234
let rec find_member to_find xs = │
match xs with │
| [] -> false │
| hd :: _ when hd = to_find -> true │
| _ :: tl -> │
find_member to_find tl │
is_tainted: false
cost: (0 0 5)
- : unit = ()