glam/doc

Types

A document that can be pretty printed with to_string.

pub opaque type Document

Constants

pub const empty: Document

An empty document that is printed as an empty string.

Examples

empty |> to_string(80)
// -> ""
pub const flex_space: Document

A document that is rendered as a single whitespace " " but can be broken by the pretty printer into newlines instead. Instead of splitting all spaces or no spaces (like it would do with space inside a group), the pretty printer can decide on a space-by-space basis.

If a flex_space inside a group needs to be broken to fit it on multiple lines, following flex_spaces may end up not being broken.

This is a shorthand for flex_break(" ", "").

Examples

let message =
  ["Gleam", "is", "fun!"]
  |> list.map(from_string)
  |> join(with: flex_space)
  |> group

to_string(message, 80)
// -> "Gleam is fun!"

to_string(message, 10)
// -> "Gleam is
fun!"

to_string(message, 4) // -> “Gleam // is // fun!”

pub const line: Document

A document that is always printed as a single new line.

Examples

line |> to_string(80)
// -> "\n"
pub const soft_break: Document

A document that is always rendered as an empty string but can act as a breaking point for the pretty printer.

This is a shorthand for break("", "").

Examples

let doc = [from_string("soft"), soft_break, from_string("break")]

doc |> to_string(80)
// -> "softbreak"

doc |> to_string(5)
// -> "soft
// break"
pub const space: Document

A document that is rendered as a single whitespace " " but can be broken by the pretty printer into newlines instead.

This is a shorthand for break(" ", "").

Examples

let doc =
  ["pretty", "printed"]
  |> list.map(from_string)
  |> join(with: space)

doc |> to_string(80)
// -> "pretty printed"

doc |> to_string(10)
// -> "pretty
// printed"

Functions

pub fn append(
  to first: Document,
  doc second: Document,
) -> Document

Joins a document into the end of another.

Examples

from_string("pretty")
|> append(from_string(" printer"))
|> to_string(80)
// -> "pretty printer"
pub fn append_docs(
  first: Document,
  docs: List(Document),
) -> Document

Joins multiple documents into the end of another.

This is a shorthand for append(to: first, doc: concat(docs)).

Examples

from_string("pretty")
|> append_docs([
  from_string("printing"),
  space,
  from_string("rocks!"),
])
|> to_string(80)
// -> "pretty printing rocks!"
pub fn break(unbroken: String, broken: String) -> Document

A document after which the pretty printer can insert a new line. A newline is added after a break document if the group it’s part of could not be rendered on a single line.

If the pretty printer decides to add a newline after break it will be rendered as its second argument, otherwise as its first argument.

Examples

let message =
  [from_string("pretty"), break("•", "↩"), from_string("printed")]
  |> concat
  |> group

message |> to_string(20)
// -> "pretty•printed"

message |> to_string(10)
// -> "pretty↩
// printed"
pub fn concat(docs: List(Document)) -> Document

Joins a list of documents into a single document.

The resulting pretty printed document would be the same as pretty printing each document separately and concatenating it together with <>:

docs |> concat |> to_string(n) ==
docs |> list.map(to_string(n)) |> string.concat

Examples

["pretty", " ", "printed"]
|> list.map(from_string)
|> concat
|> to_string(80)
// -> "pretty printed"
pub fn concat_join(
  docs: List(Document),
  with separators: List(Document),
) -> Document

Joins a list of documents into a single one by inserting the given separators between each existing document.

This is a shorthand for join(docs, concat(separators)).

Examples

["wow", "so", "many", "commas"]
|> list.map(from_string)
|> concat_join([from_string(","), space])
|> to_string(80)
// -> "wow, so, many, commas"
pub fn debug(document: Document) -> Document

Returns a debug version of the given document that can be pretty printed to see the structure of a document.

This can help you see how your data structures get turned into documents and check if the document is what you’d expect.

  • groups are surrounded by square brackets.
  • nests are surrounded by angle brackets and have a smal superscript with the nesting.
  • concatenated documents are separated by dots.
  • breaks are rendered surrounded by curly brackets and show both the broken and unbroken versions.
  • lines are rendered as the string lf followed by a superscript number of lines.
pub fn flex_break(unbroken: String, broken: String) -> Document

A document after which the pretty printer can insert a new line. The difference with a simple break is that, the pretty printer will decide wether to add a new line or not on a space-by-space basis.

While all the break inside a group are broken or not, some flex_breaks may be broken and some not, depending wether the document can fit on a single line or not. Hence the name flex.

If the pretty printer decides to add a newline after flex_break it will be rendered as its first argument, otherwise as its first argument.

Examples

let message =
  [from_string("pretty"), from_string("printed"), from_string("string")]
  |> join(with: flex_break("•", "↩"))
  |> group

message |> to_string(80)
// -> "pretty•printed•string"

message |> to_string(20)
// -> "pretty•printed↩
// string"
pub fn force_break(doc: Document) -> Document

Forces the pretty printer to break all the breaks of the outermost document. This still has no effect on groups as the pretty printer will always try to put them on a single line before splitting them.

Examples

[from_string("pretty"), break("•", "↩"), from_string("printed")]
|> concat
|> force_break
|> group
|> to_string(100)
// -> "pretty↩
// printed"
pub fn from_string(string: String) -> Document

Turns a string into a document.

Examples

"doc" |> from_string |> to_string(80)
// -> "doc"
pub fn group(doc: Document) -> Document

Allows the pretty printer to break the break documents inside the given group.

When the pretty printer runs into a group it first tries to render it on a single line, displaying all the breaks as their first argument. If the group fits this is the final pretty printed result.

However, if the group does not fit on a single line all the breaks inside that group are rendered as their second argument and immediately followed by a newline.

Any nested group is considered on its own and may or may not be split, depending if it fits on a single line or not. So, even if the outermost group is broken, its nested groups may still end up on a single line.

Examples

let food =
  ["lasagna", "ravioli", "pizza"]
  |> list.map(from_string) |> join(with: space) |> group
let message =
  [from_string("Food I love:"), space, food] |> concat |> group

message |> to_string(80)
// -> "Food I love: lasagna ravioli pizza"

message |> to_string(30)
// -> "Food I love:
// lasagna ravioli pizza"
// ^-- After splitting the outer group, the inner one can fit
//     on a single line so the pretty printer does not split it

message |> to_string(20)
// "Food I love:
// lasagna
// ravioli
// pizza"
// ^-- Even after splitting the outer group, the inner one wouldn't
//     fit on a single line, so the pretty printer splits that as well
pub fn join(
  docs: List(Document),
  with separator: Document,
) -> Document

Joins a list of documents inserting the given separator between each existing document.

Examples

let message =
  ["Gleam", "is", "fun!"]
  |> list.map(from_string)
  |> join(with: space)

message |> to_string(80)
// -> "Gleam is fun!"
pub fn lines(size: Int) -> Document

A document that is always printed as a series of consecutive newlines.

Examples

lines(3) |> to_string(80)
// -> "\n\n\n"
pub fn nest(doc: Document, by indentation: Int) -> Document

Increases the nesting level of a document by the given amount.

When the pretty printer breaks a group by inserting a newline, it also adds a whitespace padding equal to its nesting level.

Examples

let one = [space, from_string("one")] |> concat |> nest(by: 1)
let two = [space, from_string("two")] |> concat |> nest(by: 2)
let three = [space, from_string("three")] |> concat |> nest(by: 3)
let list = [from_string("list:"), one, two, three] |> concat |> group

list |> to_string(10)
// -> "list:
//  one
//   two
//    three"
pub fn nest_docs(
  docs: List(Document),
  by indentation: Int,
) -> Document

Joins together a list of documents and increases their nesting level.

This is a shorthand for nest(concat(docs), by: indentation).

Examples

[from_string("one"), space, from_string("two")]
|> nest_docs(by: 2)
|> append(space)
|> append(from_string("three"))
|> group
|> to_string(5)
// ->
// one
//   two
// three
pub fn prepend(
  to first: Document,
  doc second: Document,
) -> Document

Prefixes a document to another one.

Examples

from_string("printed!")
|> prepend(from_string("pretty "))
|> to_string(80)
// -> "pretty printed!"
pub fn prepend_docs(
  first: Document,
  docs: List(Document),
) -> Document

Prefixes multiple documents to another one.

This is a shorthand for prepend(to: first, doc: concat(docs)).

Examples

from_string("fun!")
|> prepend_docs([from_string("Gleam "), from_string("is ")])
|> to_string(80)
// -> "Gleam is fun!"
pub fn to_string(doc: Document, limit: Int) -> String

Turns a document into a pretty printed string, trying to fit it into lines of maximum size specified by limit.

The pretty printed process can be thought of as follows:

  • the pretty printer first tries to print every group on a single line
  • all the break documents are rendered as their first argument
  • if the string fits on the specified width this is the result
  • if the string does not fit on a single line the outermost group is split:
    • all of its break documents are rendered as their second argument
    • a newline is inserted after every break
    • a padding of the given nesting level is added after every inserted newline
    • all inner groups are then considered on their own: the splitting of the outermost group does not imply that the inner groups will be split as well

Examples

For some examples of how pretty printing works for each kind of document you can have a look at the package documentation. There’s also a step-by-step tutorial that will guide you through the implementation of a simple pretty printer, covering most of the Glam API.

pub fn zero_width_string(string: String) -> Document

Turns a string into a document whose length is not taken into account when formatting it.

This kind of string can be used to render non-visible characters like ansi color codes.

Examples

// Should break in two lines, but doesn't because of the zero_width_string
// does not contribute to the total line length.
[
  zero_width_string("\u{001b}[1;31m"),
  from_string("I'm a red"),
  break(", ", ","),
  from_string("bold text"),
]
|> concat
|> group
|> to_string(20)
// -> "\u{001b}[1;31mI'm a red, bold text"
Search Document