A linear time pretty printing library, ported from brownplt/pretty-fast-pretty-printer
moon add marianoguerra/pretty-fast-pretty-printerimport {
"marianoguerra/pretty-fast-pretty-printer" @pp,
}///|
test {
let cond = txt("x > 0")
let body = txt("print(x)")
let doc = vert([
horz([txt("while ("), cond, txt(") {")]),
horz([txt(" "), body]),
txt("}"),
])
inspect(
doc.display_string(width=80),
content=(
#|while (x > 0) {
#| print(x)
#|}
),
)
}///|
test {
inspect(
vert([txt("Hello,"), txt("world!")]).display_string(),
content=(
#|Hello,
#|world!
),
)
}///|
test {
let doc = horz([txt("BEGIN "), vert([txt("first line"), txt("second line")])])
inspect(
doc.display_string(),
content=(
#|BEGIN first line
#| second line
),
)
}///|
test {
let doc = if_flat(
txt("[1, 2, 3]"),
vert([txt("[1,"), txt(" 2,"), txt(" 3]")]),
)
inspect(doc.display_string(width=20), content="[1, 2, 3]")
inspect(
doc.display_string(width=5),
content=(
#|[1,
#| 2,
#| 3]
),
)
}///|
test {
let flat = txt("[1, 2]")
let broken = vert([txt("[1,"), txt(" 2]")])
// The group fits in seven columns, so it stays flat and the `))` overflows.
inspect(
horz([if_flat(flat, broken), txt("))")]).display_string(width=7),
content="[1, 2]))",
)
// Told that two more columns follow, it breaks instead.
inspect(
horz([if_flat(flat, broken, reserve=2), txt("))")]).display_string(width=7),
content=(
#|[1,
#| 2]))
),
)
}///|
test {
let given = vert([txt("first line"), txt("second line")])
inspect(
nest(2, given).display_string(),
content=(
#|first line
#| second line
),
)
inspect(
horz([txt(" "), given]).display_string(),
content=(
#| first line
#| second line
),
)
}///|
test {
let doc = horz([txt("(let ((x "), vert([txt("first"), txt("second")])])
assert_eq(doc.display(), ["(let ((x first", " second"])
assert_eq(doc.display(max_indent=4), ["(let ((x first", " second"])
}///|
test {
// A CJK character is one UTF-16 unit but occupies two columns.
assert_eq(txt_as("世界", 4).flat_width(), Some(4))
// An ANSI colour escape is five UTF-16 units and occupies none, so a
// syntax-highlighted document lays out exactly like the plain one.
let red = txt_as("\u{1b}[31m", 0)
let reset = txt_as("\u{1b}[0m", 0)
assert_eq(horz([red, txt("hello"), reset]).flat_width(), Some(5))
}///|
test {
inspect(
horz([txt("x = "), txt_lines("a\nb")]).display_string(),
content=(
#|x = a
#| b
),
)
inspect(
horz([txt("x = "), txt_raw("a\nb")]).display_string(),
content=(
#|x = a
#|b
),
)
}///|
test {
let c = txt("a == b")
let t = txt("a << 2")
let e = txt("a + b")
let doc = pretty([
Str("if ("),
Val(c),
Str(") {\n "),
Val(t),
Str("\n} else {\n "),
Val(e),
Str("\n}"),
])
inspect(
doc.display_string(),
content=(
#|if (a == b) {
#| a << 2
#|} else {
#| a + b
#|}
),
)
}///|
test {
let words = ["This", "is", "a", "sentence", "with", "eight", "words"].map(txt)
inspect(
wrap(words).display_string(width=20),
content=(
#|This is a sentence
#|with eight words
),
)
}///|
test {
let doc = sep_by(["alpha", "beta", "gamma"].map(txt), sep=", ", vert_sep=",")
inspect(doc.display_string(width=40), content="alpha, beta, gamma")
inspect(
doc.display_string(width=10),
content=(
#|alpha,
#|beta,
#|gamma
),
)
}///|
test {
let doc = begin_like_sexpr(txt("begin"), [
standard_sexpr(txt("+"), [txt("1"), txt("2")]),
standard_sexpr(txt("display"), [txt("a-fairly-long-variable-name")]),
])
inspect(
doc.display_string(width=30),
content=(
#|(begin
#| (+ 1 2)
#| (display
#| a-fairly-long-variable-name))
),
)
}moon test # unit tests, including the ported upstream suite
moon run cmd/main # a small s-expression printer, shown at three widthstest {
let doc = vert([txt("one"), horz([txt(" "), txt("two")])])
assert_eq(doc.display(), ["one", " two"])
}test {
inspect(
vert([txt("one"), txt("two")]).display_string(),
content=(
#|one
#|two
),
)
}test {
assert_eq(horz([txt("ab"), txt("cd")]).flat_width(), Some(4))
assert_eq(vert([txt("ab"), txt("cd")]).flat_width(), None)
}test {
let buf = StringBuilder::new()
buf.write_string("> ")
vert([txt("one"), txt("two")]).write_to(buf)
inspect(
buf.to_string(),
content=(
#|> one
#|two
),
)
}test {
let doc = horz([txt("(let ((x "), vert([txt("first"), txt("second")])])
assert_eq(doc.display(), ["(let ((x first", " second"])
assert_eq(doc.display(max_indent=4), ["(let ((x first", " second"])
}test {
let group = if_flat(
txt("[1, 2, 3]"),
vert([txt("[1,"), txt(" 2,"), txt(" 3]")]),
)
let doc = horz([txt(" "), vert([txt("xs ="), group])])
// At width 16 the group starts in column 8 and does not fit.
assert_eq(doc.display(width=16), [
" xs =", " [1,", " 2,", " 3]",
])
// Capped at column 2 it does.
assert_eq(doc.display(width=16, max_indent=2), [" xs =", " [1, 2, 3]"])
}(keyword
bodies
...
bodies)test {
let doc = begin_like_sexpr(txt("begin"), ["1", "2", "3"].map(txt))
inspect(
doc.display_string(),
content=(
#|(begin
#| 1
#| 2
#| 3)
),
)
}test {
let doc = concat([
txt("BEGIN "),
vert([txt("first line"), txt("second line")]),
])
inspect(
doc.display_string(),
content=(
#|BEGIN first line
#|second line
),
)
}test {
let docs = ["a", "b", "c"].map(txt)
inspect(docs.fold(init=empty, concat2).display_string(), content="abc")
}test {
let plain = horz([if_flat(txt("a"), vert([txt("a"), txt("A")])), txt("b")])
inspect(plain.display_string(width=20), content="ab")
let forced = horz([
if_flat(full_line(txt("a")), vert([txt("a"), txt("A")])),
txt("b"),
])
inspect(
forced.display_string(width=20),
content=(
#|a
#|Ab
),
)
}test {
let doc = horz([txt("BEGIN "), vert([txt("first line"), txt("second line")])])
inspect(
doc.display_string(),
content=(
#|BEGIN first line
#| second line
),
)
}test {
let docs = ["a", "b", "c"].map(txt)
inspect(docs.fold(init=empty, horz2).display_string(), content="abc")
}test {
let flat = txt("[1, 2]")
let broken = vert([txt("[1,"), txt(" 2]")])
// The group fits in seven columns, so it stays flat -- and then the `))`
// that follows overflows.
let doc = horz([if_flat(flat, broken), txt("))")])
inspect(doc.display_string(width=7), content="[1, 2]))")
// Told that two more columns follow, it breaks, and the result fits.
let doc = horz([if_flat(flat, broken, reserve=2), txt("))")])
inspect(
doc.display_string(width=7),
content=(
#|[1,
#| 2]))
),
)
}test {
let doc = if_flat(
txt("[1, 2, 3]"),
vert([txt("[1,"), txt(" 2,"), txt(" 3]")]),
)
inspect(doc.display_string(width=20), content="[1, 2, 3]")
inspect(
doc.display_string(width=5),
content=(
#|[1,
#| 2,
#| 3]
),
)
}(keyword defn body)(keyword defn
body)test {
let doc = lambda_like_sexpr(
txt("lambda"),
txt("(number)"),
txt("(* number number)"),
)
inspect(doc.display_string(), content="(lambda (number) (* number number))")
inspect(
doc.display_string(width=25),
content=(
#|(lambda (number)
#| (* number number))
),
)
}test {
let doc = vert([txt("first line"), txt("second line")])
inspect(
nest(2, doc).display_string(),
content=(
#|first line
#| second line
),
)
}test {
let doc = vert([txt("first line"), txt("second line")])
inspect(
horz([txt(" "), doc]).display_string(),
content=(
#| first line
#| second line
),
)
}test {
inspect(parens(txt("a b")).display_string(), content="(a b)")
}test {
let c = txt("a == b")
let t = txt("a << 2")
let e = txt("a + b")
let doc = pretty([
Str("if ("),
Val(c),
Str(") {\n "),
Val(t),
Str("\n} else {\n "),
Val(e),
Str("\n}"),
])
inspect(
doc.display_string(),
content=(
#|if (a == b) {
#| a << 2
#|} else {
#| a + b
#|}
),
)
}items[0] sep items[1] sep ... items[n]items[0] vert_sep
items[1] vert_sep
...
items[n]test {
let items = ["alpha", "beta", "gamma"].map(txt)
let doc = sep_by(items, sep=", ", vert_sep=",")
inspect(doc.display_string(width=40), content="alpha, beta, gamma")
inspect(
doc.display_string(width=10),
content=(
#|alpha,
#|beta,
#|gamma
),
)
}(func args ... args)(func
args
...
args)test {
let doc = standard_sexpr(txt("function"), [txt("very-long-argument")])
inspect(doc.display_string(), content="(function very-long-argument)")
inspect(
doc.display_string(width=20),
content=(
#|(function
#| very-long-argument)
),
)
}test {
inspect(txt("Hello, world").display_string(), content="Hello, world")
}test {
// A CJK character is one UTF-16 unit wide but occupies two columns.
let cjk = txt_as("世界", 4)
assert_eq(cjk.flat_width(), Some(4))
// An ANSI colour escape is five UTF-16 units and occupies none.
let red = txt_as("\u{1b}[31m", 0)
let reset = txt_as("\u{1b}[0m", 0)
assert_eq(horz([red, txt("hello"), reset]).flat_width(), Some(5))
}test {
inspect(
horz([txt("> "), txt_lines("one\ntwo")]).display_string(),
content=(
#|> one
#| two
),
)
}test {
assert_eq(horz([txt("x = "), txt_lines("a\nb")]).display(), ["x = a", " b"])
assert_eq(horz([txt("x = "), txt_raw("a\nb")]).display(), ["x = a", "b"])
}test {
inspect(
vert([txt("Hello,"), txt("world!")]).display_string(),
content=(
#|Hello,
#|world!
),
)
}test {
inspect(
vert2(txt("a"), txt("b")).display_string(),
content=(
#|a
#|b
),
)
}test {
let words = ["This", "is", "a", "sentence", "with", "eight", "words"].map(txt)
inspect(
wrap(words).display_string(width=20),
content=(
#|This is a sentence
#|with eight words
),
)
}A linear time pretty printing library, ported from brownplt/pretty-fast-pretty-printer