This library provides pretty printing combinators.
The interface is that of
Daan Leijen's library
with the
linear-time, bounded implementation
by Olaf Chitil.
Note that the implementation of fill
and fillBreak
is not linear-time bounded
Support of ANSI escape codes for formatting and colorisation of documents
in text terminals (see https://en.wikipedia.org/wiki/ANSI_escape_code
)
This library corresponds to the library provided by the PAKCS and KiCS2 compilers. But it was partially rewritten and reorganized to make use of type classes and provide pretty printing combinators in a package.
Standard printing with a column length of 80.
The empty document
:: Doc
|
an empty document |
Is the document empty?
The document (text s)
contains the literal string s
.
The string shouldn't contain any newline (\n) characters.
If the string contains newline characters,
the function string
should be used.
:: String
|
a string without newline ([\n](#\n) ) characters
|
-> Doc
|
a document which contains the literal string |
The document (linesep s)
advances to the next line and indents
to the current nesting level. Document (linesep s)
behaves like (text s)
if the line break is undone by group
.
:: String
|
a string |
-> Doc
|
a document which advances to the next line or behaves like (text s)
|
The document hardline
advances to the next line and indents
to the current nesting level. hardline
cannot be undone by group
.
:: Doc
|
a document which advances to the next line |
The document line
advances to the next line and indents to the current
nesting level. Document line
behaves like (text " ")
if the line break
is undone by group
.
:: Doc
|
a document which advances to the next line or behaves like (text " ")
|
The document linebreak
advances to the next line and indents to
the current nesting level. Document linebreak
behaves like (text "")
if the line break is undone by group
.
:: Doc
|
a document which advances to the next line or behaves like (text "")
|
The document softline
behaves like space
if the resulting output
fits the page, otherwise it behaves like line
.
softline = group line
:: Doc
|
a document which behaves like space
or line
|
The document softbreak
behaves like (text "")
if the resulting output
fits the page, otherwise it behaves like line
.
softbreak = group linebreak
:: Doc
|
a document which behaves like (text "")
or line
|
The combinator group
is used to specify alternative layouts.
The document (group x)
undoes all line breaks in document x
.
The resulting line is added to the current line if that fits the page.
Otherwise, the document x
is rendered without any changes.
:: Doc
|
a document |
-> Doc
|
document d without line breaks if that fits the page. |
The document (nest i d)
renders document d
with the current
indentation level increased by i
(See also hang
,
align
and indent
).
nest 2 (text "hello" $$ text "world") $$ text "!"
outputs as:
hello world !
:: Int
|
an integer which increases the indentation level |
-> Doc
|
a document |
-> Doc
|
document d with an indentation level increased by i |
The combinator hang
implements hanging indentation.
The document (hang i d)
renders document d
with a nesting level set
to the current column plus i
. The following example uses hanging
indentation for some text:
test = hang 4 (fillSep (map text (words "the hang combinator indents these words !")))
Which lays out on a page with a width of 20 characters as:
the hang combinator indents these words !
The hang combinator is implemented as:
hang i x = align (nest i x)
:: Int
|
an integer which increases the indentation level |
-> Doc
|
a document |
-> Doc
|
document d with an indentation level set to the current column plus i |
The document (align d)
renders document d with the nesting level
set to the current column. It is used for example to implement
hang`.
As an example, we will put a document right above another one, regardless of the current nesting level:
x $$ y = align (x $$ y) test = text "hi" <+> (text "nice" $$ text "world")
which will be layed out as:
hi nice world
:: Doc
|
a document |
-> Doc
|
document d with the nesting level set to the current column |
The document (indent i d)
indents document d
with i
spaces.
test = indent 4 (fillSep (map text (words "the indent combinator indents these words !")))
Which lays out with a page width of 20 as:
the indent combinator indents these words !
:: Int
|
an integer which increases the indentation level |
-> Doc
|
a document |
-> Doc
|
document d with an indentation level set to the current column plus i |
combine
:: Doc -> Doc -> Doc -> Doc
The document (combine c d1 d2)
combines document d1
and d2
with
document c
in between using (<>)
with identity empty
.
Thus, the following equations hold.
combine c d1 empty == d1 combine c empty d2 == d2 combine c d1 d2 == d1 <> c <> d2 if neither d1 nor d2 are empty
:: Doc
|
the middle document |
-> Doc
|
the left document |
-> Doc
|
the right document |
-> Doc
|
concatenation of d1 and d2 with c in between unless one of the documents is empty |
The document (x <> y)
concatenates document x
and document y
.
It is an associative operation having empty
as a left and right unit.
:: Doc
|
the first document |
-> Doc
|
the second document |
-> Doc
|
concatenation of x and y without seperator with identity empty |
The document (x <+> y)
concatenates document x
and y
with a
space
in between with identity empty
.
:: Doc
|
the first document |
-> Doc
|
the second document |
-> Doc
|
concatenation of x and y with a space in between |
The document (x $$ y)
concatenates document x and y with a
line
in between with identity empty
.
:: Doc
|
the first document |
-> Doc
|
the second document |
-> Doc
|
concatenation of x and y with a line in between |
The document (x <$+$> y)
concatenates document x
and y
with a
blank line in between with identity empty
.
:: Doc
|
the first document |
-> Doc
|
the second document |
-> Doc
|
concatenation of x and y with a blank line in between |
The document (x </> y)
concatenates document x
and y
with
a softline
in between with identity empty
.
This effectively puts x
and y
either next to each other
(with a space
in between) or underneath each other.
:: Doc
|
the first document |
-> Doc
|
the second document |
-> Doc
|
concatenation of x and y with a softline in between |
The document (x <$$> y)
concatenates document x
and y
with a
linebreak
in between with identity empty
.
:: Doc
|
the first document |
-> Doc
|
the second document |
-> Doc
|
concatenation of x and y with a linebreak in between |
The document (x <//> y)
concatenates document x
and y
with a
softbreak
in between with identity empty
.
This effectively puts x
and y
either right next to each other
or underneath each other.
:: Doc
|
the first document |
-> Doc
|
the second document |
-> Doc
|
concatenation of x and y with a softbreak in between |
The document (x <$!$> y)
concatenates document x
and y
with a
hardline
in between with identity empty
.
This effectively puts x
and y
underneath each other.
:: Doc
|
the first document |
-> Doc
|
the second document |
-> Doc
|
concatenation of x and y with a hardline in between |
compose
:: (Doc -> Doc -> Doc) -> [Doc] -> Doc
The document (compose f xs)
concatenates all documents xs
with function f
.
Function f
should be like (<+>)
, ($$)
and so on.
:: Doc -> Doc -> Doc
|
a combiner function |
-> [Doc]
|
a list of documents |
-> Doc
|
concatenation of documents |
The document (hsep xs)
concatenates all documents xs
horizontally with (<+>)
.
:: [Doc]
|
a list of documents |
-> Doc
|
horizontal concatenation of documents |
The document (vsep xs)
concatenates all documents xs
vertically with
($$)
. If a group undoes the line breaks inserted by vsep
,
all documents are separated with a space
.
someText = map text (words ("text to lay out")) test = text "some" <+> vsep someText
This is layed out as:
some text to lay out
The align
combinator can be used to align the documents
under their first element:
test = text "some" <+> align (vsep someText)
This is printed as:
some text to lay out
:: [Doc]
|
a list of documents |
-> Doc
|
vertical concatenation of documents |
The document vsep xs
concatenates all documents xs
vertically with
(<$+$>)
. If a group undoes the line breaks inserted by vsepBlank
,
all documents are separated with a space
.
:: [Doc]
|
a list of documents |
-> Doc
|
vertical concatenation of documents |
The document (fillSep xs)
concatenates documents xs
horizontally with
(</>)
as long as its fits the page, than inserts a
line
and continues doing that for all documents in xs
.
fillSep xs = foldr (</>) empty xs
:: [Doc]
|
a list of documents |
-> Doc
|
horizontal concatenation of documents |
The document (sep xs)
concatenates all documents xs
either horizontally
with (<+>)
, if it fits the page, or vertically
with ($$)
.
sep xs = group (vsep xs)
or vertical concatenation else
:: [Doc]
|
a list of documents |
-> Doc
|
horizontal concatenation of documents, if it fits the page, |
The document (hcat xs)
concatenates all documents xs
horizontally
with (<>)
.
:: [Doc]
|
a list of documents |
-> Doc
|
horizontal concatenation of documents |
The document (vcat xs)
concatenates all documents xs
vertically
with (<$$>)
. If a group
undoes the line breaks inserted by vcat
,
all documents are directly concatenated.
:: [Doc]
|
a list of documents |
-> Doc
|
vertical concatenation of documents |
The document (fillCat xs)
concatenates documents xs
horizontally
with (<//>)
as long as its fits the page, than inserts a linebreak
and continues doing that for all documents in xs
.
fillCat xs = foldr (<//>) empty xs
:: [Doc]
|
a list of documents |
-> Doc
|
horizontal concatenation of documents |
The document (cat xs)
concatenates all documents xs
either horizontally
with (<>)
, if it fits the page, or vertically with
(<$$>)
.
cat xs = group (vcat xs)
:: [Doc]
|
a list of documents |
-> Doc
|
horizontal concatenation of documents |
punctuate
:: Doc -> [Doc] -> [Doc]
(punctuate p xs)
concatenates all documents xs
with document p
except
for the last document.
someText = map text ["words","in","a","tuple"] test = parens (align (cat (punctuate comma someText)))
This is layed out on a page width of 20 as:
(words,in,a,tuple)
But when the page width is 15, it is layed out as:
(words, in, a, tuple)
(If you want put the commas in front of their elements instead of at the
end, you should use tupled
or, in general, encloseSep
.)
:: Doc
|
a document as seperator |
-> [Doc]
|
a list of documents |
-> [Doc]
|
concatenation of documents with p in between |
encloseSep
:: Doc -> Doc -> Doc -> [Doc] -> Doc
The document (encloseSep l r s xs)
concatenates the documents xs
seperated by s
and encloses the resulting document by l
and r
.
The documents are rendered horizontally if that fits the page. Otherwise
they are aligned vertically. All seperators are put in front of the
elements.
For example, the combinator list
can be defined with encloseSep
:
list xs = encloseSep lbracket rbracket comma xs test = text "list" <+> (list (map int [10,200,3000]))
Which is layed out with a page width of 20 as:
list [10,200,3000]
But when the page width is 15, it is layed out as:
list [10 ,200 ,3000]
:: Doc
|
left document |
-> Doc
|
right document |
-> Doc
|
a document as seperator |
-> [Doc]
|
a list of documents |
-> Doc
|
concatenation of l, xs (with s in between) and r |
encloseSepSpaced
:: Doc -> Doc -> Doc -> [Doc] -> Doc
The document (encloseSepSpaced l r s xs)
concatenates the documents xs
seperated by s
and encloses the resulting document by l
and r
.
In addition, after each occurrence of s
, after l
, and before r
,
a space
is inserted.
The documents are rendered horizontally if that fits the page. Otherwise
they are aligned vertically. All seperators are put in front of the
elements.
:: Doc
|
left document |
-> Doc
|
right document |
-> Doc
|
a document as seperator |
-> [Doc]
|
a list of documents |
-> Doc
|
concatenation of l, xs (with s in between) and r |
hEncloseSep
:: Doc -> Doc -> Doc -> [Doc] -> Doc
The document (hEncloseSep l r s xs)
concatenates the documents xs
seperated by s
and encloses the resulting document by l
and r
.
The documents are rendered horizontally.
:: Doc
|
left document |
-> Doc
|
right document |
-> Doc
|
a document as seperator |
-> [Doc]
|
a list of documents |
-> Doc
|
concatenation of l, xs (with s in between) and r |
fillEncloseSep
:: Doc -> Doc -> Doc -> [Doc] -> Doc
The document (fillEncloseSep l r s xs)
concatenates the documents xs
seperated by s
and encloses the resulting document by l
and r
.
The documents are rendered horizontally if that fits the page. Otherwise they are aligned vertically. All seperators are put in front of the elements.
:: Doc
|
left document |
-> Doc
|
right document |
-> Doc
|
a document as seperator |
-> [Doc]
|
a list of documents |
-> Doc
|
concatenation of l, xs (with s in between) and r |
fillEncloseSepSpaced
:: Doc -> Doc -> Doc -> [Doc] -> Doc
The document (fillEncloseSepSpaced l r s xs)
concatenates the documents
xs
seperated by s
and encloses the resulting document by l
and r
.
In addition, after each occurrence of s
, after l
, and before r
,
a space
is inserted.
The documents are rendered horizontally if that fits the page. Otherwise, they are aligned vertically. All seperators are put in front of the elements.
:: Doc
|
left document |
-> Doc
|
right document |
-> Doc
|
a document as seperator |
-> [Doc]
|
a list of documents |
-> Doc
|
concatenation of l, xs (with s in between) and r |
The document (list xs)
comma seperates the documents xs
and encloses
them in square brackets. The documents are rendered horizontally if
that fits the page. Otherwise they are aligned vertically.
All comma seperators are put in front of the elements.
:: [Doc]
|
a list of documents |
-> Doc
|
comma seperated documents xs and enclosed in square brackets |
listSpaced
:: [Doc] -> Doc
Spaced version of list
The document (set xs)
comma seperates the documents xs
and encloses
them in braces. The documents are rendered horizontally if
that fits the page. Otherwise they are aligned vertically.
All comma seperators are put in front of the elements.
:: [Doc]
|
a list of documents |
-> Doc
|
comma seperated documents xs and enclosed in braces |
Spaced version of set
The document (tupled xs)
comma seperates the documents xs
and encloses
them in parenthesis. The documents are rendered horizontally if that fits
the page. Otherwise they are aligned vertically.
All comma seperators are put in front of the elements.
:: [Doc]
|
a list of documents |
-> Doc
|
comma seperated documents xs and enclosed in parenthesis |
tupledSpaced
:: [Doc] -> Doc
Spaced version of tupled
semiBraces
:: [Doc] -> Doc
The document (semiBraces xs)
seperates the documents xs
with semi colons
and encloses them in braces. The documents are rendered horizontally
if that fits the page. Otherwise they are aligned vertically.
All semi colons are put in front of the elements.
:: [Doc]
|
a list of documents |
-> Doc
|
documents xs seperated with semi colons and enclosed in braces |
semiBracesSpaced
:: [Doc] -> Doc
Spaced version of semiBraces
enclose
:: Doc -> Doc -> Doc -> Doc
The document (enclose l r x)
encloses document x
between
documents l
and r
using (<>)
.
enclose l r x = l <> x <> r
:: Doc
|
the left document |
-> Doc
|
the right document |
-> Doc
|
the middle document |
-> Doc
|
concatenation of l, x and r |
Document (squotes x)
encloses document x
with single quotes "'"
.
:: Doc
|
a document |
-> Doc
|
document x enclosed by single quotes |
Document (dquotes x)
encloses document x
with double quotes.
:: Doc
|
a document |
-> Doc
|
document x enclosed by double quotes |
Document (bquotes x)
encloses document x
with back quotes "\`"
.
:: Doc
|
a document |
-> Doc
|
document x enclosed by \`
quotes
|
Document (parens x)
encloses document x
in parenthesis,
"("
and ")"
.
:: Doc
|
a document |
-> Doc
|
document x enclosed in parenthesis |
parensIf
:: Bool -> Doc -> Doc
Document (parensIf x)
encloses document x
in parenthesis,"("
and ")"
,
iff the condition is true.
:: Bool
|
a document |
-> Doc
|
|
-> Doc
|
document x enclosed in parenthesis iff the condition is true |
Document (angles x)
encloses document x
in angles, "<"
and ">"
.
:: Doc
|
a document |
-> Doc
|
document x enclosed in angles |
Document (braces x)
encloses document x
in braces, "{"
and "}"
.
:: Doc
|
a document |
-> Doc
|
document x enclosed in braces |
Document (brackets x)
encloses document x
in square brackets,
"["
and "]"
.
:: Doc
|
a document |
-> Doc
|
document x enclosed in square brackets |
The document (bool b)
shows the boolean b
using text
.
:: Bool
|
a boolean |
-> Doc
|
a document which contains the boolean b |
The document (char c)
contains the literal character c
.
The character should not be a newline (\n
),
the function line
should be used for line breaks.
:: Char
|
a character (not \n )
|
-> Doc
|
a document which contains the literal character c |
The document (string s)
concatenates all characters in s
using
line
for newline characters and char
for all other characters.
It is used instead of text
whenever the text contains newline characters.
:: String
|
a string |
-> Doc
|
a document which contains the string s |
The document (int i)
shows the literal integer i
using text
.
:: Int
|
an integer |
-> Doc
|
a document which contains the integer i |
The document (float f)
shows the literal float f
using text
.
:: Float
|
a float |
-> Doc
|
a document which contains the float f |
The document lparen
contains a left parenthesis, "("
.
:: Doc
|
a document which contains a left parenthesis |
The document rparen
contains a right parenthesis, ")"
.
:: Doc
|
a document which contains a right parenthesis |
The document langle
contains a left angle, "<"
.
:: Doc
|
a document which contains a left angle |
The document rangle
contains a right angle, ">"
.
:: Doc
|
a document which contains a right angle |
The document lbrace
contains a left brace, "{"
.
:: Doc
|
a document which contains a left brace |
The document rbrace
contains a right brace, "}"
.
:: Doc
|
a document which contains a right brace |
The document lbracket
contains a left square bracket, "["
.
:: Doc
|
a document which contains a left square bracket |
The document rbracket
contains a right square bracket, "]"
.
:: Doc
|
a document which contains a right square bracket |
The document squote
contains a single quote, "'"
.
:: Doc
|
a document which contains a single quote |
The document dquote
contains a double quote.
:: Doc
|
a document which contains a double quote |
The document semi
contains a semi colon, ";"
.
:: Doc
|
a document which contains a semi colon |
The document colon
contains a colon, ":"
.
:: Doc
|
a document which contains a colon |
The document comma
contains a comma, ","
.
:: Doc
|
a document which contains a comma |
The document space
contains a single space, " "
.
x <+> y = x <> space <> y
:: Doc
|
a document which contains a single space |
The document dot
contains a single dot, "."
.
:: Doc
|
a document which contains a single dot |
The document backslash
contains a back slash, "\\"
.
:: Doc
|
a document which contains a back slash |
The document equals
contains an equal sign, "="
.
:: Doc
|
a document which contains an equal |
The document larrow
contains a left arrow sign, "<-"
.
:: Doc
|
a document which contains a left arrow sign |
The document rarrow
contains a right arrow sign, "->"
.
:: Doc
|
a document which contains a right arrow sign |
doubleArrow
:: Doc
The document doubleArrow
contains an double arrow sign, "=>"
.
:: Doc
|
a document which contains an double arrow sign |
doubleColon
:: Doc
The document doubleColon
contains a double colon sign, "::"
.
:: Doc
|
a document which contains a double colon sign |
The document bar
contains a vertical bar sign, "|"
.
:: Doc
|
a document which contains a vertical bar sign |
The document at
contains an at sign, "@"
.
:: Doc
|
a document which contains an at sign |
The document tilde
contains a tilde sign, "~"
.
:: Doc
|
a document which contains a tilde sign |
The document (fill i d)
renders document d
. It than appends
space
s until the width is equal to i
. If the width of d
is
already larger, nothing is appended. This combinator is quite
useful in practice to output a list of bindings. The following
example demonstrates this.
types = [("empty","Doc") ,("nest","Int -> Doc -> Doc") ,("linebreak","Doc")]
ptype (name,tp) = fill 6 (text name) <+> text "::" <+> text tp
test = text "let" <+> align (vcat (map ptype types))
Which is layed out as:
let empty :: Doc nest :: Int -> Doc -> Doc linebreak :: Doc
Note that fill
is not guaranteed to be linear-time bounded since it has to
compute the width of a document before pretty printing it
fillBreak
:: Int -> Doc -> Doc
The document (fillBreak i d)
first renders document d
. It
than appends space
s until the width is equal to i
. If the
width of d
is already larger than i
, the nesting level is
increased by i
and a line
is appended. When we redefine ptype
in the previous example to use fillBreak
, we get a useful
variation of the previous output:
ptype (name,tp) = fillBreak 6 (text name) <+> text "::" <+> text tp
The output will now be:
let empty :: Doc nest :: Int -> Doc -> Doc linebreak :: Doc
Note that fillBreak
is not guaranteed to be linear-time bounded since it
has to compute the width of a document before pretty printing it
The document (bold d)
displays document d
with bold text
:: Doc
|
a document |
-> Doc
|
document d displayed with bold text |
The document (faint d)
displays document d
with faint text
:: Doc
|
a document |
-> Doc
|
document d displayed with faint text |
The document (blinkSlow d)
displays document d
with slowly blinking text
(rarely supported)
:: Doc
|
a document |
-> Doc
|
document d displayed with slowly blinking text |
blinkRapid
:: Doc -> Doc
The document (blinkRapid d)
displays document d
with rapidly blinking
text (rarely supported)
:: Doc
|
a document |
-> Doc
|
document d displayed with rapidly blinking text |
The document (italic d)
displays document d
with italicized text
(rarely supported)
:: Doc
|
a document |
-> Doc
|
document d displayed with italicized text |
The document (underline d)
displays document d
with underlined text
:: Doc
|
a document |
-> Doc
|
document d displayed with underlined text |
The document (crossout d)
displays document d
with crossed out text
:: Doc
|
a document |
-> Doc
|
document d displayed with crossed out text |
The document (inverse d)
displays document d
with inversed coloring,
i.e. use text color of d
as background color and background color of d
as text color
:: Doc
|
a document |
-> Doc
|
document d displayed with inversed coloring |
The document (black d)
displays document d
with black text color
:: Doc
|
a document |
-> Doc
|
document d displayed with black text color |
The document (red d)
displays document d
with red text color
:: Doc
|
a document |
-> Doc
|
document d displayed with red text color |
The document (green d)
displays document d
with green text color
:: Doc
|
a document |
-> Doc
|
document d displayed with green text color |
The document (yellow d)
displays document d
with yellow text color
:: Doc
|
a document |
-> Doc
|
document d displayed with yellow text color |
The document (blue d)
displays document d
with blue text color
:: Doc
|
a document |
-> Doc
|
document d displayed with blue text color |
The document (magenta d)
displays document d
with magenta text color
:: Doc
|
a document |
-> Doc
|
document d displayed with magenta text color |
The document (cyan d)
displays document d
with cyan text color
:: Doc
|
a document |
-> Doc
|
document d displayed with cyan text color |
The document (white d)
displays document d
with white text color
:: Doc
|
a document |
-> Doc
|
document d displayed with white text color |
The document (bgBlack d)
displays document d
with black background color
:: Doc
|
a document |
-> Doc
|
document d displayed with black background color |
The document (bgRed d)
displays document d
with red background color
:: Doc
|
a document |
-> Doc
|
document d displayed with red background color |
The document (bgGreen d)
displays document d
with green background color
:: Doc
|
a document |
-> Doc
|
document d displayed with green background color |
The document (bgYellow d)
displays document d
with yellow background
color
:: Doc
|
a document |
-> Doc
|
document d displayed with yellow background color |
The document (bgBlue d)
displays document d
with blue background color
:: Doc
|
a document |
-> Doc
|
document d displayed with blue background color |
The document (bgMagenta d)
displays document d
with magenta background
color
:: Doc
|
a document |
-> Doc
|
document d displayed with magenta background color |
The document (bgCyan d)
displays document d
with cyan background color
:: Doc
|
a document |
-> Doc
|
document d displayed with cyan background color |
The document (bgWhite d)
displays document d
with white background color
:: Doc
|
a document |
-> Doc
|
document d displayed with white background color |
class Pretty
a
Methods:
|