-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A modern, extensible and well-documented prettyprinter. -- -- See README.md @package prettyprinter @version 0.1 -- | A strict State/Writer monad to implement a stack machine for rendering -- SimpleDocs. module Data.Text.Prettyprint.Doc.Render.Util.StackMachine -- | WriterT output StateT [style] a, but with a strict Writer -- value. -- -- The output type is used to append data chunks to, the -- style is the member of a stack of styles to model nested -- styles with. data StackMachine output style a -- | Run the renderer and retrive the writing end execStackMachine :: [styles] -> StackMachine output styles a -> (output, [styles]) -- | Add a new style to the style stack. pushStyle :: Monoid output => style -> StackMachine output style () -- | Get the topmost style. -- -- If the stack is empty, this raises an error. unsafePopStyle :: Monoid output => StackMachine output style style -- | View the topmost style, but do not modify the stack. -- -- If the stack is empty, this raises an error. unsafePeekStyle :: Monoid output => StackMachine output style style -- | Append a value to the output end. writeOutput :: output -> StackMachine output style () instance GHC.Base.Functor (Data.Text.Prettyprint.Doc.Render.Util.StackMachine.StackMachine output style) instance GHC.Base.Monoid output => GHC.Base.Applicative (Data.Text.Prettyprint.Doc.Render.Util.StackMachine.StackMachine output style) instance GHC.Base.Monoid output => GHC.Base.Monad (Data.Text.Prettyprint.Doc.Render.Util.StackMachine.StackMachine output style) module Data.Text.Prettyprint.Doc.Render.Util.Panic -- | Raise a hard error if there is a SFail in a -- SimpleDoc. panicUncaughtFail :: a -- | Raise a hard error when an annotation terminator is encountered -- in an unannotated region. panicUnpairedPop :: a -- | Raise a hard generic error when the SimpleDoc to -- SimpleDocTree conversion fails. panicSimpleDocTreeConversionFailed :: a -- | Raise a hard error when the »to SimpleDocTree« parser -- finishes without consuming the full input. panicInputNotFullyConsumed :: a -- | 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 -- Data.Text.Prettyprint.Doc.Internal.Type. module Data.Text.Prettyprint.Doc.Internal -- | 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 -- -- -- -- The simplest way to display a Doc is via the Show class. -- --
--   >>> putStrLn (show (vsep ["hello", "world"]))
--   hello
--   world
--   
data Doc ann -- | Occurs when flattening a line. The layouter will reject this document, -- choosing a more suitable rendering. Fail :: Doc ann -- | The empty document; unit of Cat (observationally) Empty :: Doc ann -- | invariant: char is not '\n' Char :: Char -> Doc ann -- | 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. Text :: !Int -> Text -> Doc ann -- | Line break Line :: Doc ann -- | Lay out the first Doc, but when flattened (via group), -- fall back to the second. The flattened version should in general be -- higher and narrower than the fallback. FlatAlt :: (Doc ann) -> (Doc ann) -> Doc ann -- | Concatenation of two documents Cat :: (Doc ann) -> (Doc ann) -> Doc ann -- | Document indented by a number of columns Nest :: !Int -> (Doc ann) -> Doc ann -- | Invariant: first lines of first '(Doc ann)' longer than the first -- lines of the second one. Used to implement layout alternatives for -- group. Union :: (Doc ann) -> (Doc ann) -> Doc ann -- | React on the current cursor position, see column Column :: (Int -> Doc ann) -> Doc ann -- | React on the document's width, see pageWidth WithPageWidth :: (PageWidth -> Doc ann) -> Doc ann -- | React on the current nesting level, see nesting Nesting :: (Int -> Doc 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. Annotated :: ann -> (Doc ann) -> Doc ann -- |
--   x <> y = hcat [x, y]
--   
-- --
--   >>> "hello" <> "world" :: Doc ann
--   helloworld
--   
-- |
--   mempty = emptyDoc
--   mconcat = hcat
--   
-- --
--   >>> mappend "hello" "world" :: Doc ann
--   helloworld
--   
-- |
--   >>> pretty ("hello\nworld")
--   hello
--   world
--   
-- -- This instance uses the Pretty Text instance, and uses -- the same newline to line conversion. -- | Overloaded conversion to Doc. class Pretty a where pretty = viaShow prettyList = list . map pretty -- |
--   >>> pretty 1 <+> pretty "hello" <+> pretty 1.234
--   1 hello 1.234
--   
pretty :: Pretty a => a -> Doc ann -- |
--   >>> pretty 1 <+> pretty "hello" <+> pretty 1.234
--   1 hello 1.234
--   
pretty :: (Pretty a, Show a) => 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]
--   
prettyList :: Pretty a => [a] -> Doc ann -- |
--   >>> pretty [1,2,3]
--   [1, 2, 3]
--   
-- | Does not change the text, but removes all annotations. Pitfall: -- since this un-annotates its argument, nesting it means multiple, -- potentially costly, traversals over the Doc. -- --
--   >>> pretty 123
--   123
--   
--   >>> pretty (pretty 123)
--   123
--   
-- |
--   >>> pretty ()
--   ()
--   
-- -- The argument is not used, -- --
--   >>> pretty (error "Strict?" :: ())
--   ()
--   
-- |
--   >>> pretty True
--   True
--   
-- | Instead of (pretty '\n'), consider using -- line as a more readable alternative. -- --
--   >>> pretty 'f' <> pretty 'o' <> pretty 'o'
--   foo
--   
--   >>> pretty ("string" :: String)
--   string
--   
-- | Convert a Showable value to a Doc. If the String -- does not contain newlines, consider using the more performant -- unsafeViaShow. viaShow :: Show a => a -> Doc ann -- | Convert a Showable value that must not contain newlines -- to a Doc. If there are newlines, use viaShow instead. unsafeViaShow :: Show a => a -> Doc ann -- |
--   >>> pretty (123 :: Int)
--   123
--   
-- |
--   >>> pretty (2^123 :: Integer)
--   10633823966279326983230456482242756608
--   
-- |
--   >>> pretty (pi :: Float)
--   3.1415927
--   
-- |
--   >>> pretty (exp 1 :: Double)
--   2.718281828459045
--   
-- |
--   >>> pretty (123, "hello")
--   (123, hello)
--   
-- |
--   >>> pretty (123, "hello", False)
--   (123, hello, False)
--   
-- | Ignore Nothings, print Just contents. -- --
--   >>> pretty (Just True)
--   True
--   
--   >>> braces (pretty (Nothing :: Maybe Bool))
--   {}
--   
-- --
--   >>> pretty [Just 1, Nothing, Just 3, Nothing]
--   [1, 3]
--   
-- | 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. -- | (lazy Text instance, identical to the strict version) -- | I tried finding a good example to show here but could not find one -- | The data type SimpleDoc represents laid out documents and is -- used by the display functions. -- -- A simplified view is that Doc = [SimpleDoc], -- and the layout functions pick one of the SimpleDocs. This means -- that SimpleDoc 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 SimpleDoc. The »Render« -- submodules provide some built-in converters to do so, and helpers to -- create own ones. data SimpleDoc ann SFail :: SimpleDoc ann SEmpty :: SimpleDoc ann SChar :: Char -> (SimpleDoc ann) -> SimpleDoc ann -- | Some layout algorithms use the Since the frequently used length -- of the Text, which scales linearly with its length, we cache it -- in this constructor. SText :: !Int -> Text -> (SimpleDoc ann) -> SimpleDoc ann -- | Int = indentation level for the line SLine :: !Int -> (SimpleDoc ann) -> SimpleDoc ann -- | Add an annotation to the remaining document. SAnnPush :: ann -> (SimpleDoc ann) -> SimpleDoc ann -- | Remove a previously pushed annotation. SAnnPop :: (SimpleDoc ann) -> SimpleDoc ann -- | (unsafeText s) contains the literal string s. -- -- The string must not contain any newline characters, since this is an -- invariant of the Text constructor. unsafeText :: Text -> 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. emptyDoc :: Doc ann -- | (nest i x) lays out the document x with the -- current indentation level 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, align and indent. nest :: Int -> Doc ann -> 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
--   
line' :: 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'
--   
softline' :: Doc ann -- | A hardline is always laid out as a line break, -- even when grouped 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
--   
hardline :: 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, 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. group :: Doc ann -> Doc ann flatten :: Doc ann -> Doc ann -- | (flatAlt x fallback) renders as x by default, -- but falls back to fallback when grouped. Since the -- layout algorithms rely on group having an effect of shortening -- the width of the contained text, careless usage of flatAlt with -- wide fallbacks might lead to unappealingly long lines. -- -- flatAlt is particularly useful for defining conditional -- separators such as -- --
--   softHyphen = flatAlt mempty "-"
--   softline   = flatAlt space line
--   
-- -- 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" <+> 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
--   
flatAlt :: Doc ann -> 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 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 vsep's -- contents all start in the same column, -- --
--   >>> "lorem" <+> align (vsep ["ipsum", "dolor"])
--   lorem ipsum
--         dolor
--   
align :: 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)
--   
hang :: Int -> Doc ann -> Doc ann -- | (indent i x) indents document x with -- i spaces, 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)
--   
indent :: Int -> Doc ann -> 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" <+> 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 aligned vertically, with separators put -- in the front: -- --
--   >>> putDocW 10 doc
--   list [1
--        ,20
--        ,300
--        ,4000]
--   
-- -- For putting separators at the end of entries instead, have a look at -- punctuate. encloseSep :: Doc ann -> Doc ann -> Doc ann -> [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 ]
--   
list :: [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 )
--   
tupled :: [Doc ann] -> Doc ann -- | (x <+> y) concatenates document x and -- y with a space in between. -- --
--   >>> "hello" <+> "world"
--   hello world
--   
-- --
--   x <+> y = x <> space <> y
--   
(<+>) :: Doc ann -> 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 alredy -- predefined, for example -- --
--   hsep    = concatWith (<+>)
--   fillSep = concatWith (\x y -> x <> softline <> y)
--   
-- -- This is also useful to define customized joiners, -- --
--   >>> concatWith (surround dot) ["Data", "Text", "Prettyprint", "Doc"]
--   Data.Text.Prettyprint.Doc
--   
concatWith :: Foldable t => (Doc ann -> Doc ann -> Doc ann) -> t (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. hsep :: [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
--   
-- -- grouping 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 grouping a vsep is rather common, sep is a -- built-in for doing that. vsep :: [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 -- grouped, 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
--   
fillSep :: [Doc ann] -> Doc ann -- | (sep xs) tries laying out the documents 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 layouts 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
--   
sep :: [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
--   
hcat :: [Doc ann] -> Doc ann -- | (vcat xs) vertically concatenates the documents -- xs. If it is grouped, the line breaks are removed. -- -- In other words vcat is like vsep, with -- newlines removed instead of replaced by spaces. -- --
--   >>> let docs = Util.words "lorem ipsum dolor"
--   
--   >>> vcat docs
--   lorem
--   ipsum
--   dolor
--   
-- -- Since grouping a vcat is rather common, cat is a -- built-in shortcut for it. vcat :: [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 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
--   
fillCat :: [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 layouts 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
--   
cat :: [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. punctuate :: Doc ann -> [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
--   
column :: (Int -> Doc ann) -> Doc ann -- | Layout a document depending on the current nesting 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]
--   
nesting :: (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
--   
width :: Doc ann -> (Int -> 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]
--   
pageWidth :: (PageWidth -> Doc ann) -> Doc ann -- | (fill i x) lays out the document 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
--   
fill :: Int -> Doc ann -> Doc ann -- | (fillBreak i x) first lays out the document -- 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 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
--   
fillBreak :: Int -> Doc ann -> Doc ann -- | Insert a number of spaces. Negative values count as 0. spaces :: Int -> Doc ann -- | (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
--   
--   >>> "The list has" <+> pretty amount <+> plural "entry" "entries" amount
--   The list has 1 entry
--   
plural :: (Num amount, Eq amount) => doc -> doc -> amount -> doc -- | (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
--   
enclose :: 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 ".") ["Data", "Text", "Prettyprint", "Doc"]
--   Data.Text.Prettyprint.Doc
--   
surround :: Doc ann -> Doc ann -> Doc ann -> Doc ann -- |
--   >>> squotes "·"
--   '·'
--   
squotes :: Doc ann -> Doc ann -- |
--   >>> dquotes "·"
--   "·"
--   
dquotes :: Doc ann -> Doc ann -- |
--   >>> parens "·"
--   (·)
--   
parens :: Doc ann -> Doc ann -- |
--   >>> angles "·"
--   <·>
--   
angles :: Doc ann -> Doc ann -- |
--   >>> brackets "·"
--   [·]
--   
brackets :: Doc ann -> Doc ann -- |
--   >>> braces "·"
--   {·}
--   
braces :: Doc ann -> Doc ann -- |
--   >>> squote
--   '
--   
squote :: Doc ann -- |
--   >>> dquote
--   "
--   
dquote :: Doc ann -- |
--   >>> lparen
--   (
--   
lparen :: Doc ann -- |
--   >>> rparen
--   )
--   
rparen :: Doc ann -- |
--   >>> langle
--   <
--   
langle :: Doc ann -- |
--   >>> rangle
--   >
--   
rangle :: Doc ann -- |
--   >>> lbracket
--   [
--   
lbracket :: Doc ann -- |
--   >>> rbracket
--   ]
--   
rbracket :: Doc ann -- |
--   >>> lbrace
--   {
--   
lbrace :: Doc ann -- |
--   >>> rbrace
--   }
--   
rbrace :: Doc ann -- |
--   >>> semi
--   ;
--   
semi :: Doc ann -- |
--   >>> colon
--   :
--   
colon :: Doc ann -- |
--   >>> comma
--   ,
--   
comma :: Doc ann -- |
--   >>> "a" <> space <> "b"
--   a b
--   
-- -- This is mostly used via <+>, -- --
--   >>> "a" <+> "b"
--   a b
--   
space :: Doc ann -- |
--   >>> dot
--   .
--   
dot :: Doc ann -- |
--   >>> slash
--   /
--   
slash :: Doc ann -- |
--   >>> backslash
--   \
--   
backslash :: Doc ann -- |
--   >>> equals
--   =
--   
equals :: Doc ann -- |
--   >>> pipe
--   |
--   
pipe :: 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 -- Data.Text.Prettyprint.Doc.Render.Tutorials.StackMachineTutorial -- or -- Data.Text.Prettyprint.Doc.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. Data.Text.Prettyprint.Doc.Render.Text, should -- be enough for the most common needs. annotate :: ann -> Doc ann -> Doc ann -- | 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. unAnnotate :: Doc ann -> Doc xxx -- | Change the annotation of a Document. -- -- Useful in particular to embed documents with one form of annotation in -- a more generlly annotated document. -- -- Since this traverses the entire Doc tree, it is preferrable to -- reannotate after producing the layout by using reAnnotateS. -- -- Technically reAnnotate makes Doc a Functor, but -- since reannotation is hardly intuitive we omit the instance. reAnnotate :: (ann -> ann') -> Doc ann -> Doc ann' -- | Remove all annotations. unAnnotate for SimpleDoc. unAnnotateS :: SimpleDoc ann -> SimpleDoc xxx -- | Change the annotation of a document. reAnnotate for -- SimpleDoc. reAnnotateS :: (ann -> ann') -> SimpleDoc ann -> SimpleDoc ann' -- | Fusion depth parameter, used by fuse. data FusionDepth -- | Do not dive deep into nested documents, fusing mostly concatenations -- of text nodes together. Shallow :: FusionDepth -- | 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. Deep :: FusionDepth -- | (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 Document out to a SimpleDoc, 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 SimpleDoc, although -- this is fully equivalent to the tightly packed -- --
--   >>> "abcd" :: Doc ann
--   abcd
--   
-- -- which is only a single SimpleDoc 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
--   
fuse :: FusionDepth -> Doc ann -> Doc ann -- | Decide whether a SimpleDoc fits the constraints given, namely -- -- newtype FittingPredicate ann FP :: (PageWidth -> Int -> Maybe Int -> SimpleDoc ann -> Bool) -> FittingPredicate ann -- | List of nesting level/document pairs yet to be laid out. data LayoutPipeline ann Nil :: LayoutPipeline ann Cons :: !Int -> (Doc ann) -> (LayoutPipeline ann) -> LayoutPipeline ann UndoAnn :: (LayoutPipeline ann) -> LayoutPipeline ann -- | 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'). data PageWidth -- | Layouters should not exceed the specified space per line. -- -- AvailablePerLine :: Int -> Double -> PageWidth -- | Layouters should not introduce line breaks on their own. Unbounded :: PageWidth -- | Options to influence the layout algorithms. newtype LayoutOptions LayoutOptions :: PageWidth -> LayoutOptions [layoutPageWidth] :: LayoutOptions -> PageWidth -- | 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 0.4}
--   
defaultLayoutOptions :: LayoutOptions -- | 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 SimpleDoc 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. layoutPretty :: LayoutOptions -> Doc ann -> SimpleDoc 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. -- -- Considre the following python-ish document, -- --
--   >>> let fun x = hang 2 ("fun(" <> softline' <> x) <> ")"
--   
--   >>> let doc = (fun . fun . fun . fun . fun) (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 Data.Text.Prettyprint.Doc.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 up to the end of the current indentation level, -- instead of just having one element lookahead. layoutSmart :: LayoutOptions -> Doc ann -> SimpleDoc ann layoutFits :: forall ann. FittingPredicate ann -> LayoutOptions -> Doc ann -> SimpleDoc ann -- | (layoutCompact x) lays out the document x without -- adding any indentation. 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. -- -- This layout function does not add any colorisation information. -- --
--   >>> 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
--   
layoutCompact :: Doc ann -> SimpleDoc ann -- | (show doc) prettyprints document doc with -- defaultLayoutOptions, ignoring all annotations. -- | Render a SimpleDoc to a ShowS, useful to write -- Show instances based on the prettyprinter. -- --
--   instance Show MyType where
--       showsPrec _ = renderShowS . layoutPretty defaultLayoutOptions . pretty
--   
renderShowS :: SimpleDoc ann -> ShowS instance GHC.Show.Show Data.Text.Prettyprint.Doc.Internal.LayoutOptions instance GHC.Classes.Ord Data.Text.Prettyprint.Doc.Internal.LayoutOptions instance GHC.Classes.Eq Data.Text.Prettyprint.Doc.Internal.LayoutOptions instance GHC.Show.Show Data.Text.Prettyprint.Doc.Internal.PageWidth instance GHC.Classes.Ord Data.Text.Prettyprint.Doc.Internal.PageWidth instance GHC.Classes.Eq Data.Text.Prettyprint.Doc.Internal.PageWidth instance GHC.Show.Show Data.Text.Prettyprint.Doc.Internal.FusionDepth instance GHC.Classes.Ord Data.Text.Prettyprint.Doc.Internal.FusionDepth instance GHC.Classes.Eq Data.Text.Prettyprint.Doc.Internal.FusionDepth instance GHC.Show.Show ann => GHC.Show.Show (Data.Text.Prettyprint.Doc.Internal.SimpleDoc ann) instance GHC.Classes.Ord ann => GHC.Classes.Ord (Data.Text.Prettyprint.Doc.Internal.SimpleDoc ann) instance GHC.Classes.Eq ann => GHC.Classes.Eq (Data.Text.Prettyprint.Doc.Internal.SimpleDoc ann) instance Data.Semigroup.Semigroup (Data.Text.Prettyprint.Doc.Internal.Doc ann) instance GHC.Base.Monoid (Data.Text.Prettyprint.Doc.Internal.Doc ann) instance Data.String.IsString (Data.Text.Prettyprint.Doc.Internal.Doc ann) instance Data.Text.Prettyprint.Doc.Internal.Pretty a => Data.Text.Prettyprint.Doc.Internal.Pretty [a] instance Data.Text.Prettyprint.Doc.Internal.Pretty a => Data.Text.Prettyprint.Doc.Internal.Pretty (Data.List.NonEmpty.NonEmpty a) instance Data.Text.Prettyprint.Doc.Internal.Pretty (Data.Text.Prettyprint.Doc.Internal.Doc ann) instance Data.Text.Prettyprint.Doc.Internal.Pretty () instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Types.Bool instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Types.Char instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Types.Int instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Int.Int8 instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Int.Int16 instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Int.Int32 instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Int.Int64 instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Types.Word instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Word.Word8 instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Word.Word16 instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Word.Word32 instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Word.Word64 instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Integer.Type.Integer instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Natural.Natural instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Types.Float instance Data.Text.Prettyprint.Doc.Internal.Pretty GHC.Types.Double instance (Data.Text.Prettyprint.Doc.Internal.Pretty a1, Data.Text.Prettyprint.Doc.Internal.Pretty a2) => Data.Text.Prettyprint.Doc.Internal.Pretty (a1, a2) instance (Data.Text.Prettyprint.Doc.Internal.Pretty a1, Data.Text.Prettyprint.Doc.Internal.Pretty a2, Data.Text.Prettyprint.Doc.Internal.Pretty a3) => Data.Text.Prettyprint.Doc.Internal.Pretty (a1, a2, a3) instance Data.Text.Prettyprint.Doc.Internal.Pretty a => Data.Text.Prettyprint.Doc.Internal.Pretty (GHC.Base.Maybe a) instance Data.Text.Prettyprint.Doc.Internal.Pretty Data.Text.Internal.Text instance Data.Text.Prettyprint.Doc.Internal.Pretty Data.Text.Internal.Lazy.Text instance Data.Text.Prettyprint.Doc.Internal.Pretty Data.Void.Void instance GHC.Show.Show (Data.Text.Prettyprint.Doc.Internal.Doc ann) -- | Internal module with stability guarantees -- -- This module exposes the internals of the Doc type so -- other libraries can write adaptors to/from it. For all other uses, -- please use only the API provided by non-internal modules. -- -- Although this module is internal, it follows the usual package -- versioning policy, AKA Haskell’s version of semantic versioning. In -- other words, this module is as stable as the public API. module Data.Text.Prettyprint.Doc.Internal.Type -- | 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 -- -- -- -- The simplest way to display a Doc is via the Show class. -- --
--   >>> putStrLn (show (vsep ["hello", "world"]))
--   hello
--   world
--   
data Doc ann -- | Occurs when flattening a line. The layouter will reject this document, -- choosing a more suitable rendering. Fail :: Doc ann -- | The empty document; unit of Cat (observationally) Empty :: Doc ann -- | invariant: char is not '\n' Char :: Char -> Doc ann -- | 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. Text :: !Int -> Text -> Doc ann -- | Line break Line :: Doc ann -- | Lay out the first Doc, but when flattened (via group), -- fall back to the second. The flattened version should in general be -- higher and narrower than the fallback. FlatAlt :: (Doc ann) -> (Doc ann) -> Doc ann -- | Concatenation of two documents Cat :: (Doc ann) -> (Doc ann) -> Doc ann -- | Document indented by a number of columns Nest :: !Int -> (Doc ann) -> Doc ann -- | Invariant: first lines of first '(Doc ann)' longer than the first -- lines of the second one. Used to implement layout alternatives for -- group. Union :: (Doc ann) -> (Doc ann) -> Doc ann -- | React on the current cursor position, see column Column :: (Int -> Doc ann) -> Doc ann -- | React on the document's width, see pageWidth WithPageWidth :: (PageWidth -> Doc ann) -> Doc ann -- | React on the current nesting level, see nesting Nesting :: (Int -> Doc 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. Annotated :: ann -> (Doc ann) -> Doc ann module Data.Text.Prettyprint.Doc.Render.ShowS -- | Render a SimpleDoc to a ShowS, useful to write -- Show instances based on the prettyprinter. -- --
--   instance Show MyType where
--       showsPrec _ = renderShowS . layoutPretty defaultLayoutOptions . pretty
--   
renderShowS :: SimpleDoc ann -> ShowS -- |

Overview

-- -- This module defines a prettyprinter to format text in a flexible and -- convenient way. The idea is to combine a Document out of many -- small components, then using a layouter to convert it to an easily -- renderable SimpleDoc, which can then be rendered to a variety -- of formats, for example plain Text. -- -- The documentation consists of several parts: -- --
    --
  1. Just below is some general information about the library.
  2. --
  3. The actual library with extensive documentation and examples
  4. --
  5. Migration guide for users familiar with (ansi-)wl-pprint
  6. --
-- --

Starting out

-- -- As a reading list for starters, some of the most commonly used -- functions in this module include <>, hsep, -- <+>, vsep, align, hang. These cover -- many use cases already, and many other functions are variations or -- combinations of these. -- --

Simple example

-- -- Let’s prettyprint a simple Haskell type definition. First, intersperse -- -> and add a leading ::, -- --
--   >>> let prettyType = align . sep . zipWith (<+>) ("::" : repeat "->")
--   
-- -- The sep function is one way of concatenating documents, there -- are multiple others, e.g. vsep, cat and fillSep. -- In our case, sep space-separates all entries if there is space, -- and newlines if the remaining line is too short. -- -- Second, prepend the name to the type, -- --
--   >>> let prettyDecl n tys = pretty n <+> prettyType tys
--   
-- -- Now we can define a document that contains some type signature: -- --
--   >>> let doc = prettyDecl "example" ["Int", "Bool", "Char", "IO ()"]
--   
-- -- This document can now be printed, and it automatically adapts to -- available space. If the page is wide enough (80 characters in this -- case), the definitions are space-separated, -- --
--   >>> putDocW 80 doc
--   example :: Int -> Bool -> Char -> IO ()
--   
-- -- If we narrow the page width to only 20 characters, the same -- document renders vertically aligned: -- --
--   >>> putDocW 20 doc
--   example :: Int
--           -> Bool
--           -> Char
--           -> IO ()
--   
-- -- Speaking of alignment, had we not used align, the -- -> would be at the beginning of each line, and not beneath -- the ::. -- --

General workflow

-- --
--   ╭───────────────╮      ╭───────────────────╮
--   │ vsep, pretty, │      │        Doc        │
--   │ <+>, nest,    ├─────▷│  (rich document)  │
--   │ align, …      │      ╰─────────┬─────────╯
--   ╰───────────────╯                │
--                                    │ Layout algorithms
--                                    │ e.g. layoutPretty
--                                    ▽
--                          ╭───────────────────╮
--                          │     SimpleDoc     │
--                          │ (simple document) │
--                          ╰─────────┬─────────╯
--                                    │
--                                    │ Renderers
--                                    │
--                ╭───────────────────┼───────────────────╮
--                │                   │                   │
--                ▽                   ▽                   ▽
--        ╭───────────────╮   ╭───────────────╮   ╭───────────────╮
--        │  Plain Text   │   │ ANSI terminal │   │ other/custom  │
--        ╰───────────────╯   ╰───────────────╯   ╰───────────────╯
--   
-- --

How the layout works

-- -- There are two key concepts to laying a document out: the available -- width, and grouping. -- --

Available width

-- -- The page has a certain maximum width, which the layouter tries to not -- exceed, by inserting line breaks where possible. The functions given -- in this module make it fairly straightforward to specify where, and -- under what circumstances, such a line break may be inserted by the -- layouter, for example via the sep function. -- -- There is also the concept of ribbon width. The ribbon is the -- part of a line that is printed, i.e. the line length without the -- leading indentation. The layouters take a ribbon fraction argument, -- which specifies how much of a line should be filled before trying to -- break it up. A ribbon width of 0.5 in a document of width 80 will -- result in the layouter to try to not exceed 0.5*80 = 40 -- (ignoring current indentation depth). -- --

Grouping

-- -- A document can be grouped, which tells the layouter that it -- should attempt to collapse it to a single line. If the result does not -- fit within the constraints (given by page and ribbon widths), the -- document is rendered unaltered. This allows fallback definitions, so -- that we get nice results even when the original document would exceed -- the layout constraints. module Data.Text.Prettyprint.Doc -- | 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 -- -- -- -- The simplest way to display a Doc is via the Show class. -- --
--   >>> putStrLn (show (vsep ["hello", "world"]))
--   hello
--   world
--   
data Doc ann -- | Overloaded conversion to Doc. class Pretty a where pretty = viaShow prettyList = list . map pretty -- |
--   >>> pretty 1 <+> pretty "hello" <+> pretty 1.234
--   1 hello 1.234
--   
pretty :: Pretty a => a -> Doc ann -- |
--   >>> pretty 1 <+> pretty "hello" <+> pretty 1.234
--   1 hello 1.234
--   
pretty :: (Pretty a, Show a) => 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]
--   
prettyList :: Pretty a => [a] -> 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. emptyDoc :: Doc ann -- | (nest i x) lays out the document x with the -- current indentation level 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, align and indent. nest :: Int -> Doc ann -> 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
--   
line' :: 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'
--   
softline' :: Doc ann -- | A hardline is always laid out as a line break, -- even when grouped 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
--   
hardline :: 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, 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. group :: Doc ann -> Doc ann -- | (flatAlt x fallback) renders as x by default, -- but falls back to fallback when grouped. Since the -- layout algorithms rely on group having an effect of shortening -- the width of the contained text, careless usage of flatAlt with -- wide fallbacks might lead to unappealingly long lines. -- -- flatAlt is particularly useful for defining conditional -- separators such as -- --
--   softHyphen = flatAlt mempty "-"
--   softline   = flatAlt space line
--   
-- -- 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" <+> 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
--   
flatAlt :: Doc ann -> 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 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 vsep's -- contents all start in the same column, -- --
--   >>> "lorem" <+> align (vsep ["ipsum", "dolor"])
--   lorem ipsum
--         dolor
--   
align :: 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)
--   
hang :: Int -> Doc ann -> Doc ann -- | (indent i x) indents document x with -- i spaces, 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)
--   
indent :: Int -> Doc ann -> 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" <+> 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 aligned vertically, with separators put -- in the front: -- --
--   >>> putDocW 10 doc
--   list [1
--        ,20
--        ,300
--        ,4000]
--   
-- -- For putting separators at the end of entries instead, have a look at -- punctuate. encloseSep :: Doc ann -> Doc ann -> Doc ann -> [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 ]
--   
list :: [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 )
--   
tupled :: [Doc ann] -> Doc ann -- | An associative operation. -- --
--   (a <> b) <> c = a <> (b <> c)
--   
-- -- If a is also a Monoid we further require -- --
--   (<>) = mappend
--   
(<>) :: Semigroup a => a -> a -> a -- | (x <+> y) concatenates document x and -- y with a space in between. -- --
--   >>> "hello" <+> "world"
--   hello world
--   
-- --
--   x <+> y = x <> space <> y
--   
(<+>) :: Doc ann -> 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 alredy -- predefined, for example -- --
--   hsep    = concatWith (<+>)
--   fillSep = concatWith (\x y -> x <> softline <> y)
--   
-- -- This is also useful to define customized joiners, -- --
--   >>> concatWith (surround dot) ["Data", "Text", "Prettyprint", "Doc"]
--   Data.Text.Prettyprint.Doc
--   
concatWith :: Foldable t => (Doc ann -> Doc ann -> Doc ann) -> t (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. hsep :: [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
--   
-- -- grouping 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 grouping a vsep is rather common, sep is a -- built-in for doing that. vsep :: [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 -- grouped, 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
--   
fillSep :: [Doc ann] -> Doc ann -- | (sep xs) tries laying out the documents 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 layouts 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
--   
sep :: [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
--   
hcat :: [Doc ann] -> Doc ann -- | (vcat xs) vertically concatenates the documents -- xs. If it is grouped, the line breaks are removed. -- -- In other words vcat is like vsep, with -- newlines removed instead of replaced by spaces. -- --
--   >>> let docs = Util.words "lorem ipsum dolor"
--   
--   >>> vcat docs
--   lorem
--   ipsum
--   dolor
--   
-- -- Since grouping a vcat is rather common, cat is a -- built-in shortcut for it. vcat :: [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 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
--   
fillCat :: [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 layouts 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
--   
cat :: [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. punctuate :: Doc ann -> [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
--   
column :: (Int -> Doc ann) -> Doc ann -- | Layout a document depending on the current nesting 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]
--   
nesting :: (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
--   
width :: Doc ann -> (Int -> 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]
--   
pageWidth :: (PageWidth -> Doc ann) -> Doc ann -- | (fill i x) lays out the document 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
--   
fill :: Int -> Doc ann -> Doc ann -- | (fillBreak i x) first lays out the document -- 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 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
--   
fillBreak :: Int -> Doc ann -> Doc ann -- | (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
--   
--   >>> "The list has" <+> pretty amount <+> plural "entry" "entries" amount
--   The list has 1 entry
--   
plural :: (Num amount, Eq amount) => doc -> doc -> amount -> doc -- | (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
--   
enclose :: 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 ".") ["Data", "Text", "Prettyprint", "Doc"]
--   Data.Text.Prettyprint.Doc
--   
surround :: Doc ann -> Doc ann -> Doc ann -> Doc ann -- |
--   >>> squotes "·"
--   '·'
--   
squotes :: Doc ann -> Doc ann -- |
--   >>> dquotes "·"
--   "·"
--   
dquotes :: Doc ann -> Doc ann -- |
--   >>> parens "·"
--   (·)
--   
parens :: Doc ann -> Doc ann -- |
--   >>> angles "·"
--   <·>
--   
angles :: Doc ann -> Doc ann -- |
--   >>> brackets "·"
--   [·]
--   
brackets :: Doc ann -> Doc ann -- |
--   >>> braces "·"
--   {·}
--   
braces :: Doc ann -> Doc ann -- |
--   >>> lparen
--   (
--   
lparen :: Doc ann -- |
--   >>> rparen
--   )
--   
rparen :: Doc ann -- |
--   >>> langle
--   <
--   
langle :: Doc ann -- |
--   >>> rangle
--   >
--   
rangle :: Doc ann -- |
--   >>> lbrace
--   {
--   
lbrace :: Doc ann -- |
--   >>> rbrace
--   }
--   
rbrace :: Doc ann -- |
--   >>> lbracket
--   [
--   
lbracket :: Doc ann -- |
--   >>> rbracket
--   ]
--   
rbracket :: Doc ann -- |
--   >>> squote
--   '
--   
squote :: Doc ann -- |
--   >>> dquote
--   "
--   
dquote :: Doc ann -- |
--   >>> semi
--   ;
--   
semi :: Doc ann -- |
--   >>> colon
--   :
--   
colon :: Doc ann -- |
--   >>> comma
--   ,
--   
comma :: Doc ann -- |
--   >>> "a" <> space <> "b"
--   a b
--   
-- -- This is mostly used via <+>, -- --
--   >>> "a" <+> "b"
--   a b
--   
space :: Doc ann -- |
--   >>> dot
--   .
--   
dot :: Doc ann -- |
--   >>> slash
--   /
--   
slash :: Doc ann -- |
--   >>> backslash
--   \
--   
backslash :: Doc ann -- |
--   >>> equals
--   =
--   
equals :: Doc ann -- |
--   >>> pipe
--   |
--   
pipe :: 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 -- Data.Text.Prettyprint.Doc.Render.Tutorials.StackMachineTutorial -- or -- Data.Text.Prettyprint.Doc.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. Data.Text.Prettyprint.Doc.Render.Text, should -- be enough for the most common needs. annotate :: ann -> Doc ann -> Doc ann -- | 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. unAnnotate :: Doc ann -> Doc xxx -- | Change the annotation of a Document. -- -- Useful in particular to embed documents with one form of annotation in -- a more generlly annotated document. -- -- Since this traverses the entire Doc tree, it is preferrable to -- reannotate after producing the layout by using reAnnotateS. -- -- Technically reAnnotate makes Doc a Functor, but -- since reannotation is hardly intuitive we omit the instance. reAnnotate :: (ann -> ann') -> Doc ann -> Doc ann' -- | Remove all annotations. unAnnotate for SimpleDoc. unAnnotateS :: SimpleDoc ann -> SimpleDoc xxx -- | Change the annotation of a document. reAnnotate for -- SimpleDoc. reAnnotateS :: (ann -> ann') -> SimpleDoc ann -> SimpleDoc 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 Document out to a SimpleDoc, 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 SimpleDoc, although -- this is fully equivalent to the tightly packed -- --
--   >>> "abcd" :: Doc ann
--   abcd
--   
-- -- which is only a single SimpleDoc 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
--   
fuse :: FusionDepth -> Doc ann -> Doc ann -- | Fusion depth parameter, used by fuse. data FusionDepth -- | Do not dive deep into nested documents, fusing mostly concatenations -- of text nodes together. Shallow :: FusionDepth -- | 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. Deep :: FusionDepth -- | The data type SimpleDoc represents laid out documents and is -- used by the display functions. -- -- A simplified view is that Doc = [SimpleDoc], -- and the layout functions pick one of the SimpleDocs. This means -- that SimpleDoc 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 SimpleDoc. The »Render« -- submodules provide some built-in converters to do so, and helpers to -- create own ones. data SimpleDoc ann SFail :: SimpleDoc ann SEmpty :: SimpleDoc ann SChar :: Char -> (SimpleDoc ann) -> SimpleDoc ann -- | Some layout algorithms use the Since the frequently used length -- of the Text, which scales linearly with its length, we cache it -- in this constructor. SText :: !Int -> Text -> (SimpleDoc ann) -> SimpleDoc ann -- | Int = indentation level for the line SLine :: !Int -> (SimpleDoc ann) -> SimpleDoc ann -- | Add an annotation to the remaining document. SAnnPush :: ann -> (SimpleDoc ann) -> SimpleDoc ann -- | Remove a previously pushed annotation. SAnnPop :: (SimpleDoc ann) -> SimpleDoc ann -- | 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'). data PageWidth -- | Layouters should not exceed the specified space per line. -- -- AvailablePerLine :: Int -> Double -> PageWidth -- | Layouters should not introduce line breaks on their own. Unbounded :: PageWidth -- | Options to influence the layout algorithms. newtype LayoutOptions LayoutOptions :: PageWidth -> LayoutOptions [layoutPageWidth] :: LayoutOptions -> PageWidth -- | 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 0.4}
--   
defaultLayoutOptions :: LayoutOptions -- | 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 SimpleDoc 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. layoutPretty :: LayoutOptions -> Doc ann -> SimpleDoc ann -- | (layoutCompact x) lays out the document x without -- adding any indentation. 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. -- -- This layout function does not add any colorisation information. -- --
--   >>> 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
--   
layoutCompact :: Doc ann -> SimpleDoc 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. -- -- Considre the following python-ish document, -- --
--   >>> let fun x = hang 2 ("fun(" <> softline' <> x) <> ")"
--   
--   >>> let doc = (fun . fun . fun . fun . fun) (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 Data.Text.Prettyprint.Doc.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 up to the end of the current indentation level, -- instead of just having one element lookahead. layoutSmart :: LayoutOptions -> Doc ann -> SimpleDoc ann -- | Render an unannotated SimpleDoc as plain Text. module Data.Text.Prettyprint.Doc.Render.Text -- | (renderLazy sdoc) takes the output sdoc from -- a rendering function and transforms it to lazy text. -- --
--   >>> let render = TL.putStrLn . renderLazy . layoutPretty defaultLayoutOptions
--   
--   >>> let doc = "lorem" <+> align (vsep ["ipsum dolor", parens "foo bar", "sit amet"])
--   
--   >>> render doc
--   lorem ipsum dolor
--         (foo bar)
--         sit amet
--   
renderLazy :: SimpleDoc ann -> Text -- | (renderLazy sdoc) takes the output sdoc from -- a rendering and transforms it to strict text. renderStrict :: SimpleDoc ann -> Text -- | (renderIO h sdoc) writes sdoc to the file -- h. -- --
--   >>> renderIO System.IO.stdout (layoutPretty defaultLayoutOptions "hello\nworld")
--   hello
--   world
--   
renderIO :: Handle -> SimpleDoc ann -> IO () -- | (putDoc doc) prettyprints document doc to -- standard output. Uses the defaultLayoutOptions. -- --
--   >>> putDoc ("hello" <+> "world")
--   hello world
--   
-- --
--   putDoc = hPutDoc stdout
--   
putDoc :: Doc ann -> IO () -- | Like putDoc, but instead of using stdout, print to a -- user-provided handle, e.g. a file or a socket. Uses the -- defaultLayoutOptions. -- --
--   main = withFile filename (h -> hPutDoc h doc)
--     where
--       doc = vcat ["vertical", "text"]
--       filename = "someFile.txt"
--   
-- --
--   hPutDoc h doc = renderIO h (layoutPretty defaultLayoutOptions doc)
--   
hPutDoc :: Handle -> Doc ann -> IO () -- | This module shows how to write a custom prettyprinter backend, based -- on directly converting a SimpleDoc to an output format using a -- stack machine. For a tree serialization approach, which may be more -- suitable for certain output formats, see -- Data.Text.Prettyprint.Doc.Render.Tutorials.TreeRenderingTutorial. -- -- Rendering to ANSI terminal with colors is an important use case for -- stack machine based rendering. -- -- The module is written to be readable top-to-bottom in both Haddock and -- raw source form. module Data.Text.Prettyprint.Doc.Render.Tutorials.StackMachineTutorial data SimpleHtml Bold :: SimpleHtml Italics :: SimpleHtml Color :: Color -> SimpleHtml Paragraph :: SimpleHtml Headline :: SimpleHtml data Color Red :: Color Green :: Color Blue :: 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 -- | The StackMachine type defines a stack machine suitable for many -- rendering needs. It has two auxiliary parameters: the type of the end -- result, and the type of the document’s annotations. -- -- Most StackMachine creations will look like this definition: a -- recursive walk through the SimpleDoc, pushing styles on the -- stack and popping them off again, and writing raw output. -- -- The equivalent to this in the tree based rendering approach is -- renderTree. renderStackMachine :: SimpleDoc SimpleHtml -> StackMachine Builder SimpleHtml () -- | Convert a SimpleHtml annotation to a pair of opening and -- closing tags. This is where the translation of style to raw output -- happens. htmlTag :: SimpleHtml -> (Builder, Builder) -- | We can now wrap our stack machine definition from -- renderStackMachine in a nicer interface; on successful -- conversion, we run the builder to give us the final Text, and -- before we do that we check that the style stack is empty (i.e. there -- are no unmatched style applications) after the machine is run. -- -- This function does only a bit of plumbing around -- renderStackMachine, and is the main API function of a stack -- machine renderer. The tree renderer equivalent to this is -- render. render :: SimpleDoc SimpleHtml -> Text -- | Conversion of the linked-list-like SimpleDoc to a tree-like -- SimpleDocTree. module Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree -- | A SimpleDoc is a linked list of different annotated cons cells -- (SText and then some further SimpleDoc, SLine and -- then some further SimpleDoc, …). This format is very suitable -- as a target for a layout engine, but not very useful for rendering to -- a structured format such as HTML, where we don’t want to do a -- lookahead until the end of some markup. These formats benefit from a -- tree-like structure that explicitly marks its contents as annotated. -- SimpleDocTree is that format. data SimpleDocTree ann STEmpty :: SimpleDocTree ann STChar :: Char -> SimpleDocTree ann STText :: !Int -> Text -> SimpleDocTree ann STLine :: !Int -> SimpleDocTree ann STAnn :: ann -> (SimpleDocTree ann) -> SimpleDocTree ann STConcat :: [SimpleDocTree ann] -> SimpleDocTree ann -- | Convert a SimpleDoc to its SimpleDocTree representation. treeForm :: SimpleDoc ann -> SimpleDocTree ann -- | Remove all annotations. unAnnotate for SimpleDocTree. unAnnotateST :: SimpleDocTree ann -> SimpleDocTree xxx -- | Change the annotation of a document. reAnnotate for -- SimpleDocTree. reAnnotateST :: (ann -> ann') -> SimpleDocTree ann -> SimpleDocTree ann' instance GHC.Show.Show ann => GHC.Show.Show (Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree.SimpleDocTree ann) instance GHC.Classes.Ord ann => GHC.Classes.Ord (Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree.SimpleDocTree ann) instance GHC.Classes.Eq ann => GHC.Classes.Eq (Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree.SimpleDocTree ann) instance GHC.Show.Show ann => GHC.Show.Show (Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree.SimpleDocTok ann) instance GHC.Classes.Ord ann => GHC.Classes.Ord (Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree.SimpleDocTok ann) instance GHC.Classes.Eq ann => GHC.Classes.Eq (Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree.SimpleDocTok ann) instance GHC.Base.Functor (Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree.UniqueParser s) instance GHC.Base.Applicative (Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree.UniqueParser s) instance GHC.Base.Monad (Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree.UniqueParser s) instance Control.Monad.Fail.MonadFail (Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree.UniqueParser s) instance GHC.Base.Alternative (Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree.UniqueParser s) -- | This module shows how to write a custom prettyprinter backend, based -- on a tree representation of a SimpleDoc. For a stack machine -- approach, which may be more suitable for certain output formats, see -- Data.Text.Prettyprint.Doc.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. module Data.Text.Prettyprint.Doc.Render.Tutorials.TreeRenderingTutorial data SimpleHtml Bold :: SimpleHtml Italics :: SimpleHtml Color :: Color -> SimpleHtml Paragraph :: SimpleHtml Headline :: SimpleHtml data Color Red :: Color Green :: Color Blue :: 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 -- | To render the HTML, we first convert the SimpleDoc 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. render :: SimpleDoc SimpleHtml -> Text -- | 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. renderTree :: SimpleDocTree SimpleHtml -> Builder -- | Convert a SimpleHtml to a function that encloses a -- Builder in HTML tags. This is where the translation of style to -- raw output happens. encloseInTagFor :: SimpleHtml -> Builder -> Builder -- | Frequently useful definitions for working with general prettyprinters. module Data.Text.Prettyprint.Doc.Util -- | Split an input into word-sized Docs. -- --
--   >>> putDoc (tupled (words "Lorem ipsum dolor"))
--   (Lorem, ipsum, dolor)
--   
words :: Text -> [Doc ann] -- | Insert soft linebreaks between words, so that text is broken into -- multiple lines when it exceeds the available width. -- --
--   >>> putDocW 32 (reflow "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
--   Lorem ipsum dolor sit amet,
--   consectetur adipisicing elit,
--   sed do eiusmod tempor incididunt
--   ut labore et dolore magna
--   aliqua.
--   
-- --
--   reflow = fillSep . words
--   
reflow :: Text -> Doc ann -- | Render a document with a certain width. Useful for quick-and-dirty -- testing of layout behaviour. Used heavily in the doctests of this -- package, for example. -- --
--   >>> let doc = reflow "Lorem ipsum dolor sit amet, consectetur adipisicing elit"
--   
--   >>> putDocW 20 doc
--   Lorem ipsum dolor
--   sit amet,
--   consectetur
--   adipisicing elit
--   
--   >>> putDocW 30 doc
--   Lorem ipsum dolor sit amet,
--   consectetur adipisicing elit
--   
putDocW :: Int -> Doc ann -> IO ()