Giter VIP home page Giter VIP logo

printbox's Introduction

PrintBox build

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

  • text (assuming monospace font)
  • HTML (using tyxml )
  • LaTeX (not implemented yet)

Documentation

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

License

BSD-2-clauses

Build

Ideally, use opam with OCaml >= 4.08:

$ opam install printbox printbox-text

Manually:

$ make install

A few examples

importing the module

# #require "printbox";;
# #require "printbox-text";;

# module B = PrintBox;;
module B = PrintBox

simple box

# let box = B.(hlist [ text "hello"; text "world"; ]);;
val box : B.t = <abstr>

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

less simple boxes

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

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

printing a table

# 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 = <fun>

# let sq = square 5;;
val sq : B.t = <abstr>
# 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.

# let sq2 = square 3 |> B.frame ;;
val sq2 : B.t = <abstr>

# 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:

# 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 = <abstr>

# 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.

# #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.00.1││
│├───┼───┤│
││1.01.1││
│├───┼───┤│
││2.02.1││
│└───┴───┘│
└─────────┘
# #remove_printer PrintBox_text.pp;;

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

# let b = PrintBox.(frame @@ hlist [text "a\nb"; text "c"]);;
val b : B.t = <abstr>
# 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:

# let b2 = PrintBox.(
    let style = Style.(fg_color Red) in
  frame @@ hlist [text_with_style style "a\nb"; text "c"]);;
val b2 : B.t = <abstr>
# Format.printf "some text %a around@." (PrintBox_text.pp_with ~style:true) b2;;
some text ┌─┬─┐
          │a│c│
          │b│ │
          └─┴─┘ around
- : unit = ()
# 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 = <abstr>
utop [1]: print_endline @@ PrintBox_text.to_string b3;;

gives the following image.

Handling unicode

Unicode (utf8) text is handled.

# 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 = <abstr>

# 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:

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. 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 <details> element. To activate it, use the tree_summary config:

# #require "printbox-html";;
# print_endline PrintBox_html.(to_string
  ~config:Config.(tree_summary true default)
    B.(tree (text "0")[text "1"; tree (text "ω") [text "ω²"]]));;
<div><details><summary><span>0</span></summary><ul><li><div>1</div></li><li><details><summary><span>ω</span></summary><ul><li><div>ω²</div></li></ul></details></li></ul></details></div>

- : unit = ()

printbox's People

Contributors

arbipher avatar c-cube avatar fardalem avatar gbury avatar kit-ty-kate avatar lukstafi avatar mattiasdrp avatar mattjbray avatar rgrinberg avatar typetheory avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

printbox's Issues

Allow the use of styles or colors

Thanks for this useful package. It would be great to be able to apply styles (bold, italic) or colors on specific boxes; or to have boxes preserve the style of strings inside them (set with libraries such as CCFormat or Fmt).

right-alignment in grids

control alignment by padding by col.size - cell.size on the left, rather than the right.

more generally that should be a combinator (how to pad a cell within its rendering space)

Release compatible with Dune 3

Thanks for this excellent library!

Could we get a release with the Dune 3 compat fix (#22) shortly?

We're currently using this library in Irmin, and would appreciate being able to upgrade to Dune 3 as soon as possible :-)

Doesn't build using OPAMBUILDDOC=true: Cannot create directory ‘/usr/local/share/doc’

This is on opam, 2.0.0~rc:

% opam install printbox
The following actions will be performed:
  ∗  install printbox 0.1

=-=- Gathering sources =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[printbox.0.1] downloaded from cache at https://opam.ocaml.org/2.0/cache

=-=- Processing actions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[ERROR] The installation of printbox failed at "make install".
Processing  2/2: [printbox: ocamlfind remove]
#=== ERROR while installing printbox.0.1 ======================================#
# context      2.0.0~rc | linux/x86_64 | ocaml-base-compiler.4.06.1 | https://opam.ocaml.org/2.0#ba33a2cc
# path         ~/.opam2/4.06.1/.opam-switch/build/printbox.0.1
# command      /usr/bin/make install
# exit-code    2
# env-file     ~/.opam2/log/printbox-9719-6cc03f.env
# output-file  ~/.opam2/log/printbox-9719-6cc03f.out
### output ###
# [...]
# mkdir: cannot create directory ‘/usr/local/share/doc’: Permission denied
# E: Failure("Command ''mkdir' '/usr/local/share/doc'' terminated with error code 1")
# make: *** [Makefile:19: install] Error 1

Representing DAGs (box diagrams). Representing plots.

Hi! Would others benefit from such advanced functionality? If I work on it, should I upstream it? Plots could be external to PrintBox -- treating a box as a canvas. But DAGs would be easier to implement integral to PrintBox.

Multiline text is broken in `PrintBox_html`

I.e. PrintBox.lines, the lines should be interspersed with <br/>. Currently the lines aren't even space separated.

There's also unsupported-yet features which seem to only be: padding and vertical alignment, less of a problem because more of an esthetics thing.

Assertion triggered in `PrintBox_text`

I somehow managed to trigger assert (Pos.compare curr_pos start_pos <= 0); (in to_buf_aux_). The problem disappeared with changes on my side, I'll try to reproduce it...

Better Unicode advice

The advice here is very inaccurate, unless you only care about US-ASCII, counting scalar values will not give you good a visual length, please do not dispel such an idea.

Better advice would be to either count the grapheme clusters (e.g. using Uuseg_string) and/or accumulate on the scalar values @pqwy's carefully crafted Uucp.Break.tty_width_hint whose doc string also gives a nice overview of the challenges for terminal width measurements.

Extensibility considerations

Hi,

First of all, thank you for such a great library!

I wonder if you guys have considered an extensibility story for printbox. I know you've made t opaque and view private in 0.2 (I am not 100% sure about the reasoning here) but have you thought about allowing end-users to add their own constructs if t was made extensible instead (I guess that would make view go away?)

type t = ..

type t += TitledFrame of (string * t)
type t += MyWidget

Where printers like text or html would have a way to pass a handler for a catch-all match that is not handled by the library itself? Something like

 PrintBox_text.to_string ~extension_handler box

Support multiple box-drawing sets

Currently, boxes are drawn with '+', '-' and '|'. Support for unicode's box-drawing characters would be good as they are designed to match up more precisely than the ASCII options currently available.

The box-drawing characters also include more specific joiners than +. There are angle joiners (e.g., ┌), three prongs joiners (e.g., ├), and the full joiner (┼). This would probably cause major changes to the code base.

See https://www.fileformat.info/info/unicode/char/search.htm?q=box+drawings&preview=entity for a full list.


From a user interface perspective, I'd be content with something along the lines of type drawings = ASCII | UTF8_LIGHT | UTF8_HEAVY, but I could also see type drawings = { hz: Uchar.t; vt: Uchar.t; join: Uchar.t; hzdown: Uchar.t; hzup: Uchar.t; … }.

Misbehavior of trees with empty nodes

While working on issue #26 I encountered the following bug / arguably undesirable behavior (to the left of subchild 4).
I would prefer that empty nodes are "transparent" to connectors: no up-tick toward an unrelated box.

let b =
  let open PrintBox in
  tree (frame @@ text "root") [
    frame @@ text "child 1";
    text "child 2";
    (* Note that an empty tree node causes a potentially-undesired but expected disconnection. *)
    frame @@ tree empty [
      tree (frame @@ text "header 3") [frame @@ text "subchild 3"]
    ];
    (* FIXME: empty tree nodes cause weird-looking connectors. *)
    tree empty [
      tree empty [frame @@ text "subchild 4"]
    ];
    frame @@ text "child 5"
  ]

let () = print_endline @@ PrintBox_text.to_string b

produces at head:

┌────┐
│root│
└────┘
├─┌───────┐
│ │child 1│
│ └───────┘
├─child 2
├─┌──────────────────┐
│ │└─┌────────┐      │
│ │  │header 3│      │
│ │  └────────┘      │
│ │  └─┌──────────┐  │
│ │    │subchild 3│  │
│ │    └──────────┘  │
│ └──────────────────┘
├─└─└─┌──────────┐
│     │subchild 4│
│     └──────────┘
└─┌───────┐
  │child 5│
  └───────┘

Tree connectors touching frames

Hi!

What was the motivation behind not bleeding the tree connectors into the box frames? I think it would look nicer.
E.g.

│┌─┐                                          │
││+│                                          │
│└─┘                                          │
│├─┌──┐                                       │
││ │*.│                                       │
││ └──┘                                       │
││ ├─┌───────┐                                │
││ │ │[34] *.│                                │
││ │ └───────┘                                │
││ │ ├─┌─┐                                    │
││ │ │ │+│                                    │
││ │ │ └─┘

vs.

│┌─┐                                          │
││+│                                          │
│├─┘                                          │
│├─┬──┐                                       │
││ │*.│                                       │
││ ├──┘                                       │
││ ├─┬───────┐                                │
││ │ │[34] *.│                                │
││ │ ├───────┘                                │
││ │ ├─┬─┐                                    │
││ │ │ │+│                                    │
││ │ │ ├─┘

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.