Skip to content
heff

std.doc

Pretty-printing documents: Wadler’s algorithm as Haskell’s prettyprinter has it (layoutPretty, ribbon 1.0), so that the formatter, and any other code that lays text out, can be written in heff. A Doc is built with text, line, group, nest and align, and render lays it out at a width: a group goes on one line if it fits, and breaks otherwise. The language is call-by-value, so the layout’s laziness — fits looks at the first line only — is a Unit -> SDoc at each step.

Doc

data Doc
= Fail
| None
| Text String
| Line
| FlatAlt Doc Doc
| Cat Doc Doc
| Nest Int Doc
| Union Doc Doc
| Column (Int -> Doc)
| Nesting (Int -> Doc)

emptyDoc

emptyDoc : Doc

text

text : String -> Doc

Text without newlines (pretty takes text with them).

hardline

hardline : Doc

A line break, kept when its group is flattened.

line

line : Doc

A line break, a space when its group is flattened.

linebreak

linebreak : Doc

A line break, nothing when its group is flattened.

softline

softline : Doc

A space if what follows fits on the line, a line break otherwise.

<>

(<>) : Doc -> Doc -> Doc

<+>

(<+>) : Doc -> Doc -> Doc

nest

nest : Int -> Doc -> Doc

The document, its line breaks after nest’s further columns in.

flatAlt

flatAlt : Doc -> Doc -> Doc

The first when flattened, the second when not.

flatten

flatten : Doc -> Doc

The document on one line: each line a space, each linebreak nothing, each hardline a failure the layout backs out of.

Flat

data Flat = Flattened Doc | AlreadyFlat | NeverFlat

group

group : Doc -> Doc

On one line if it fits, as written otherwise.

align

align : Doc -> Doc

The document, its line breaks at the column where it starts.

hang

hang : Int -> Doc -> Doc

indent

indent : Int -> Doc -> Doc

concatWith

concatWith : (Doc -> Doc -> Doc) -> List Doc -> Doc

pretty

pretty : String -> Doc

Text, its newlines hard line breaks.

vsep

vsep : List Doc -> Doc

hsep

hsep : List Doc -> Doc

vcat

vcat : List Doc -> Doc

sep

sep : List Doc -> Doc

enclose

enclose : Doc -> Doc -> Doc -> Doc

textWidth

textWidth : String -> Int

How many columns a text takes: one a rune, whatever units it takes (an East Asian wide one too, as Go’s text/tabwriter counts).

>>> List.map textWidth ["abc", "é😀", ""]
[3, 2, 0]

SDoc

data SDoc
= SEmpty
| SFail
| SText String Int (Unit -> SDoc)
| SLine Int (Unit -> SDoc)

fits

fits : Int -> Int -> Int -> SDoc -> Bool

display

display : SDoc -> String

renderWidth

renderWidth : Int -> Doc -> String

render

render : Doc -> String