| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Text.PrettyPrint.Annotated.Leijen
Description
Deprecated: Compatibility module for users of annotated-wl-pprint - use Prettyprinter instead
Synopsis
- data Doc ann
- type SimpleDoc = SimpleDocStream
- type SpanList a = [(Int, Int, a)]
- putDoc :: Doc () -> IO ()
- hPutDoc :: Handle -> Doc () -> IO ()
- empty :: Doc ann
- char :: Char -> Doc ann
- text :: String -> Doc ann
- (<>) :: Semigroup a => a -> a -> a
- nest :: Int -> Doc ann -> Doc ann
- line :: Doc ann
- linebreak :: Doc ann
- group :: Doc ann -> Doc ann
- softline :: Doc ann
- softbreak :: Doc ann
- align :: Doc ann -> Doc ann
- hang :: Int -> Doc ann -> Doc ann
- indent :: Int -> Doc ann -> Doc ann
- encloseSep :: Doc ann -> Doc ann -> Doc ann -> [Doc ann] -> Doc ann
- list :: [Doc ann] -> Doc ann
- tupled :: [Doc ann] -> Doc ann
- semiBraces :: [Doc ann] -> Doc ann
- (<+>) :: Doc ann -> Doc ann -> Doc ann
- (<$>) :: Doc ann -> Doc ann -> Doc ann
- (</>) :: Doc ann -> Doc ann -> Doc ann
- (<$$>) :: Doc ann -> Doc ann -> Doc ann
- (<//>) :: Doc ann -> Doc ann -> Doc ann
- hsep :: [Doc ann] -> Doc ann
- vsep :: [Doc ann] -> Doc ann
- fillSep :: [Doc ann] -> Doc ann
- sep :: [Doc ann] -> Doc ann
- hcat :: [Doc ann] -> Doc ann
- vcat :: [Doc ann] -> Doc ann
- fillCat :: [Doc ann] -> Doc ann
- cat :: [Doc ann] -> Doc ann
- punctuate :: Doc ann -> [Doc ann] -> [Doc ann]
- fill :: Int -> Doc ann -> Doc ann
- fillBreak :: Int -> Doc ann -> Doc ann
- enclose :: Doc ann -> Doc ann -> Doc ann -> Doc ann
- squotes :: Doc ann -> Doc ann
- dquotes :: Doc ann -> Doc ann
- parens :: Doc ann -> Doc ann
- angles :: Doc ann -> Doc ann
- braces :: Doc ann -> Doc ann
- brackets :: Doc ann -> Doc ann
- lparen :: Doc ann
- rparen :: Doc ann
- langle :: Doc ann
- rangle :: Doc ann
- lbrace :: Doc ann
- rbrace :: Doc ann
- lbracket :: Doc ann
- rbracket :: Doc ann
- squote :: Doc ann
- dquote :: Doc ann
- semi :: Doc ann
- colon :: Doc ann
- comma :: Doc ann
- space :: Doc ann
- dot :: Doc ann
- backslash :: Doc ann
- equals :: Doc ann
- pipe :: Doc ann
- string :: String -> Doc ann
- int :: Int -> Doc ann
- integer :: Integer -> Doc ann
- float :: Float -> Doc ann
- double :: Double -> Doc ann
- rational :: Rational -> Doc ann
- bool :: Bool -> Doc ann
- annotate :: ann -> Doc ann -> Doc ann
- noAnnotate :: Doc ann -> Doc xxx
- renderPretty :: Float -> Int -> Doc ann -> SimpleDoc ann
- renderCompact :: Doc ann -> SimpleDoc ann
- displayDecorated :: (a -> String -> String) -> SimpleDoc a -> String
- displayDecoratedA :: (Applicative f, Monoid b) => (String -> f b) -> (a -> f b) -> (a -> f b) -> SimpleDoc a -> f b
- display :: SimpleDoc ann -> String
- displayS :: SimpleDoc ann -> ShowS
- displayIO :: Handle -> SimpleDoc a -> IO ()
- displaySpans :: SimpleDoc a -> (String, SpanList a)
- column :: (Int -> Doc ann) -> Doc ann
- nesting :: (Int -> Doc ann) -> Doc ann
- width :: Doc ann -> (Int -> Doc ann) -> Doc ann
Documentation
The abstract data type represents pretty documents that have
been annotated with data of type Doc annann.
More specifically, a value of type represents a non-empty set of
possible layouts of a document. The layout functions select one of these
possibilities, taking into account things like the width of the output
document.Doc
The annotation is an arbitrary piece of data associated with (part of) a document. Annotations may be used by the rendering backends in order to display output differently, such as
- color information (e.g. when rendering to the terminal)
- mouseover text (e.g. when rendering to rich HTML)
- whether to show something or not (to allow simple or detailed versions)
The simplest way to display a Doc is via the Show class.
>>>putStrLn (show (vsep ["hello", "world"]))hello world
Instances
type SimpleDoc = SimpleDocStream Source #
(<>) :: Semigroup a => a -> a -> a infixr 6 #
An associative operation.
>>>[1,2,3] <> [4,5,6][1,2,3,4,5,6]
( lays out the document nest i x)x with the current nesting level
(indentation of the following lines) increased by i. Negative values are
allowed, and decrease the nesting level accordingly.
>>>vsep [nest 4 (vsep ["lorem", "ipsum", "dolor"]), "sit", "amet"]lorem ipsum dolor sit amet
See also
( tries laying out group x)x into a single line by removing the
contained line breaks; if this does not fit the page, or when a hardline
within x prevents it from being flattened, x is laid out without any
changes.
The group function is key to layouts that adapt to available space nicely.
See vcat, line, or flatAlt for examples that are related, or make good
use of it.
softline behaves like if the resulting output fits the page,
otherwise like space.line
Here, we have enough space to put everything in one line:
>>>let doc = "lorem ipsum" <> softline <> "dolor sit amet">>>putDocW 80 doclorem ipsum dolor sit amet
If we narrow the page to width 10, the layouter produces a line break:
>>>putDocW 10 doclorem ipsum dolor sit amet
softline=groupline
( lays out the document align x)x 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. Without alignment, the second line is put simply
below everything we've had so far,
>>>"lorem" <+> vsep ["ipsum", "dolor"]lorem ipsum dolor
If we add an align to the mix, the 's contents all start in the
same column,vsep
>>>"lorem" <+> align (vsep ["ipsum", "dolor"])lorem ipsum dolor
Arguments
| :: Int | Change of nesting level, relative to the start of the first line |
| -> Doc ann | |
| -> Doc ann |
( lays out the document hang i x)x with a nesting level set to the
current column plus i. Negative values are allowed, and decrease the
nesting level accordingly.
>>>let doc = reflow "Indenting these words with hang">>>putDocW 24 ("prefix" <+> hang 4 doc)prefix Indenting these words with hang
This differs from nest, which is based on the current nesting level plus
i. When you're not sure, try the more efficient nest first. In our
example, this would yield
>>>let doc = reflow "Indenting these words with nest">>>putDocW 24 ("prefix" <+> nest 4 doc)prefix Indenting these words with nest
hangi doc =align(nesti doc)
Arguments
| :: Doc ann | left delimiter |
| -> Doc ann | right delimiter |
| -> Doc ann | separator |
| -> [Doc ann] | input documents |
| -> Doc ann |
( concatenates the documents encloseSep l r sep xs)xs separated by
sep, and encloses the resulting document by l and r.
The documents are laid out horizontally if that fits the page,
>>>let doc = "list" <+> align (encloseSep lbracket rbracket comma (map pretty [1,20,300,4000]))>>>putDocW 80 doclist [1,20,300,4000]
If there is not enough space, then the input is split into lines entry-wise therwise they are laid out vertically, with separators put in the front:
>>>putDocW 10 doclist [1 ,20 ,300 ,4000]
Note that doc contains an explicit call to align so that the list items
are aligned vertically.
For putting separators at the end of entries instead, have a look at
punctuate.
list :: [Doc ann] -> Doc ann #
Haskell-inspired variant of encloseSep with braces and comma as
separator.
>>>let doc = list (map pretty [1,20,300,4000])
>>>putDocW 80 doc[1, 20, 300, 4000]
>>>putDocW 10 doc[ 1 , 20 , 300 , 4000 ]
tupled :: [Doc ann] -> Doc ann #
Haskell-inspired variant of encloseSep with parentheses and comma as
separator.
>>>let doc = tupled (map pretty [1,20,300,4000])
>>>putDocW 80 doc(1, 20, 300, 4000)
>>>putDocW 10 doc( 1 , 20 , 300 , 4000 )
semiBraces :: [Doc ann] -> Doc ann Source #
hsep :: [Doc ann] -> Doc ann #
( concatenates all documents hsep xs)xs horizontally with ,
i.e. it puts a space between all entries.<+>
>>>let docs = Util.words "lorem ipsum dolor sit amet"
>>>hsep docslorem ipsum dolor sit amet
does not introduce line breaks on its own, even when the page is too
narrow:hsep
>>>putDocW 5 (hsep docs)lorem ipsum dolor sit amet
For automatic line breaks, consider using fillSep instead.
vsep :: [Doc ann] -> Doc ann #
( concatenates all documents vsep xs)xs above each other. If a
group undoes the line breaks inserted by vsep, the documents are
separated with a space instead.
Using vsep alone yields
>>>"prefix" <+> vsep ["text", "to", "lay", "out"]prefix text to lay out
grouping a vsep separates the documents with a space if it fits the
page (and does nothing otherwise). See the convenience function for
this use case.sep
The align function can be used to align the documents under their first
element:
>>>"prefix" <+> align (vsep ["text", "to", "lay", "out"])prefix text to lay out
Since grouping a vsep is rather common, sep is a built-in for doing
that.
fillSep :: [Doc ann] -> Doc ann #
( concatenates the documents fillSep xs)xs horizontally with
as long as it fits the page, then inserts a <+> and continues doing that
for all documents in linexs. ( means that if linegrouped, the documents
are separated with a space instead of newlines. Use fillCat if you do not
want a space.)
Let's print some words to fill the line:
>>>let docs = take 20 (cycle ["lorem", "ipsum", "dolor", "sit", "amet"])>>>putDocW 80 ("Docs:" <+> fillSep docs)Docs: lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet
The same document, printed at a width of only 40, yields
>>>putDocW 40 ("Docs:" <+> fillSep docs)Docs: lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet
( tries laying out the documents sep xs)xs separated with spaces,
and if this does not fit the page, separates them with newlines. This is what
differentiates it from vsep, which always lays out its contents beneath
each other.
>>>let doc = "prefix" <+> sep ["text", "to", "lay", "out"]>>>putDocW 80 docprefix text to lay out
With a narrower layout, the entries are separated by newlines:
>>>putDocW 20 docprefix text to lay out
sep=group.vsep
vcat :: [Doc ann] -> Doc ann #
( vertically concatenates the documents vcat xs)xs. If it is
grouped, the line breaks are removed.
In other words is like vcat, with newlines removed instead of
replaced by vsepspaces.
>>>let docs = Util.words "lorem ipsum dolor">>>vcat docslorem ipsum dolor>>>group (vcat docs)loremipsumdolor
Since grouping a vcat is rather common, cat is a built-in shortcut for
it.
fillCat :: [Doc ann] -> Doc ann #
( concatenates documents fillCat xs)xs horizontally with as
long as it fits the page, then inserts a <> and continues doing that
for all documents in line'xs. This is similar to how an ordinary word processor
lays out the text if you just keep typing after you hit the maximum line
length.
( means that if line'grouped, the documents are separated with nothing
instead of newlines. See fillSep if you want a space instead.)
Observe the difference between fillSep and fillCat. fillSep
concatenates the entries spaced when grouped,
>>>let docs = take 20 (cycle (["lorem", "ipsum", "dolor", "sit", "amet"]))>>>putDocW 40 ("Grouped:" <+> group (fillSep docs))Grouped: lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet
On the other hand, fillCat concatenates the entries directly when
grouped,
>>>putDocW 40 ("Grouped:" <+> group (fillCat docs))Grouped: loremipsumdolorsitametlorem ipsumdolorsitametloremipsumdolorsitamet loremipsumdolorsitamet
( tries laying out the documents cat xs)xs separated with nothing,
and if this does not fit the page, separates them with newlines. This is what
differentiates it from vcat, which always lays out its contents beneath
each other.
>>>let docs = Util.words "lorem ipsum dolor">>>putDocW 80 ("Docs:" <+> cat docs)Docs: loremipsumdolor
When there is enough space, the documents are put above one another,
>>>putDocW 10 ("Docs:" <+> cat docs)Docs: lorem ipsum dolor
cat=group.vcat
( appends punctuate p xs)p to all but the last document in xs.
>>>let docs = punctuate comma (Util.words "lorem ipsum dolor sit amet")>>>putDocW 80 (hsep docs)lorem, ipsum, dolor, sit, amet
The separators are put at the end of the entries, which we can see if we position the result vertically:
>>>putDocW 20 (vsep docs)lorem, ipsum, dolor, sit, amet
If you want put the commas in front of their elements instead of at the end,
you should use tupled or, in general, encloseSep.
( lays out the document fill i x)x. It then appends spaces until
the width is equal to i. If the width of x is already larger, nothing is
appended.
This function is quite useful in practice to output a list of bindings:
>>>let types = [("empty","Doc"), ("nest","Int -> Doc -> Doc"), ("fillSep","[Doc] -> Doc")]>>>let ptype (name, tp) = fill 5 (pretty name) <+> "::" <+> pretty tp>>>"let" <+> align (vcat (map ptype types))let empty :: Doc nest :: Int -> Doc -> Doc fillSep :: [Doc] -> Doc
( first lays out the document fillBreak i x)x. It then appends spaces
until the width is equal to i. If the width of x is already larger than
i, the nesting level is increased by i and a line is appended. When we
redefine ptype in the example given in fill to use , we get
a useful variation of the output:fillBreak
>>>let types = [("empty","Doc"), ("nest","Int -> Doc -> Doc"), ("fillSep","[Doc] -> Doc")]>>>let ptype (name, tp) = fillBreak 5 (pretty name) <+> "::" <+> pretty tp>>>"let" <+> align (vcat (map ptype types))let empty :: Doc nest :: Int -> Doc -> Doc fillSep :: [Doc] -> Doc
annotate :: ann -> Doc ann -> Doc ann #
Add an annotation to a . This annotation can then be used by the
renderer to e.g. add color to certain parts of the output. For a full
tutorial example on how to use it, see the
Prettyprinter.Render.Tutorials.StackMachineTutorial or
Prettyprinter.Render.Tutorials.TreeRenderingTutorial modules.Doc
This function is only relevant for custom formats with their own annotations, and not relevant for basic prettyprinting. The predefined renderers, e.g. Prettyprinter.Render.Text, should be enough for the most common needs.
noAnnotate :: Doc ann -> Doc xxx Source #
renderCompact :: Doc ann -> SimpleDoc ann Source #
displayDecoratedA :: (Applicative f, Monoid b) => (String -> f b) -> (a -> f b) -> (a -> f b) -> SimpleDoc a -> f b Source #
column :: (Int -> Doc ann) -> Doc ann #
Layout a document depending on which column it starts at. align is
implemented in terms of column.
>>>column (\l -> "Columns are" <+> pretty l <> "-based.")Columns are 0-based.
>>>let doc = "prefix" <+> column (\l -> "| <- column" <+> pretty l)>>>vsep [indent n doc | n <- [0,4,8]]prefix | <- column 7 prefix | <- column 11 prefix | <- column 15
width :: Doc ann -> (Int -> Doc ann) -> Doc ann #
( lays out the document width doc f)doc, and makes the column width
of it available to a function.
>>>let annotate doc = width (brackets doc) (\w -> " <- width:" <+> pretty w)>>>align (vsep (map annotate ["---", "------", indent 3 "---", vsep ["---", indent 4 "---"]]))[---] <- width: 5 [------] <- width: 8 [ ---] <- width: 8 [--- ---] <- width: 8