Prettyprinter.Internal

prettyprinter-1.7.1: A modern, easy to use, well-documented, extensible pretty-printer.

Safe Haskell | Safe-Inferred
Language | Haskell2010

Prettyprinter.Internal

Contents

- Documents
- Basic functionality
  - Primitives for alternative layouts
- Alignment functions
- Binary functions
- List functions
  - `sep` family
  - `cat` family
  - Others
- Reactive/conditional layouts
- Filler functions
- General convenience
  - Annotations
- Optimization
- Layout
- Rendering
- Internal helpers

Description

Warning: internal module! This means that the API may change arbitrarily between versions without notice. Depending on this module may lead to unexpected breakages, so proceed with caution!

For a stable API, use the non-internal modules. For the special case of writing adaptors to this library’s ``Doc`` type, see Prettyprinter.Internal.Type.

Synopsis

- data Doc ann
  - = Fail
  - | Empty
  - | Char !Char
  - | Text !Int !Text
  - | Line
  - | FlatAlt (Doc ann) (Doc ann)
  - | Cat (Doc ann) (Doc ann)
  - | Nest !Int (Doc ann)
  - | Union (Doc ann) (Doc ann)
  - | Column (Int -> Doc ann)
  - | WithPageWidth (PageWidth -> Doc ann)
  - | Nesting (Int -> Doc ann)
  - | Annotated ann (Doc ann)
- class Pretty a where
  - pretty :: a -> Doc ann
  - prettyList :: [a] -> Doc ann
- viaShow :: Show a => a -> Doc ann
- unsafeViaShow :: Show a => a -> Doc ann
- unsafeTextWithoutNewlines :: Text -> Doc ann
- emptyDoc :: Doc ann
- nest :: Int -> Doc ann -> Doc ann
- line :: Doc ann
- line' :: Doc ann
- softline :: Doc ann
- softline' :: Doc ann
- hardline :: Doc ann
- group :: Doc ann -> Doc ann
- flatAlt :: Doc ann -> Doc ann -> 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
- (<+>) :: Doc ann -> Doc ann -> Doc ann
- concatWith :: Foldable t => (Doc ann -> Doc ann -> Doc ann) -> t (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]
- column :: (Int -> Doc ann) -> Doc ann
- nesting :: (Int -> Doc ann) -> Doc ann
- width :: Doc ann -> (Int -> Doc ann) -> Doc ann
- pageWidth :: (PageWidth -> Doc ann) -> Doc ann
- fill :: Int -> Doc ann -> Doc ann
- fillBreak :: Int -> Doc ann -> Doc ann
- plural :: (Num amount, Eq amount) => doc -> doc -> amount -> doc
- enclose :: Doc ann -> Doc ann -> Doc ann -> Doc ann
- surround :: Doc ann -> Doc ann -> Doc ann -> Doc ann
- annotate :: ann -> Doc ann -> Doc ann
- unAnnotate :: Doc ann -> Doc xxx
- reAnnotate :: (ann -> ann') -> Doc ann -> Doc ann'
- alterAnnotations :: (ann -> [ann']) -> Doc ann -> Doc ann'
- unAnnotateS :: SimpleDocStream ann -> SimpleDocStream xxx
- reAnnotateS :: (ann -> ann') -> SimpleDocStream ann -> SimpleDocStream ann'
- alterAnnotationsS :: (ann -> Maybe ann') -> SimpleDocStream ann -> SimpleDocStream ann'
- fuse :: FusionDepth -> Doc ann -> Doc ann
- data FusionDepth
  - = Shallow
  - | Deep
- data SimpleDocStream ann
  - = SFail
  - | SEmpty
  - | SChar !Char (SimpleDocStream ann)
  - | SText !Int !Text (SimpleDocStream ann)
  - | SLine !Int (SimpleDocStream ann)
  - | SAnnPush ann (SimpleDocStream ann)
  - | SAnnPop (SimpleDocStream ann)
- data PageWidth
  - = AvailablePerLine !Int !Double
  - | Unbounded
- defaultPageWidth :: PageWidth
- newtype LayoutOptions = LayoutOptions {
  - layoutPageWidth :: PageWidth
  }
- defaultLayoutOptions :: LayoutOptions
- layoutPretty :: LayoutOptions -> Doc ann -> SimpleDocStream ann
- layoutCompact :: Doc ann1 -> SimpleDocStream ann2
- layoutSmart :: LayoutOptions -> Doc ann -> SimpleDocStream ann
- removeTrailingWhitespace :: SimpleDocStream ann -> SimpleDocStream ann
- renderShowS :: SimpleDocStream ann -> ShowS
- textSpaces :: Int -> Text

# Documents

data Doc ann #

The abstract data type ``Doc` ann` represents pretty documents that have been annotated with data of type `ann`.

More specifically, a value of type ``Doc`` 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.

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

Constructors

Fail | Occurs when flattening a line. The layouter will reject this document, choosing a more suitable rendering.
Empty | The empty document; conceptually the unit of `Cat`
Char !Char | invariant: not 'n'
Text !Int !Text | Invariants: at least two characters long, does not contain 'n'. For empty documents, there is `Empty`; for singleton documents, there is `Char`; newlines should be replaced by e.g. `Line`. Since the frequently used `length` of `Text` is O(length), we cache it in this constructor.
Line | Hard line break
FlatAlt (Doc ann) (Doc ann) | Lay out the first `Doc`, but when flattened (via `group`), prefer the second. The layout algorithms work under the assumption that the first alternative is less wide than the flattened second alternative.
Cat (Doc ann) (Doc ann) | Concatenation of two documents
Nest !Int (Doc ann) | Document indented by a number of columns
Union (Doc ann) (Doc ann) | Invariant: The first lines of first document should be longer than the first lines of the second one, so the layout algorithm can pick the one that fits best. Used to implement layout alternatives for `group`.
Column (Int -> Doc ann) | React on the current cursor position, see `column`
WithPageWidth (PageWidth -> Doc ann) | React on the document's width, see `pageWidth`
Nesting (Int -> Doc ann) | React on the current nesting level, see `nesting`
Annotated ann (Doc ann) | Add an annotation to the enclosed `Doc`. Can be used for example to add styling directives or alt texts that can then be used by the renderer.

#### Instances

Instances details

Functor Doc # | Alter the document’s annotations. This instance makes `Doc` more flexible (because it can be used in `Functor`-polymorphic values), but ``fmap`` is much less readable compared to using ``reAnnotate`` in code that only works for ``Doc`` anyway. Consider using the latter when the type does not matter.
Instance details Defined in Prettyprinter.Internal Methods fmap :: (a -> b) -> Doc a -> Doc b # (<$) :: a -> Doc b -> Doc a #
Monoid (Doc ann) # |
    mempty = emptyDoc
    mconcat = hcat
    >>> mappend "hello" "world" :: Doc ann
    helloworld
Instance details Defined in Prettyprinter.Internal Methods mempty :: Doc ann # mappend :: Doc ann -> Doc ann -> Doc ann # mconcat :: [Doc ann] -> Doc ann #
Semigroup (Doc ann) # |
    x <> y = hcat [x, y]
    >>> "hello" <> "world" :: Doc ann
    helloworld
Instance details Defined in Prettyprinter.Internal Methods (<>) :: Doc ann -> Doc ann -> Doc ann # sconcat :: NonEmpty (Doc ann) -> Doc ann # stimes :: Integral b => b -> Doc ann -> Doc ann #
IsString (Doc ann) # |
    >>> pretty ("hello\nworld")
    hello
    world
This instance uses the `Pretty` `Text` instance, and uses the same newline to `line` conversion.
Instance details Defined in Prettyprinter.Internal Methods fromString :: String -> Doc ann #
Generic (Doc ann) # |
Instance details Defined in Prettyprinter.Internal Associated Types
type Rep (Doc ann) |
Instance details Defined in Prettyprinter.Internal type Rep (Doc ann) = D1 ('MetaData "Doc" "Prettyprinter.Internal" "prettyprinter-1.7.1-IkgfhT2Rur1GNk5bvThQCA" 'False) (((C1 ('MetaCons "Fail" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "Empty" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Char" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Char)))) :+: (C1 ('MetaCons "Text" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text)) :+: (C1 ('MetaCons "Line" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "FlatAlt" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann)))))) :+: ((C1 ('MetaCons "Cat" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann))) :+: (C1 ('MetaCons "Nest" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann))) :+: C1 ('MetaCons "Union" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann))))) :+: ((C1 ('MetaCons "Column" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Int -> Doc ann))) :+: C1 ('MetaCons "WithPageWidth" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (PageWidth -> Doc ann)))) :+: (C1 ('MetaCons "Nesting" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Int -> Doc ann))) :+: C1 ('MetaCons "Annotated" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ann) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann)))))))
Methods from :: Doc ann -> Rep (Doc ann) x # to :: Rep (Doc ann) x -> Doc ann #
Show (Doc ann) # | `(`show` doc)` prettyprints document `doc` with `defaultLayoutOptions`, ignoring all annotations.
Instance details Defined in Prettyprinter.Internal Methods showsPrec :: Int -> Doc ann -> ShowS # show :: Doc ann -> String # showList :: [Doc ann] -> ShowS #
type Rep (Doc ann) # |
Instance details Defined in Prettyprinter.Internal type Rep (Doc ann) = D1 ('MetaData "Doc" "Prettyprinter.Internal" "prettyprinter-1.7.1-IkgfhT2Rur1GNk5bvThQCA" 'False) (((C1 ('MetaCons "Fail" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "Empty" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Char" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Char)))) :+: (C1 ('MetaCons "Text" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text)) :+: (C1 ('MetaCons "Line" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "FlatAlt" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann)))))) :+: ((C1 ('MetaCons "Cat" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann))) :+: (C1 ('MetaCons "Nest" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann))) :+: C1 ('MetaCons "Union" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann)) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann))))) :+: ((C1 ('MetaCons "Column" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Int -> Doc ann))) :+: C1 ('MetaCons "WithPageWidth" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (PageWidth -> Doc ann)))) :+: (C1 ('MetaCons "Nesting" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Int -> Doc ann))) :+: C1 ('MetaCons "Annotated" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ann) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Doc ann)))))))

# Basic functionality

class Pretty a where #

Overloaded conversion to `Doc`.

Laws:

1. output should be pretty. :-)

Minimal complete definition

pretty

Methods

pretty :: a -> Doc ann #

    >>> pretty 1 <+> pretty "hello" <+> pretty 1.234
    1 hello 1.234

default pretty :: Show a => a -> Doc ann #

prettyList :: [a] -> Doc ann #

``prettyList`` is only used to define the `instance `Pretty` a => `Pretty` [a]`. In normal circumstances only the ``pretty`` function is used.

    >>> prettyList [1, 23, 456]
    [1, 23, 456]

#### Instances

Instances details

Pretty Void # | Finding a good example for printing something that does not exist is hard, so here is an example of printing a list full of nothing.
    >>> pretty ([] :: [Void])
    []
Instance details Defined in Prettyprinter.Internal Methods pretty :: Void -> Doc ann # prettyList :: [Void] -> Doc ann #
Pretty Int16 # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: Int16 -> Doc ann # prettyList :: [Int16] -> Doc ann #
Pretty Int32 # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: Int32 -> Doc ann # prettyList :: [Int32] -> Doc ann #
Pretty Int64 # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: Int64 -> Doc ann # prettyList :: [Int64] -> Doc ann #
Pretty Int8 # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: Int8 -> Doc ann # prettyList :: [Int8] -> Doc ann #
Pretty Word16 # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: Word16 -> Doc ann # prettyList :: [Word16] -> Doc ann #
Pretty Word32 # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: Word32 -> Doc ann # prettyList :: [Word32] -> Doc ann #
Pretty Word64 # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: Word64 -> Doc ann # prettyList :: [Word64] -> Doc ann #
Pretty Word8 # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: Word8 -> Doc ann # prettyList :: [Word8] -> Doc ann #
Pretty Text # | Automatically converts all newlines to ``line``.
    >>> pretty ("hello\nworld" :: Text)
    hello
    world
Note that ``line`` can be undone by ``group``:
    >>> group (pretty ("hello\nworld" :: Text))
    hello world
Manually use ``hardline`` if you definitely want newlines.
Instance details Defined in Prettyprinter.Internal Methods pretty :: Text -> Doc ann # prettyList :: [Text] -> Doc ann #
Pretty Text # | (lazy `Text` instance, identical to the strict version)
Instance details Defined in Prettyprinter.Internal Methods pretty :: Text -> Doc ann # prettyList :: [Text] -> Doc ann #
Pretty Integer # |
    >>> pretty (2^123 :: Integer)
    10633823966279326983230456482242756608
Instance details Defined in Prettyprinter.Internal Methods pretty :: Integer -> Doc ann # prettyList :: [Integer] -> Doc ann #
Pretty Natural # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: Natural -> Doc ann # prettyList :: [Natural] -> Doc ann #
Pretty () # |
    >>> pretty ()
    ()
The argument is not used:
    >>> pretty (error "Strict?" :: ())
    ()
Instance details Defined in Prettyprinter.Internal Methods pretty :: () -> Doc ann # prettyList :: [()] -> Doc ann #
Pretty Bool # |
    >>> pretty True
    True
Instance details Defined in Prettyprinter.Internal Methods pretty :: Bool -> Doc ann # prettyList :: [Bool] -> Doc ann #
Pretty Char # | Instead of `(`pretty` 'n')`, consider using ``line`` as a more readable alternative.
    >>> pretty 'f' <> pretty 'o' <> pretty 'o'
    foo
    >>> pretty ("string" :: String)
    string
Instance details Defined in Prettyprinter.Internal Methods pretty :: Char -> Doc ann # prettyList :: [Char] -> Doc ann #
Pretty Double # |
    >>> pretty (exp 1 :: Double)
    2.71828182845904...
Instance details Defined in Prettyprinter.Internal Methods pretty :: Double -> Doc ann # prettyList :: [Double] -> Doc ann #
Pretty Float # |
    >>> pretty (pi :: Float)
    3.1415927
Instance details Defined in Prettyprinter.Internal Methods pretty :: Float -> Doc ann # prettyList :: [Float] -> Doc ann #
Pretty Int # |
    >>> pretty (123 :: Int)
    123
Instance details Defined in Prettyprinter.Internal Methods pretty :: Int -> Doc ann # prettyList :: [Int] -> Doc ann #
Pretty Word # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: Word -> Doc ann # prettyList :: [Word] -> Doc ann #
Pretty a => Pretty (NonEmpty a) # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: NonEmpty a -> Doc ann # prettyList :: [NonEmpty a] -> Doc ann #
Pretty a => Pretty (Identity a) # |
    >>> pretty (Identity 1)
    1
Instance details Defined in Prettyprinter.Internal Methods pretty :: Identity a -> Doc ann # prettyList :: [Identity a] -> Doc ann #
Pretty a => Pretty (Maybe a) # | Ignore `Nothing`s, print `Just` contents.
    >>> pretty (Just True)
    True
    >>> braces (pretty (Nothing :: Maybe Bool))
    {}
    >>> pretty [Just 1, Nothing, Just 3, Nothing]
    [1, 3]
Instance details Defined in Prettyprinter.Internal Methods pretty :: Maybe a -> Doc ann # prettyList :: [Maybe a] -> Doc ann #
Pretty a => Pretty [a] # |
    >>> pretty [1,2,3]
    [1, 2, 3]
Instance details Defined in Prettyprinter.Internal Methods pretty :: [a] -> Doc ann # prettyList :: [[a]] -> Doc ann #
(Pretty a1, Pretty a2) => Pretty (a1, a2) # |
    >>> pretty (123, "hello")
    (123, hello)
Instance details Defined in Prettyprinter.Internal Methods pretty :: (a1, a2) -> Doc ann # prettyList :: [(a1, a2)] -> Doc ann #
Pretty a => Pretty (Const a b) # |
Instance details Defined in Prettyprinter.Internal Methods pretty :: Const a b -> Doc ann # prettyList :: [Const a b] -> Doc ann #
(Pretty a1, Pretty a2, Pretty a3) => Pretty (a1, a2, a3) # |
    >>> pretty (123, "hello", False)
    (123, hello, False)
Instance details Defined in Prettyprinter.Internal Methods pretty :: (a1, a2, a3) -> Doc ann # prettyList :: [(a1, a2, a3)] -> Doc ann #

viaShow :: Show a => a -> Doc ann #

Convenience function to convert a `Show`able value to a `Doc`. If the `String` does not contain newlines, consider using the more performant `unsafeViaShow`.

unsafeViaShow :: Show a => a -> Doc ann #

Convenience function to convert a `Show`able value /that must not contain newlines/ to a `Doc`. If there may be newlines, use `viaShow` instead.

unsafeTextWithoutNewlines :: Text -> Doc ann #

`(unsafeTextWithoutNewlines s)` contains the literal string `s`.

The string must not contain any newline characters, since this is an invariant of the `Text` constructor.

emptyDoc :: Doc ann #

The empty document behaves like `(`pretty` "")`, so it has a height of 1. This may lead to surprising behaviour if we expect it to bear no weight inside e.g. `vcat`, where we get an empty line of output from it (`parens` for visibility only):

    >>> vsep ["hello", parens emptyDoc, "world"]
    hello
    ()
    world

Together with `<>`, `emptyDoc` forms the `Monoid` `Doc`.

nest #

Arguments

:: Int | Change of nesting level
-> Doc ann |
-> Doc ann |

`(`nest` i x)` lays out the document `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

- `hang` (`nest` relative to current cursor position instead of current nesting level)
- `align` (set nesting level to current cursor position)
- `indent` (increase indentation on the spot, padding with spaces).

line :: Doc ann #

The ``line`` document advances to the next line and indents to the current nesting level.

    >>> let doc = "lorem ipsum" <> line <> "dolor sit amet"
    >>> doc
    lorem ipsum
    dolor sit amet

``line`` behaves like ``space`` if the line break is undone by `group`:

    >>> group doc
    lorem ipsum dolor sit amet

line' :: Doc ann #

``line'`` is like ``line``, but behaves like ``mempty`` if the line break is undone by `group` (instead of ``space``).

    >>> let doc = "lorem ipsum" <> line' <> "dolor sit amet"
    >>> doc
    lorem ipsum
    dolor sit amet
    >>> group doc
    lorem ipsumdolor sit amet

softline :: Doc ann #

`softline` behaves like ``space`` if the resulting output fits the page, otherwise like ``line``.

Here, we have enough space to put everything in one line:

    >>> let doc = "lorem ipsum" <> softline <> "dolor sit amet"
    >>> putDocW 80 doc
    lorem ipsum dolor sit amet

If we narrow the page to width 10, the layouter produces a line break:

    >>> putDocW 10 doc
    lorem ipsum
    dolor sit amet

    softline = group line

softline' :: Doc ann #

``softline'`` is like ``softline``, but behaves like ``mempty`` if the resulting output does not fit on the page (instead of ``space``). In other words, ``line`` is to ``line'`` how ``softline`` is to ``softline'``.

With enough space, we get direct concatenation:

    >>> let doc = "ThisWord" <> softline' <> "IsWayTooLong"
    >>> putDocW 80 doc
    ThisWordIsWayTooLong

If we narrow the page to width 10, the layouter produces a line break:

    >>> putDocW 10 doc
    ThisWord
    IsWayTooLong

    softline' = group line'

hardline :: Doc ann #

A ``hardline`` is always laid out as a line break, even when `group`ed or when there is plenty of space. Note that it might still be simply discarded if it is part of a `flatAlt` inside a `group`.

    >>> let doc = "lorem ipsum" <> hardline <> "dolor sit amet"
    >>> putDocW 1000 doc
    lorem ipsum
    dolor sit amet

    >>> group doc
    lorem ipsum
    dolor sit amet

## Primitives for alternative layouts

group :: Doc ann -> Doc ann #

`(`group` x)` tries laying out `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.

flatAlt #

Arguments

:: Doc ann | Default
-> Doc ann | Preferred when `group`ed
-> Doc ann |

By default, `(`flatAlt` x y)` renders as `x`. However when `group`ed, `y` will be preferred, with `x` as the fallback for the case when `y` doesn't fit.

    >>> let doc = flatAlt "a" "b"
    >>> putDoc doc
    a
    >>> putDoc (group doc)
    b
    >>> putDocW 0 (group doc)
    a

`flatAlt` is particularly useful for defining conditional separators such as

    softline = group (flatAlt hardline " ")

    >>> let hello = "Hello" <> softline <> "world!"
    >>> putDocW 12 hello
    Hello world!
    >>> putDocW 11 hello
    Hello
    world!

### Example: Haskell's do-notation

Expand

We can use this to render Haskell's do-notation nicely:

    >>> let open        = flatAlt "" "{ "
    >>> let close       = flatAlt "" " }"
    >>> let separator   = flatAlt "" "; "
    >>> let prettyDo xs = group ("do" <+> align (encloseSep open close separator xs))
    >>> let statements  = ["name:_ <- getArgs", "let greet = \"Hello, \" <> name", "putStrLn greet"]

This is put into a single line with `{;}` style if it fits:

    >>> putDocW 80 (prettyDo statements)
    do { name:_ <- getArgs; let greet = "Hello, " <> name; putStrLn greet }

When there is not enough space the statements are broken up into lines nicely:

    >>> putDocW 10 (prettyDo statements)
    do name:_ <- getArgs
       let greet = "Hello, " <> name
       putStrLn greet

### Notes

Users should be careful to choose `x` to be less wide than `y`. Otherwise, if `y` turns out not to fit the page, we fall back on an even wider layout:

    >>> let ugly = group (flatAlt "even wider" "too wide")
    >>> putDocW 7 ugly
    even wider

Also note that `group` will flatten `y`:

    >>> putDoc (group (flatAlt "x" ("y" <> line <> "y")))
    y y

This also means that an "unflattenable" `y` which contains a hard linebreak will never be rendered:

    >>> putDoc (group (flatAlt "x" ("y" <> hardline <> "y")))
    x

# Alignment functions

align :: Doc ann -> Doc ann #

`(`align` x)` lays out the document `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 `align`ment, 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 ``vsep``'s contents all start in the same column:

    >>> "lorem" <+> align (vsep ["ipsum", "dolor"])
    lorem ipsum
          dolor

hang #

Arguments

:: Int | Change of nesting level, relative to the start of the first line
-> Doc ann |
-> Doc ann |

`(`hang` i x)` lays out the document `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

    hang i doc = align (nest i doc)

indent #

Arguments

:: Int | Number of spaces to increase indentation by
-> Doc ann |
-> Doc ann |

`(`indent` i x)` indents document `x` by `i` columns, starting from the current cursor position.

    >>> let doc = reflow "The indent function indents these words!"
    >>> putDocW 24 ("prefix" <> indent 4 doc)
    prefix    The indent
              function
              indents these
              words!

    indent i d = hang i ({i spaces} <> d)

encloseSep #

Arguments

:: Doc ann | left delimiter
-> Doc ann | right delimiter
-> Doc ann | separator
-> [Doc ann] | input documents
-> Doc ann |

`(`encloseSep` l r sep xs)` concatenates the documents `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 doc
    list [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 doc
    list [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 )

# Binary functions

(<+>) :: Doc ann -> Doc ann -> Doc ann infixr 6 #

`(x `<+>` y)` concatenates document `x` and `y` with a ``space`` in between.

    >>> "hello" <+> "world"
    hello world

    x <+> y = x <> space <> y

# List functions

concatWith :: Foldable t => (Doc ann -> Doc ann -> Doc ann) -> t (Doc ann) -> Doc ann #

Concatenate all documents element-wise with a binary function.

    concatWith _ [] = mempty
    concatWith (**) [x,y,z] = x ** y ** z

Multiple convenience definitions based on `concatWith` are already predefined, for example:

    hsep    = concatWith (<+>)
    fillSep = concatWith (\x y -> x <> softline <> y)

This is also useful to define customized joiners:

    >>> concatWith (surround dot) ["Prettyprinter", "Render", "Text"]
    Prettyprinter.Render.Text

## `sep` family

hsep :: [Doc ann] -> Doc ann #

`(`hsep` xs)` concatenates all documents `xs` horizontally with ``<+>``, i.e. it puts a space between all entries.

    >>> let docs = Util.words "lorem ipsum dolor sit amet"

    >>> hsep docs
    lorem ipsum dolor sit amet

``hsep`` does not introduce line breaks on its own, even when the page is too narrow:

    >>> putDocW 5 (hsep docs)
    lorem ipsum dolor sit amet

For automatic line breaks, consider using `fillSep` instead.

vsep :: [Doc ann] -> Doc ann #

`(`vsep` xs)` concatenates all documents `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

`group`ing a `vsep` separates the documents with a `space` if it fits the page (and does nothing otherwise). See the ``sep`` convenience function for this use case.

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 `group`ing a `vsep` is rather common, `sep` is a built-in for doing that.

fillSep :: [Doc ann] -> Doc ann #

`(`fillSep` xs)` concatenates the documents `xs` horizontally with ``<+>`` as long as it fits the page, then inserts a ``line`` and continues doing that for all documents in `xs`. (``line`` means that if `group`ed, 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

sep :: [Doc ann] -> Doc ann #

`(`sep` xs)` tries laying out the documents `xs` separated with `space`s, 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 doc
    prefix text to lay out

With a narrower layout, the entries are separated by newlines:

    >>> putDocW 20 doc
    prefix text
    to
    lay
    out

    sep = group . vsep

## `cat` family

hcat :: [Doc ann] -> Doc ann #

`(`hcat` xs)` concatenates all documents `xs` horizontally with ``<>`` (i.e. without any spacing).

It is provided only for consistency, since it is identical to `mconcat`.

    >>> let docs = Util.words "lorem ipsum dolor"
    >>> hcat docs
    loremipsumdolor

vcat :: [Doc ann] -> Doc ann #

`(`vcat` xs)` vertically concatenates the documents `xs`. If it is `group`ed, the line breaks are removed.

In other words ``vcat`` is like ``vsep``, with newlines removed instead of replaced by `space`s.

    >>> let docs = Util.words "lorem ipsum dolor"
    >>> vcat docs
    lorem
    ipsum
    dolor
    >>> group (vcat docs)
    loremipsumdolor

Since `group`ing a `vcat` is rather common, `cat` is a built-in shortcut for it.

fillCat :: [Doc ann] -> Doc ann #

`(`fillCat` xs)` concatenates documents `xs` horizontally with ``<>`` as long as it fits the page, then inserts a ``line'`` and continues doing that for all documents in `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.

(``line'`` means that if `group`ed, 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 `space`d when `group`ed:

    >>> 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 `group`ed:

    >>> putDocW 40 ("Grouped:" <+> group (fillCat docs))
    Grouped: loremipsumdolorsitametlorem
    ipsumdolorsitametloremipsumdolorsitamet
    loremipsumdolorsitamet

cat :: [Doc ann] -> Doc ann #

`(`cat` xs)` tries laying out the documents `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

## Others

punctuate #

Arguments

:: Doc ann | Punctuation, e.g. `comma`
-> [Doc ann] |
-> [Doc ann] |

`(`punctuate` p xs)` appends `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`.

# Reactive/conditional layouts

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

nesting :: (Int -> Doc ann) -> Doc ann #

Layout a document depending on the current `nest`ing level. `align` is implemented in terms of `nesting`.

    >>> let doc = "prefix" <+> nesting (\l -> brackets ("Nested:" <+> pretty l))
    >>> vsep [indent n doc | n <- [0,4,8]]
    prefix [Nested: 0]
        prefix [Nested: 4]
            prefix [Nested: 8]

width :: Doc ann -> (Int -> Doc ann) -> Doc ann #

`(`width` doc f)` lays out the document `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

pageWidth :: (PageWidth -> Doc ann) -> Doc ann #

Layout a document depending on the page width, if one has been specified.

    >>> let prettyPageWidth (AvailablePerLine l r) = "Width:" <+> pretty l <> ", ribbon fraction:" <+> pretty r
    >>> let doc = "prefix" <+> pageWidth (brackets . prettyPageWidth)
    >>> putDocW 32 (vsep [indent n doc | n <- [0,4,8]])
    prefix [Width: 32, ribbon fraction: 1.0]
        prefix [Width: 32, ribbon fraction: 1.0]
            prefix [Width: 32, ribbon fraction: 1.0]

# Filler functions

fill #

Arguments

:: Int | Append spaces until the document is at least this wide
-> Doc ann |
-> Doc ann |

`(`fill` i x)` lays out the document `x`. It then appends `space`s 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

fillBreak #

Arguments

:: Int | Append spaces until the document is at least this wide
-> Doc ann |
-> Doc ann |

`(`fillBreak` i x)` first lays out the document `x`. It then appends `space`s 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 ``fillBreak``, we get a useful variation of the output:

    >>> 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

# General convenience

plural #

Arguments

:: (Num amount, Eq amount) |
=> doc | `1` case
-> doc | other cases
-> amount |
-> doc |

`(`plural` n one many)` is `one` if `n` is `1`, and `many` otherwise. A typical use case is adding a plural "s".

    >>> let things = [True]
    >>> let amount = length things
    >>> pretty things <+> "has" <+> pretty amount <+> plural "entry" "entries" amount
    [True] has 1 entry

enclose #

Arguments

:: Doc ann | L
-> Doc ann | R
-> Doc ann | x
-> Doc ann | LxR

`(`enclose` l r x)` encloses document `x` between documents `l` and `r` using ``<>``.

    >>> enclose "A" "Z" "·"
    A·Z

    enclose l r x = l <> x <> r

surround :: Doc ann -> Doc ann -> Doc ann -> Doc ann #

`(`surround` x l r)` surrounds document `x` with `l` and `r`.

    >>> surround "·" "A" "Z"
    A·Z

This is merely an argument reordering of ``enclose``, but allows for definitions like

    >>> concatWith (surround dot) ["Prettyprinter", "Render", "Text"]
    Prettyprinter.Render.Text

## Annotations

annotate :: ann -> Doc ann -> Doc ann #

Add an annotation to a ``Doc``. 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.

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.

unAnnotate :: Doc ann -> Doc xxx #

Remove all annotations.

Although `unAnnotate` is idempotent with respect to rendering,

    unAnnotate . unAnnotate = unAnnotate

it should not be used without caution, for each invocation traverses the entire contained document. If possible, it is preferrable to unannotate after producing the layout by using `unAnnotateS`.

reAnnotate :: (ann -> ann') -> Doc ann -> Doc ann' #

Change the annotation of a `Doc`ument.

Useful in particular to embed documents with one form of annotation in a more generally annotated document.

Since this traverses the entire ``Doc`` tree, including parts that are not rendered due to other layouts fitting better, it is preferrable to reannotate after producing the layout by using ``reAnnotateS``.

Since ``reAnnotate`` has the right type and satisfies `'reAnnotate id = id'`, it is used to define the ``Functor`` instance of ``Doc``.

alterAnnotations :: (ann -> [ann']) -> Doc ann -> Doc ann' #

Change the annotations of a `Doc`ument. Individual annotations can be removed, changed, or replaced by multiple ones.

This is a general function that combines `unAnnotate` and `reAnnotate`, and it is useful for mapping semantic annotations (such as »this is a keyword«) to display annotations (such as »this is red and underlined«), because some backends may not care about certain annotations, while others may.

Annotations earlier in the new list will be applied earlier, i.e. returning `[Bold, Green]` will result in a bold document that contains green text, and not vice-versa.

Since this traverses the entire ``Doc`` tree, including parts that are not rendered due to other layouts fitting better, it is preferrable to reannotate after producing the layout by using ``alterAnnotationsS``.

unAnnotateS :: SimpleDocStream ann -> SimpleDocStream xxx #

Remove all annotations. `unAnnotate` for `SimpleDocStream`.

reAnnotateS :: (ann -> ann') -> SimpleDocStream ann -> SimpleDocStream ann' #

Change the annotation of a document. `reAnnotate` for `SimpleDocStream`.

alterAnnotationsS :: (ann -> Maybe ann') -> SimpleDocStream ann -> SimpleDocStream ann' #

Change the annotation of a document to a different annotation, or none at all. `alterAnnotations` for `SimpleDocStream`.

Note that the `Doc` version is more flexible, since it allows changing a single annotation to multiple ones. (`SimpleDocTree` restores this flexibility again.)

# Optimization

fuse :: FusionDepth -> Doc ann -> Doc ann #

`(`fuse` depth doc)` combines text nodes so they can be rendered more efficiently. A fused document is always laid out identical to its unfused version.

When laying a `Doc`ument out to a `SimpleDocStream`, every component of the input is translated directly to the simpler output format. This sometimes yields undesirable chunking when many pieces have been concatenated together.

For example

    >>> "a" <> "b" <> pretty 'c' <> "d"
    abcd

results in a chain of four entries in a `SimpleDocStream`, although this is fully equivalent to the tightly packed

    >>> "abcd" :: Doc ann
    abcd

which is only a single `SimpleDocStream` entry, and can be processed faster.

It is therefore a good idea to run `fuse` on concatenations of lots of small strings that are used many times:

    >>> let oftenUsed = fuse Shallow ("a" <> "b" <> pretty 'c' <> "d")
    >>> hsep (replicate 5 oftenUsed)
    abcd abcd abcd abcd abcd

data FusionDepth #

Fusion depth parameter, used by `fuse`.

Constructors

Shallow | Do not dive deep into nested documents, fusing mostly concatenations of text nodes together.
Deep | Recurse into all parts of the `Doc`, including different layout alternatives, and location-sensitive values such as created by `nesting` which cannot be fused before, but only during, the layout process. As a result, the performance cost of using deep fusion is often hard to predict, and depends on the interplay between page layout and document to prettyprint. This value should only be used if profiling shows it is significantly faster than using `Shallow`.

#### Instances

Instances details

Show FusionDepth # |
Instance details Defined in Prettyprinter.Internal Methods showsPrec :: Int -> FusionDepth -> ShowS # show :: FusionDepth -> String # showList :: [FusionDepth] -> ShowS #
Eq FusionDepth # |
Instance details Defined in Prettyprinter.Internal Methods (==) :: FusionDepth -> FusionDepth -> Bool # (/=) :: FusionDepth -> FusionDepth -> Bool #
Ord FusionDepth # |
Instance details Defined in Prettyprinter.Internal Methods compare :: FusionDepth -> FusionDepth -> Ordering # (<) :: FusionDepth -> FusionDepth -> Bool # (<=) :: FusionDepth -> FusionDepth -> Bool # (>) :: FusionDepth -> FusionDepth -> Bool # (>=) :: FusionDepth -> FusionDepth -> Bool # max :: FusionDepth -> FusionDepth -> FusionDepth # min :: FusionDepth -> FusionDepth -> FusionDepth #

# Layout

data SimpleDocStream ann #

The data type `SimpleDocStream` represents laid out documents and is used by the display functions.

A simplified view is that ``Doc` = [`SimpleDocStream`]`, and the layout functions pick one of the `SimpleDocStream`s based on which one fits the layout constraints best. This means that `SimpleDocStream` has all complexity contained in `Doc` resolved, making it very easy to convert it to other formats, such as plain text or terminal output.

To write your own ``Doc`` to X converter, it is therefore sufficient to convert from ``SimpleDocStream``. The »Render« submodules provide some built-in converters to do so, and helpers to create own ones.

Constructors

SFail |
SEmpty |
SChar !Char (SimpleDocStream ann) |
SText !Int !Text (SimpleDocStream ann) | `length` is O(n), so we cache it in the `Int` field.
SLine !Int (SimpleDocStream ann) | `Int` = indentation level for the (next) line
SAnnPush ann (SimpleDocStream ann) | Add an annotation to the remaining document.
SAnnPop (SimpleDocStream ann) | Remove a previously pushed annotation.

#### Instances

Instances details

Functor SimpleDocStream # | Alter the document’s annotations. This instance makes `SimpleDocStream` more flexible (because it can be used in `Functor`-polymorphic values), but ``fmap`` is much less readable compared to using ``reAnnotateST`` in code that only works for ``SimpleDocStream`` anyway. Consider using the latter when the type does not matter.
Instance details Defined in Prettyprinter.Internal Methods fmap :: (a -> b) -> SimpleDocStream a -> SimpleDocStream b # (<$) :: a -> SimpleDocStream b -> SimpleDocStream a #
Foldable SimpleDocStream # | Collect all annotations from a document.
Instance details Defined in Prettyprinter.Internal Methods fold :: Monoid m => SimpleDocStream m -> m # foldMap :: Monoid m => (a -> m) -> SimpleDocStream a -> m # foldMap' :: Monoid m => (a -> m) -> SimpleDocStream a -> m # foldr :: (a -> b -> b) -> b -> SimpleDocStream a -> b # foldr' :: (a -> b -> b) -> b -> SimpleDocStream a -> b # foldl :: (b -> a -> b) -> b -> SimpleDocStream a -> b # foldl' :: (b -> a -> b) -> b -> SimpleDocStream a -> b # foldr1 :: (a -> a -> a) -> SimpleDocStream a -> a # foldl1 :: (a -> a -> a) -> SimpleDocStream a -> a # toList :: SimpleDocStream a -> [a] # null :: SimpleDocStream a -> Bool # length :: SimpleDocStream a -> Int # elem :: Eq a => a -> SimpleDocStream a -> Bool # maximum :: Ord a => SimpleDocStream a -> a # minimum :: Ord a => SimpleDocStream a -> a # sum :: Num a => SimpleDocStream a -> a # product :: Num a => SimpleDocStream a -> a #
Traversable SimpleDocStream # | Transform a document based on its annotations, possibly leveraging `Applicative` effects.
Instance details Defined in Prettyprinter.Internal Methods traverse :: Applicative f => (a -> f b) -> SimpleDocStream a -> f (SimpleDocStream b) # sequenceA :: Applicative f => SimpleDocStream (f a) -> f (SimpleDocStream a) # mapM :: Monad m => (a -> m b) -> SimpleDocStream a -> m (SimpleDocStream b) # sequence :: Monad m => SimpleDocStream (m a) -> m (SimpleDocStream a) #
Generic (SimpleDocStream ann) # |
Instance details Defined in Prettyprinter.Internal Associated Types
type Rep (SimpleDocStream ann) |
Instance details Defined in Prettyprinter.Internal type Rep (SimpleDocStream ann) = D1 ('MetaData "SimpleDocStream" "Prettyprinter.Internal" "prettyprinter-1.7.1-IkgfhT2Rur1GNk5bvThQCA" 'False) ((C1 ('MetaCons "SFail" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "SEmpty" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "SChar" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Char) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (SimpleDocStream ann))))) :+: ((C1 ('MetaCons "SText" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (SimpleDocStream ann)))) :+: C1 ('MetaCons "SLine" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (SimpleDocStream ann)))) :+: (C1 ('MetaCons "SAnnPush" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ann) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (SimpleDocStream ann))) :+: C1 ('MetaCons "SAnnPop" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (SimpleDocStream ann))))))
Methods from :: SimpleDocStream ann -> Rep (SimpleDocStream ann) x # to :: Rep (SimpleDocStream ann) x -> SimpleDocStream ann #
Show ann => Show (SimpleDocStream ann) # |
Instance details Defined in Prettyprinter.Internal Methods showsPrec :: Int -> SimpleDocStream ann -> ShowS # show :: SimpleDocStream ann -> String # showList :: [SimpleDocStream ann] -> ShowS #
Eq ann => Eq (SimpleDocStream ann) # |
Instance details Defined in Prettyprinter.Internal Methods (==) :: SimpleDocStream ann -> SimpleDocStream ann -> Bool # (/=) :: SimpleDocStream ann -> SimpleDocStream ann -> Bool #
Ord ann => Ord (SimpleDocStream ann) # |
Instance details Defined in Prettyprinter.Internal Methods compare :: SimpleDocStream ann -> SimpleDocStream ann -> Ordering # (<) :: SimpleDocStream ann -> SimpleDocStream ann -> Bool # (<=) :: SimpleDocStream ann -> SimpleDocStream ann -> Bool # (>) :: SimpleDocStream ann -> SimpleDocStream ann -> Bool # (>=) :: SimpleDocStream ann -> SimpleDocStream ann -> Bool # max :: SimpleDocStream ann -> SimpleDocStream ann -> SimpleDocStream ann # min :: SimpleDocStream ann -> SimpleDocStream ann -> SimpleDocStream ann #
type Rep (SimpleDocStream ann) # |
Instance details Defined in Prettyprinter.Internal type Rep (SimpleDocStream ann) = D1 ('MetaData "SimpleDocStream" "Prettyprinter.Internal" "prettyprinter-1.7.1-IkgfhT2Rur1GNk5bvThQCA" 'False) ((C1 ('MetaCons "SFail" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "SEmpty" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "SChar" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Char) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (SimpleDocStream ann))))) :+: ((C1 ('MetaCons "SText" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (SimpleDocStream ann)))) :+: C1 ('MetaCons "SLine" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (SimpleDocStream ann)))) :+: (C1 ('MetaCons "SAnnPush" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ann) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (SimpleDocStream ann))) :+: C1 ('MetaCons "SAnnPop" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (SimpleDocStream ann))))))

data PageWidth #

Maximum number of characters that fit in one line. The layout algorithms will try not to exceed the set limit by inserting line breaks when applicable (e.g. via `softline'`).

Constructors

AvailablePerLine !Int !Double | Layouters should not exceed the specified space per line. The `Int` is the number of characters, including whitespace, that fit in a line. A typical value is 80. The `Double` is the ribbon with, i.e. the fraction of the total page width that can be printed on. This allows limiting the length of printable text per line. Values must be between 0 and 1, and 0.4 to 1 is typical.
Unbounded | Layouters should not introduce line breaks on their own.

#### Instances

Instances details

Show PageWidth # |
Instance details Defined in Prettyprinter.Internal Methods showsPrec :: Int -> PageWidth -> ShowS # show :: PageWidth -> String # showList :: [PageWidth] -> ShowS #
Eq PageWidth # |
Instance details Defined in Prettyprinter.Internal Methods (==) :: PageWidth -> PageWidth -> Bool # (/=) :: PageWidth -> PageWidth -> Bool #
Ord PageWidth # |
Instance details Defined in Prettyprinter.Internal Methods compare :: PageWidth -> PageWidth -> Ordering # (<) :: PageWidth -> PageWidth -> Bool # (<=) :: PageWidth -> PageWidth -> Bool # (>) :: PageWidth -> PageWidth -> Bool # (>=) :: PageWidth -> PageWidth -> Bool # max :: PageWidth -> PageWidth -> PageWidth # min :: PageWidth -> PageWidth -> PageWidth #

defaultPageWidth :: PageWidth #

newtype LayoutOptions #

Options to influence the layout algorithms.

Constructors

LayoutOptions |
Fields layoutPageWidth :: PageWidth

#### Instances

Instances details

Show LayoutOptions # |
Instance details Defined in Prettyprinter.Internal Methods showsPrec :: Int -> LayoutOptions -> ShowS # show :: LayoutOptions -> String # showList :: [LayoutOptions] -> ShowS #
Eq LayoutOptions # |
Instance details Defined in Prettyprinter.Internal Methods (==) :: LayoutOptions -> LayoutOptions -> Bool # (/=) :: LayoutOptions -> LayoutOptions -> Bool #
Ord LayoutOptions # |
Instance details Defined in Prettyprinter.Internal Methods compare :: LayoutOptions -> LayoutOptions -> Ordering # (<) :: LayoutOptions -> LayoutOptions -> Bool # (<=) :: LayoutOptions -> LayoutOptions -> Bool # (>) :: LayoutOptions -> LayoutOptions -> Bool # (>=) :: LayoutOptions -> LayoutOptions -> Bool # max :: LayoutOptions -> LayoutOptions -> LayoutOptions # min :: LayoutOptions -> LayoutOptions -> LayoutOptions #

defaultLayoutOptions :: LayoutOptions #

The default layout options, suitable when you just want some output, and don’t particularly care about the details. Used by the `Show` instance, for example.

    >>> defaultLayoutOptions
    LayoutOptions {layoutPageWidth = AvailablePerLine 80 1.0}

layoutPretty :: LayoutOptions -> Doc ann -> SimpleDocStream ann #

This is the default layout algorithm, and it is used by `show`, `putDoc` and `hPutDoc`.

``layoutPretty`` commits to rendering something in a certain way if the next element fits the layout constraints; in other words, it has one `SimpleDocStream` element lookahead when rendering. Consider using the smarter, but a bit less performant, ``layoutSmart`` algorithm if the results seem to run off to the right before having lots of line breaks.

layoutCompact :: Doc ann1 -> SimpleDocStream ann2 #

`(layoutCompact x)` lays out the document `x` without adding any indentation and without preserving annotations. Since no 'pretty' printing is involved, this layouter is very fast. The resulting output contains fewer characters than a prettyprinted version and can be used for output that is read by other programs.

    >>> let doc = hang 4 (vsep ["lorem", "ipsum", hang 4 (vsep ["dolor", "sit"])])
    >>> doc
    lorem
        ipsum
        dolor
            sit

    >>> let putDocCompact = renderIO System.IO.stdout . layoutCompact
    >>> putDocCompact doc
    lorem
    ipsum
    dolor
    sit

layoutSmart :: LayoutOptions -> Doc ann -> SimpleDocStream ann #

A layout algorithm with more lookahead than `layoutPretty`, that introduces line breaks earlier if the content does not (or will not, rather) fit into one line.

Consider the following python-ish document,

    >>> let fun x = hang 2 ("fun(" <> softline' <> x) <> ")"
    >>> let doc = (fun . fun . fun . fun . fun) (align (list ["abcdef", "ghijklm"]))

which we’ll be rendering using the following pipeline (where the layout algorithm has been left open):

    >>> import Data.Text.IO as T
    >>> import Prettyprinter.Render.Text
    >>> let hr = pipe <> pretty (replicate (26-2) '-') <> pipe
    >>> let go layouter x = (T.putStrLn . renderStrict . layouter (LayoutOptions (AvailablePerLine 26 1))) (vsep [hr, x, hr])

If we render this using `layoutPretty` with a page width of 26 characters per line, all the `fun` calls fit into the first line so they will be put there:

    >>> go layoutPretty doc
    |------------------------|
    fun(fun(fun(fun(fun(
                      [ abcdef
                      , ghijklm ])))))
    |------------------------|

Note that this exceeds the desired 26 character page width. The same document, rendered with ``layoutSmart``, fits the layout contstraints:

    >>> go layoutSmart doc
    |------------------------|
    fun(
      fun(
        fun(
          fun(
            fun(
              [ abcdef
              , ghijklm ])))))
    |------------------------|

The key difference between `layoutPretty` and `layoutSmart` is that the latter will check the potential document until it encounters a line with the same indentation or less than the start of the document. Any line encountered earlier is assumed to belong to the same syntactic structure. `layoutPretty` checks only the first line.

Consider for example the question of whether the `A`s fit into the document below:

    1 A
    2   A
    3  A
    4 B
    5   B

`layoutPretty` will check only line 1, ignoring whether e.g. line 2 might already be too wide. By contrast, `layoutSmart` stops only once it reaches line 4, where the `B` has the same indentation as the first `A`.

removeTrailingWhitespace :: SimpleDocStream ann -> SimpleDocStream ann #

Remove all trailing space characters.

This has some performance impact, because it does an entire additional pass over the `SimpleDocStream`.

No trimming will be done inside annotations, which are considered to contain no (trimmable) whitespace, since the annotation might actually be about the whitespace, for example a renderer that colors the background of trailing whitespace, as e.g. `git diff` can be configured to do.

Historical note: Since v1.7.0, `layoutPretty` and `layoutSmart` avoid producing the trailing whitespace that was the original motivation for creating `removeTrailingWhitespace`. See https://github.com/quchen/prettyprinter/pull/139 for some background info.

# Rendering

renderShowS :: SimpleDocStream ann -> ShowS #

Render a `SimpleDocStream` to a `ShowS`, useful to write `Show` instances based on the prettyprinter.

    instance Show MyType where
        showsPrec _ = renderShowS . layoutPretty defaultLayoutOptions . pretty

# Internal helpers

textSpaces :: Int -> Text #

A utility for producing indentation etc.

    >>> textSpaces 3
    "   "

This produces much better Core than the equivalent

    T.replicate n " "

(See https://github.com/quchen/prettyprinter/issues/131.)