Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
This module shows how to write a custom prettyprinter backend, based on a
tree representation of a SimpleDocStream
. For a stack machine approach, which
may be more suitable for certain output formats, see
Prettyprinter.Render.Tutorials.StackMachineTutorial.
Rendering to HTML, particularly using libraries such as blaze-html or lucid, is one important use case of tree-based rendering.
The module is written to be readable top-to-bottom in both Haddock and raw source form.
Synopsis
- data SimpleHtml
- data Color
- bold :: Doc SimpleHtml -> Doc SimpleHtml
- italics :: Doc SimpleHtml -> Doc SimpleHtml
- paragraph :: Doc SimpleHtml -> Doc SimpleHtml
- headline :: Doc SimpleHtml -> Doc SimpleHtml
- color :: Color -> Doc SimpleHtml -> Doc SimpleHtml
- render :: SimpleDocStream SimpleHtml -> Text
- renderTree :: SimpleDocTree SimpleHtml -> Builder
- encloseInTagFor :: SimpleHtml -> Builder -> Builder
The type of available markup
First, we define a set of valid annotations must be defined, with the goal of
defining a
. We will later define how to convert this to
the output format (Doc
SimpleHtml
Text
).
Convenience definitions
bold :: Doc SimpleHtml -> Doc SimpleHtml Source #
italics :: Doc SimpleHtml -> Doc SimpleHtml Source #
paragraph :: Doc SimpleHtml -> Doc SimpleHtml Source #
headline :: Doc SimpleHtml -> Doc SimpleHtml Source #
color :: Color -> Doc SimpleHtml -> Doc SimpleHtml Source #
The rendering algorithm
With the annotation definitions out of the way, we can now define a
conversion function from SimpleDocStream
(annotated with our SimpleHtml
)
to the tree-shaped SimpleDocTree
, which is easily convertible to a
HTML/Text
representation.
There are two ways to render this; the simpler one is just using
renderSimplyDecorated
. However, some output formats require more
complicated functionality, so we explore this explicitly with a simple
example below. An example for something more complicated is e.g. an XHTML
renderer, where a newline may not simply be a newline character followed by a
certain number of spaces, but e.g. involve adding a br/
tag.
render :: SimpleDocStream SimpleHtml -> Text Source #
To render the HTML, we first convert the SimpleDocStream
to the
SimpleDocTree
format, which makes enveloping sub-documents in markup
easier.
This function is the entry main API function of the renderer; as such, it is
only glue for the internal functions. This is similar to
render
from
the stack machine tutorial in its purpose.
renderTree :: SimpleDocTree SimpleHtml -> Builder Source #
Render a SimpleDocTree
to a Builder
; this is the workhorse of the
tree-based rendering approach, and equivalent to
renderStackMachine
in the stack machine rendering tutorial.
encloseInTagFor :: SimpleHtml -> Builder -> Builder Source #
Convert a SimpleHtml
to a function that encloses a Builder
in HTML
tags. This is where the translation of style to raw output happens.
Example invocation
We can now render an example document using our definitions:
>>>
:set -XOverloadedStrings
>>>
import qualified Data.Text.Lazy.IO as TL
>>>
:{
>>>
let go = TL.putStrLn . render . layoutPretty defaultLayoutOptions
>>>
in go (vsep
>>>
[ headline "Example document"
>>>
, paragraph ("This is a" <+> color Red "paragraph" <> comma)
>>>
, paragraph ("and" <+> bold "this text is bold.")
>>>
])
>>>
:}
<h1>Example document</h1> <p>This is a <span style="color: #f00">paragraph</span>,</p> <p>and <strong>this text is bold.</strong></p>