lib/display.ml -rw-r--r-- 3 KiB
1open Core
2
3type cell = string * (string -> string)
4
5and row = cell list
6
7module Tabular = struct
8 let maximum_lengths rows =
9 rows
10 |> List.foldi ~init:[] ~f:(fun index accm row ->
11 let row_maximums =
12 row |> List.map ~f:(fun cell -> fst cell |> String.length)
13 in
14 if Int.equal index 0 then row_maximums
15 else List.map2_exn accm row_maximums ~f:Int.max)
16
17 let fixed rows =
18 let dimensions = rows |> maximum_lengths in
19 let lines =
20 rows
21 |> List.fold ~init:[] ~f:(fun accm row ->
22 let line =
23 row
24 |> List.foldi ~init:"" ~f:(fun index line cell ->
25 let content, paint_fn = cell in
26 let padding =
27 List.nth_exn dimensions index
28 - String.length content + 1
29 in
30 let padding = String.make padding ' ' in
31 let line = line ^ (content |> paint_fn) ^ padding in
32 line)
33 in
34
35 line :: accm)
36 in
37 lines |> List.rev
38
39 let wide ?(pivot = 1) ~width rows =
40 let dimensions = rows |> maximum_lengths in
41 let left, right =
42 rows
43 |> List.fold ~init:([], []) ~f:(fun accm row ->
44 let left, right = List.split_n row pivot in
45 (left :: fst accm, right :: snd accm))
46 in
47 let left = left |> fixed in
48 let right = right |> fixed in
49 let column_length = dimensions |> List.reduce_exn ~f:( + ) in
50 let n_columns = dimensions |> List.length in
51 let total_length = width - (column_length + n_columns) in
52 let padding = String.make total_length ' ' in
53 List.map2_exn left right ~f:(fun left right ->
54 String.concat [ left; padding; right ])
55 |> List.rev
56
57end
58
59module Hierarchical = struct
60 type tree = Tree of (string * tree list)
61
62 let get_padding = function true -> "│ " | false -> " "
63
64 let get_edge = function true -> "└──" | false -> "├──"
65
66 let fill ~last ~state =
67 match List.length state with
68 | 0 -> []
69 | 1 -> [ last |> get_edge ]
70 | len ->
71 let state = List.slice state 0 (len - 1) in
72 let padding = List.map ~f:get_padding state in
73 List.append padding [ last |> get_edge ]
74
75 let rec to_lines ?(state = []) ?(last = false) next =
76 let (Tree next) = next in
77 let title, children = next in
78 match List.length children with
79 | 0 ->
80 (* leaf *)
81 List.append (fill ~last ~state) [ title; "\n" ]
82 | n_children ->
83 (* node *)
84 List.foldi
85 ~init:
86 [ List.append (fill ~last ~state) [ title; "\n" ] |> String.concat ]
87 ~f:(fun i accm node ->
88 let is_last = Int.equal i (n_children - 1) in
89 let state = List.append state [ phys_equal is_last false ] in
90 let lines = to_lines ~state ~last:is_last node in
91 List.append accm lines)
92 children
93
94 let to_string tree = "\n" ^ (tree |> to_lines |> String.concat)
95end