prettyprinter

pretty printer for moonbit

pretty printer
format
utils
string
moon add Yoorkin/prettyprinter@0.4.10
Download zip
Author
Version
0.4.10
License
Apache-2.0
Last updated
6 months ago
Downloads
5K
README

#pretty printer

A declarative-style pretty printer engine, which includes printers for built-in types such as Array, Map, and Json.

#Usage

Use render to pretty print any type implemented Pretty trait.

let map = {
"name": ["John", "Mike"], "age": ["15","18"], "id": ["11109121","2000012312"]
}
map |> @prettyprinter.render() |> println()

output:
{ "name": ["John", "Mike"], "age": ["15", "18"], "id": ["11109121", "2000012312"] }

#Implement Pretty Trait

Write declarative code to implement a printer for your type. See example in package prettyprinter/example.

#
Pretty

pub(open) trait Pretty {
pretty(Self) -> Document
}

impl Pretty for Unit
impl Pretty for Bool
impl Pretty for Byte
impl Pretty for Char
impl Pretty for Int
impl Pretty for Int16
impl Pretty for Int64
impl Pretty for UInt
impl Pretty for UInt16
impl Pretty for UInt64
impl Pretty for Float
impl Pretty for Double
impl Pretty for String
impl Pretty for Option[A]
impl Pretty for Result[A, B]
impl Pretty for FixedArray[A]
impl Pretty for Bytes
impl Pretty for BigInt
impl Pretty for Array[A]
impl Pretty for Iter[A]
impl Pretty for Iter2[A, B]
impl Pretty for Json
impl Pretty for Map[A, B]
impl Pretty for Deque[A]
impl Pretty for HashMap[A, B]
impl Pretty for HashSet[A]
impl Pretty for T[A]
impl Pretty for List[A]
impl Pretty for T[A]
impl Pretty for Queue[A]
impl Pretty for Set[A]
impl Pretty for Tuple2[A, B]
impl Pretty for Tuple3[A, B, C]
impl Pretty for Tuple4[A, B, C, D]
impl Pretty for Tuple5[A, B, C, D, E]
impl Pretty for Tuple6[A, B, C, D, E, F]
impl Pretty for Tuple7[A, B, C, D, E, F, G]
impl Pretty for Tuple8[A, B, C, D, E, F, G, H]
impl Pretty for Tuple9[A, B, C, D, E, F, G, H, I]

#
Context

pub struct Context {
indent : Int
next_indent : Int
width : Int
}

impl Show for Context

#
Context::current_remain

fn Context::current_remain(self : Context) -> Requirement

#
Context::next_remain

fn Context::next_remain(self : Context) -> Requirement

#
Document

type Document

impl Pretty for Document
impl Add for Document
impl Show for Document

#
Document::requirement

fn Document::requirement(doc : Document) -> Requirement

#
Requirement

pub(all) enum Requirement {
Space(Int)
Infinite
}

impl Add for Requirement
impl Eq for Requirement
impl Show for Requirement

#
braces

fn braces(doc : Document) -> Document

wraps the given document in braces.

inspect(braces(text("doc")), content="{doc}")

#
brackets

fn brackets(doc : Document) -> Document

wraps the given document in brackets.

inspect(brackets(text("doc")), content="[doc]")

#
char

fn char(c : Char) -> Document

#
concat

fn concat(l : Document, r : Document) -> Document

Concatenate two documents. You can also use the + operator.

#
ctor

fn ctor(pkg? : String, ty? : String, ctor : String, payloads : Array[Document], labeled? : Map[String, Document]) -> Document

Represent an enum value.

Example

let doc = ctor(pkg="pkg", ty="Enum", "Constr", [pretty(1), pretty(2)], labeled={ "loc": pretty(100), "name": pretty("cons"), }) inspect( doc, content=( #|@pkg.Enum::Constr(1, 2, loc=100, name="cons") ), ) let doc = ctor( pkg="pkg", ty="Enum", "LongConstructor", [ pretty(100000000), pretty(200000000), pretty(100000000), pretty(200000000), pretty(100000000), pretty(200000000), pretty(100000000), pretty(200000000), ], labeled={ "loc": pretty(100), "name": pretty("cons") }, ) inspect( doc, content=( #|@pkg.Enum::LongConstructor( #| 100000000, #| 200000000, #| 100000000, #| 200000000, #| 100000000, #| 200000000, #| 100000000, #| 200000000, #| loc=100, #| name="cons", #|) ), )

#
dynamic

fn dynamic(f : (Context) -> Document) -> Document

#
empty

let empty : Document

Empty document. render(empty) == ""

#
flow

fn flow(doc : Array[Document]) -> Document

print each documents in the same line if it fits, insert a line break otherwise.

let words = [ "The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog", ] let doc = words.map(fn(x){text(x) + space}) |> flow() inspect(doc, content="The quick brown fox jumps over the lazy dog ") inspect( render(doc, width=10), content=( #|The quick brown #|fox jumps over #|the lazy dog ), )

#
group

fn group(doc : Document) -> Document

group(doc) tries to render the doc on a single line, but if the doc doesn't fit, or contains a hardline, all the switch inside the doc will be rendered with the right document.

#
hardline

let hardline : Document

Force line break with current indentation. This document will always doesn't fit in the current line.

Example

render(text("hello") + nest(hardline + text("world"))) |> inspect( content=( #|hello #| world ), )

#
line

let line : Document

Represents a line break if the line is too long, or a space if it fits.

#
list

fn list(ls : Array[Document]) -> Document

Concatenate documents.

#
mandatory_line

let mandatory_line : Document

Ensures at least one line at this position.
inspect( mandatory_line + nest(line + text("abc")), content=( #| #| abc ), ) inspect( mandatory_line + nest(text("abc")), content=( #| #|abc ), )

#
mandatory_space

let mandatory_space : Document

Inserts at least one space between concatenated text segments.
inspect( text("f();") + mandatory_space + text("//todo"), content="f(); //todo", ) inspect( text("f();") + space + mandatory_space + text("//todo"), content="f(); //todo", ) inspect( text("f();") + hardline + mandatory_space + text("//todo"), content=( #|f(); #|//todo ), )

#
nest

fn nest(indent? : Int, doc : Document) -> Document

Nest the document by n spaces. Any line breaks inside the nested document will be indented by n spaces.

#
parens

fn parens(doc : Document) -> Document

wraps the given document in parentheses.

inspect(parens(text("doc")), content="(doc)")

#
pretty

fn[A : Pretty] pretty(x : A) -> Document

#
record

fn record(pkg? : String, ty? : String, fields : Map[String, Document]) -> Document

Represent a struct.

Example

let doc = record(pkg="pkg", ty="Struct", { "spos": pretty(1), "epos": pretty(2), "file": pretty("abc"), }) inspect( doc, content=( #|@pkg.Struct::{spos: 1, epos: 2, file: "abc"} ), ) let doc = record(pkg="pkg", ty="Struct", { "spos": pretty(1000000000), "epos": pretty(2000000000), "file": pretty("abc"), "spos1": pretty(1000000000), "epos1": pretty(2000000000), "file1": pretty("abc"), }) inspect( doc, content=( #|@pkg.Struct::{ #| spos: 1000000000, #| epos: 2000000000, #| file: "abc", #| spos1: 1000000000, #| epos1: 2000000000, #| file1: "abc", #|} ), )

#
render

fn[A : Pretty] render(document : A, width? : Int) -> String

Renders a document as a pretty string with a specified width.

Arguments

  • x - The document to render.
  • width - The maximum width of the rendered string. Defaults to 80.

Returns

The rendered string.

#
separate

fn separate(sep : Document, docs : Array[Document]) -> Document

This function takes a separator document sep and an array of documents docs and returns a document where each document in the array is separated by the separator document.

Example

let sep = text("-") let docs = [text("Hello"), text("World"), text("!")] separate(sep, docs).pretty() |> inspect(content="Hello-World-!")

#
separate_map

fn[A] separate_map(sep : Document, elems : Array[A], f : (A) -> Document) -> Document

This function takes a separator document, an array of values, and a mapping function, and returns a document where each value in the array is mapped to a document using the mapping function, and then separated by the separator document.

Arguments

  • sep - The separator document to be used between each mapped value.
  • xs - The array of values to be mapped and separated.
  • f - The mapping function that takes a value from the array and returns a document.

Returns

The resulting document where each value is mapped and separated by the separator document.

Example

let doc = separate_map(text(","), [1,2,3], pretty) inspect(doc, content="1,2,3")

#
softline

let softline : Document

Represents a line break if the line is too long, or nothing if it fits.

#
space

let space : Document

Space character. render(space) == " "

#
string

fn string(str : String) -> Document

print the string with double quotes.

inspect(string("Hello, World!"), content="\"Hello, World!\"")

#
surround

fn surround(left : Document, right : Document, doc : Document) -> Document

Surrounds the given document with the left and right documents.

surround(l, r, doc) is equivalent to l + doc + r

Example

inspect(surround(char('['), char(']'), text("doc")), content="[doc]")

#
switch

fn switch(l : Document, r : Document) -> Document

Switch between two documents based on the available space. The left document represents the flatten mode, and the right one the pretty mode. If the left document fits, it will be rendered, otherwise the right one.

#
text

fn text(s : String) -> Document

#
tuple

fn tuple(elems : Array[Document]) -> Document

Represent a tuple.

Example

let doc = tuple([pretty(1), pretty('a'), pretty(true)]) inspect(doc, content="(1, a, true)") let elem = pretty("very long string") let doc = tuple(Array::make(5, elem)) inspect( doc, content=( #|( #| "very long string", #| "very long string", #| "very long string", #| "very long string", #| "very long string", #|) ), )