Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/c-cube/printbox

print nested boxes, lists, arrays, tables in several formats
https://github.com/c-cube/printbox

ocaml pretty-printing tables text-rendering tree

Last synced: 6 days ago
JSON representation

print nested boxes, lists, arrays, tables in several formats

Awesome Lists containing this project

README

        

# PrintBox [![build](https://github.com/c-cube/printbox/actions/workflows/main.yml/badge.svg)](https://github.com/c-cube/printbox/actions/workflows/main.yml)

Allows to print nested boxes, lists, arrays, tables in several formats,
including:

- text (assuming monospace font)
- HTML (using [tyxml](https://github.com/ocsigen/tyxml/) )
- LaTeX (*not implemented yet*)

## Documentation

See https://c-cube.github.io/printbox/

See the [test/](test/) and [examples/](examples/) directories for illustrations of potential usage.

## License

BSD-2-clauses

## Build

Ideally, use [opam](http://opam.ocaml.org/) with OCaml >= 4.08:

```sh non-deterministic=command
$ opam install printbox printbox-text
```

Manually:

```sh non-deterministic=command
$ make install
```

## A few examples

#### importing the module

```ocaml
# #require "printbox";;
# #require "printbox-text";;

# module B = PrintBox;;
module B = PrintBox
```

#### simple box

```ocaml
# let box = B.(hlist [ text "hello"; text "world"; ]);;
val box : B.t =

# PrintBox_text.output stdout box;;
hello│world
- : unit = ()
```

#### less simple boxes

```ocaml
# let box =
B.(hlist
[ text "I love\nto\npress\nenter";
grid_text [| [|"a"; "bbb"|];
[|"c"; "hello world"|] |]
])
|> B.frame;;
val box : B.t =

# PrintBox_text.output stdout box;;
┌──────┬─┬───────────┐
│I love│a│bbb │
│to ├─┼───────────┤
│press │c│hello world│
│enter │ │ │
└──────┴─┴───────────┘
- : unit = ()
```

#### printing a table

```ocaml
# let square n =
(* function to make a square *)
Array.init n
(fun i -> Array.init n (fun j -> B.sprintf "(%d,%d)" i j))
|> B.grid ;;
val square : int -> B.t =

# let sq = square 5;;
val sq : B.t =
# PrintBox_text.output stdout sq;;
(0,0)│(0,1)│(0,2)│(0,3)│(0,4)
─────┼─────┼─────┼─────┼─────
(1,0)│(1,1)│(1,2)│(1,3)│(1,4)
─────┼─────┼─────┼─────┼─────
(2,0)│(2,1)│(2,2)│(2,3)│(2,4)
─────┼─────┼─────┼─────┼─────
(3,0)│(3,1)│(3,2)│(3,3)│(3,4)
─────┼─────┼─────┼─────┼─────
(4,0)│(4,1)│(4,2)│(4,3)│(4,4)
- : unit = ()
```

#### frame

Why not put a frame around this? That's easy.

```ocaml
# let sq2 = square 3 |> B.frame ;;
val sq2 : B.t =

# PrintBox_text.output stdout sq2;;
┌─────┬─────┬─────┐
│(0,0)│(0,1)│(0,2)│
├─────┼─────┼─────┤
│(1,0)│(1,1)│(1,2)│
├─────┼─────┼─────┤
│(2,0)│(2,1)│(2,2)│
└─────┴─────┴─────┘
- : unit = ()
```

#### tree

We can also create trees and display them using indentation:

```ocaml
# let tree =
B.tree (B.text "root")
[ B.tree (B.text "a") [B.text "a1\na1"; B.text "a2\na2\na2"];
B.tree (B.text "b") [B.text "b1\nb1"; B.text "b2"; B.text "b3"];
];;
val tree : B.t =

# PrintBox_text.output stdout tree;;
root
├─a
│ ├─a1
│ │ a1
│ └─a2
│ a2
│ a2
└─b
├─b1
│ b1
├─b2
└─b3
- : unit = ()
```

#### Installing the pretty-printer in the toplevel

`PrintBox_text` contains a `Format`-compatible pretty-printer that
can be used as a default printer for boxes.

```ocaml
# #install_printer PrintBox_text.pp;;
# PrintBox.(frame @@ frame @@ init_grid ~line:3 ~col:2 (fun ~line:i ~col:j -> sprintf "%d.%d" i j));;
- : B.t =
┌─────────┐
│┌───┬───┐│
││0.0│0.1││
│├───┼───┤│
││1.0│1.1││
│├───┼───┤│
││2.0│2.1││
│└───┴───┘│
└─────────┘
# #remove_printer PrintBox_text.pp;;
```

Note that this pretty-printer plays nicely with `Format` boxes:

```ocaml
# let b = PrintBox.(frame @@ hlist [text "a\nb"; text "c"]);;
val b : B.t =
# Format.printf "some text %a around@." PrintBox_text.pp b;;
some text ┌─┬─┐
│a│c│
│b│ │
└─┴─┘ around
- : unit = ()
```

Also works with basic styling on text now:

```ocaml
# let b2 = PrintBox.(
let style = Style.(fg_color Red) in
frame @@ hlist [text_with_style style "a\nb"; text "c"]);;
val b2 : B.t =
# Format.printf "some text %a around@." (PrintBox_text.pp_with ~style:true) b2;;
some text ┌─┬─┐
│a│c│
│b│ │
└─┴─┘ around
- : unit = ()
```

```ocaml non-deterministic=command
# let b3 = PrintBox.(
let style = Style.(fg_color Red) in
frame @@ grid_l [
[text_with_style style "a\nb";
line_with_style Style.(set_bold true @@ bg_color Green) "OH!"];
[text "c"; text "ballot"];
])
val b3 : PrintBox.t =
utop [1]: print_endline @@ PrintBox_text.to_string b3;;
```

gives ![the following image](./.screen1.png).

#### Handling unicode

Unicode (utf8) text is handled.

```ocaml
# let b =
PrintBox.(frame @@
hlist [
vlist[text "oï ωεird nums:\nπ/2\nτ/4";
tree (text "0")[text "1"; tree (text "ω") [text "ω²"]]];
frame @@ vlist [text "sum=Σ_i a·xᵢ²\n—————\n1+1"; text "Ōₒ\nÀ"]]);;
val b : B.t =

# print_endline @@ PrintBox_text.to_string b;;
┌──────────────┬───────────────┐
│oï ωεird nums:│┌─────────────┐│
│π/2 ││sum=Σ_i a·xᵢ²││
│τ/4 ││————— ││
├──────────────┤│1+1 ││
│0 │├─────────────┤│
│├─1 ││Ōₒ ││
│└─ω ││À ││
│ └─ω² │└─────────────┘│
└──────────────┴───────────────┘
- : unit = ()
```

#### HTML output (with `tyxml`)

Assuming you have loaded `printbox-html` somehow:

```ocaml non-deterministic=command
let out = open_out "/tmp/foo.html";;
output_string out (PrintBox_html.to_string_doc (square 5));;
```

which prints some HTML in the file [foo.html](docs/foo.html).
Note that trees are printed in HTML using nested lists, and
that `PrintBox_html.to_string_doc` will insert some javascript to
make sub-lists fold/unfold on click (this is useful to display very large
trees compactly and exploring them incrementally). But there is also
an alternative solution where trees are printed in HTML using the
`` element. To activate it, use the `tree_summary` config:

```ocaml
# #require "printbox-html";;
# print_endline PrintBox_html.(to_string
~config:Config.(tree_summary true default)
B.(tree (text "0")[text "1"; tree (text "ω") [text "ω²"]]));;


0

  • 1


  • ω
    • ω²



- : unit = ()
```