2 {-# LANGUAGE FlexibleInstances #-}
3 {-# LANGUAGE MultiParamTypeClasses #-}
4 -----------------------------------------------------------------------------
6 -- Module : Hcompta.Lib.Leijen
7 -- Copyright : Julien Moutinho <julm+hcompta@autogeree.net> (c) 2015,
8 -- Ivan Lazar Miljenovic <Ivan.Miljenovic@gmail.com> (c) 2010,
9 -- Daan Leijen (c) 2000, http://www.cs.uu.nl/~daan
10 -- License : BSD-style
12 -- Stability : provisional
13 -- Portability : portable
15 -- This module is a merge between /wl-pprint-text/ and /ansi-wl-pprint/ packages
16 -- to use 'Text' values rather than 'String's and ANSI formatting.
18 -- Pretty print module based on Philip Wadler's \"prettier printer\"
21 -- \"A prettier printer\"
22 -- Draft paper, April 1997, revised March 1998.
23 -- <http://cm.bell-labs.com/cm/cs/who/wadler/papers/prettier/prettier.ps>
26 -- PPrint is an implementation of the pretty printing combinators
27 -- described by Philip Wadler (1997). In their bare essence, the
28 -- combinators of Wadler are not expressive enough to describe some
29 -- commonly occurring layouts. The PPrint library adds new primitives
30 -- to describe these layouts and works well in practice.
32 -- The library is based on a single way to concatenate documents,
33 -- which is associative and has both a left and right unit. This
34 -- simple design leads to an efficient and short implementation. The
35 -- simplicity is reflected in the predictable behaviour of the
36 -- combinators which make them easy to use in practice.
38 -- A thorough description of the primitive combinators and their
39 -- implementation can be found in Philip Wadler's paper
40 -- (1997). Additions and the main differences with his original paper
43 -- * The nil document is called empty.
45 -- * The above combinator is called '<$>'. The operator '</>' is used
46 -- for soft line breaks.
48 -- * There are three new primitives: 'align', 'fill' and
49 -- 'fillBreak'. These are very useful in practice.
51 -- * Lots of other useful combinators, like 'fillSep' and 'list'.
53 -- * There are two renderers, 'renderPretty' for pretty printing and
54 -- 'renderCompact' for compact output. The pretty printing algorithm
55 -- also uses a ribbon-width now for even prettier output.
57 -- * There are two displayers, 'displayT' for 'Text' values and 'displayIO'
58 -- for file based output.
60 -- * There is a 'Pretty' class.
62 -- * The implementation uses optimised representations and strictness
65 -- Ways that this library differs from /wl-pprint/ (apart from using
66 -- 'Text' rather than 'String'):
68 -- * Smarter treatment of 'empty' sub-documents (partially copied over
69 -- from the /pretty/ library).
70 -----------------------------------------------------------
71 module Hcompta.Lib.Leijen (
75 -- * Basic combinators
76 empty, char, text, strict_text, (<>), nest, line, linebreak, group, softline,
77 softbreak, spacebreak, renderSmart,
86 -- | The combinators in this section can not be described by Wadler's
87 -- original combinators. They align their output relative to the
88 -- current output position - in contrast to @nest@ which always
89 -- aligns to the current nesting level. This deprives these
90 -- combinators from being \`optimal\'. In practice however they
91 -- prove to be very useful. The combinators in this section should
92 -- be used with care, since they are more expensive than the other
93 -- combinators. For example, @align@ shouldn't be used to pretty
94 -- print all top-level declarations of a language, but using @hang@
95 -- for let expressions is fine.
96 align, hang, indent, encloseSep, list, tupled, semiBraces,
99 (<+>), (<++>), (<$>), (</>), (<$$>), (<//>),
101 -- * List combinators
102 hsep, vsep, fillSep, sep, hcat, vcat, fillCat, cat, punctuate, intercalate,
107 -- * Bracketing combinators
108 enclose, squotes, dquotes, parens, angles, braces, brackets,
110 -- * Character documents
111 lparen, rparen, langle, rangle, lbrace, rbrace, lbracket, rbracket,
112 squote, dquote, semi, colon, comma, space, dot, backslash, equals,
114 -- * Colorisation combinators
115 black, red, green, yellow, blue, magenta, cyan, white,
116 dullblack, dullred, dullgreen, dullyellow, dullblue, dullmagenta, dullcyan, dullwhite,
117 onblack, onred, ongreen, onyellow, onblue, onmagenta, oncyan, onwhite,
118 ondullblack, ondullred, ondullgreen, ondullyellow, ondullblue, ondullmagenta, ondullcyan, ondullwhite,
120 -- * Emboldening combinators
123 -- * Underlining combinators
124 underline, deunderline,
126 -- * Removing formatting
129 -- * Primitive type documents
130 string, int, integer, float, double, rational, bool,
132 -- * Position-based combinators
133 column, nesting, width,
139 SimpleDoc(..), renderPretty, renderCompact, renderOneLine,
140 displayB, displayT, displayIO, putDoc, hPutDoc,
144 #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 710
145 import Prelude hiding ((<$>))
148 import Data.String (IsString (..))
149 import System.IO (Handle, hPutChar, stdout)
150 import System.Console.ANSI (Color(..), ColorIntensity(..), ConsoleLayer(..),
151 Underlining(..), ConsoleIntensity(..),
152 SGR(..), hSetSGR, setSGRCode)
154 import Data.Int (Int64)
155 import Data.Maybe (catMaybes)
156 import Data.Monoid ((<>))
157 import qualified Data.Foldable (Foldable(..))
158 import qualified Data.Text (Text)
159 import Data.Text.Lazy (Text)
160 import qualified Data.Text.Lazy as T
161 import Data.Text.Lazy.Builder (Builder)
162 import qualified Data.Text.Lazy.Builder as B
163 import qualified Data.Text.Lazy.IO as T
164 {-# ANN module "HLint: ignore Eta reduce" #-}
167 infixr 5 </>,<//>,<$>,<$$>
171 -----------------------------------------------------------
172 -- list, tupled and semiBraces pretty print a list of
173 -- documents either horizontally or vertically aligned.
174 -----------------------------------------------------------
177 -- | The document @(list xs)@ comma separates the documents @xs@ and
178 -- encloses them in square brackets. The documents are rendered
179 -- horizontally if that fits the page. Otherwise they are aligned
180 -- vertically. All comma separators are put in front of the
183 list = encloseSep lbracket rbracket comma
185 -- | The document @(tupled xs)@ comma separates the documents @xs@ and
186 -- encloses them in parenthesis. The documents are rendered
187 -- horizontally if that fits the page. Otherwise they are aligned
188 -- vertically. All comma separators are put in front of the
190 tupled :: [Doc] -> Doc
191 tupled = encloseSep lparen rparen comma
193 -- | The document @(semiBraces xs)@ separates the documents @xs@ with
194 -- semi colons and encloses them in braces. The documents are
195 -- rendered horizontally if that fits the page. Otherwise they are
196 -- aligned vertically. All semi colons are put in front of the
198 semiBraces :: [Doc] -> Doc
199 semiBraces = encloseSep lbrace rbrace semi
201 -- | The document @(encloseSep l r sep xs)@ concatenates the documents
202 -- @xs@ separated by @sep@ and encloses the resulting document by
203 -- @l@ and @r@. The documents are rendered horizontally if that fits
204 -- the page. Otherwise they are aligned vertically. All separators
205 -- are put in front of the elements. For example, the combinator
206 -- 'list' can be defined with @encloseSep@:
208 -- > list xs = encloseSep lbracket rbracket comma xs
209 -- > test = text "list" <+> (list (map int [10,200,3000]))
211 -- Which is laid out with a page width of 20 as:
214 -- list [10,200,3000]
217 -- But when the page width is 15, it is laid out as:
224 encloseSep :: Doc -> Doc -> Doc -> [Doc] -> Doc
225 encloseSep left right sp ds
228 [d] -> left <> d <> right
229 _ -> align (cat (zipWith (<>) (left : repeat sp) ds) <> right)
231 -----------------------------------------------------------
232 -- punctuate p [d1,d2,...,dn] => [d1 <> p,d2 <> p, ... ,dn]
233 -----------------------------------------------------------
236 -- | @(punctuate p xs)@ concatenates all documents in @xs@ with
237 -- document @p@ except for the last document.
239 -- > someText = map text ["words","in","a","tuple"]
240 -- > test = parens (align (cat (punctuate comma someText)))
242 -- This is laid out on a page width of 20 as:
245 -- (words,in,a,tuple)
248 -- But when the page width is 15, it is laid out as:
257 -- (If you want put the commas in front of their elements instead of
258 -- at the end, you should use 'tupled' or, in general, 'encloseSep'.)
259 punctuate :: Doc -> [Doc] -> [Doc]
261 punctuate _ [d] = [d]
262 punctuate p (d:ds) = (d <> p) : punctuate p ds
265 -----------------------------------------------------------
266 -- high-level combinators
267 -----------------------------------------------------------
270 -- | The document @(sep xs)@ concatenates all documents @xs@ either
271 -- horizontally with @(\<+\>)@, if it fits the page, or vertically
274 -- > sep xs = group (vsep xs)
278 -- | The document @(fillSep xs)@ concatenates documents @xs@
279 -- horizontally with @(\<+\>)@ as long as its fits the page, then
280 -- inserts a @line@ and continues doing that for all documents in
283 -- > fillSep xs = foldr (</>) empty xs
284 fillSep :: [Doc] -> Doc
287 -- | The document @(hsep xs)@ concatenates all documents @xs@
288 -- horizontally with @(\<+\>)@.
292 -- | The document @(vsep xs)@ concatenates all documents @xs@
293 -- vertically with @(\<$\>)@. If a 'group' undoes the line breaks
294 -- inserted by @vsep@, all documents are separated with a space.
296 -- > someText = map text (words ("text to lay out"))
298 -- > test = text "some" <+> vsep someText
300 -- This is laid out as:
309 -- The 'align' combinator can be used to align the documents under
310 -- their first element
312 -- > test = text "some" <+> align (vsep someText)
314 -- Which is printed as:
325 -- | The document @(cat xs)@ concatenates all documents @xs@ either
326 -- horizontally with @(\<\>)@, if it fits the page, or vertically
329 -- > cat xs = group (vcat xs)
333 -- | The document @(fillCat xs)@ concatenates documents @xs@
334 -- horizontally with @(\<\>)@ as long as its fits the page, then
335 -- inserts a @linebreak@ and continues doing that for all documents
338 -- > fillCat xs = foldr (<//>) empty xs
339 fillCat :: [Doc] -> Doc
340 fillCat = fold (<//>)
342 -- | The document @(hcat xs)@ concatenates all documents @xs@
343 -- horizontally with @(\<\>)@.
347 -- | The document @(vcat xs)@ concatenates all documents @xs@
348 -- vertically with @(\<$$\>)@. If a 'group' undoes the line breaks
349 -- inserted by @vcat@, all documents are directly concatenated.
353 fold :: (Doc -> Doc -> Doc) -> [Doc] -> Doc
355 fold f ds = foldr1 f ds
357 -- | The document @(x \<+\> y)@ concatenates document @x@ and @y@ with
358 -- a 'space' in between. (infixr 6)
359 (<+>) :: Doc -> Doc -> Doc
362 x <+> y = x <> space <> y
364 -- | The document @(x \<++\> y)@ concatenates document @x@ and @y@ with
365 -- a 'spacebreak' in between. (infixr 6)
366 (<++>) :: Doc -> Doc -> Doc
369 x <++> y = x <> spacebreak <> y
372 -- | The document @(x \<\/\> y)@ concatenates document @x@ and @y@
373 -- with a 'softline' in between. This effectively puts @x@ and @y@
374 -- either next to each other (with a @space@ in between) or
375 -- underneath each other. (infixr 5)
376 (</>) :: Doc -> Doc -> Doc
377 (</>) = splitWithBreak False
379 -- | The document @(x \<\/\/\> y)@ concatenates document @x@ and @y@
380 -- with a 'softbreak' in between. This effectively puts @x@ and @y@
381 -- either right next to each other or underneath each other. (infixr
383 (<//>) :: Doc -> Doc -> Doc
384 (<//>) = splitWithBreak True
386 splitWithBreak :: Bool -> Doc -> Doc -> Doc
387 splitWithBreak _ Empty b = b
388 splitWithBreak _ a Empty = a
389 splitWithBreak f a b = a <> group (Line f) <> b
391 -- | The document @(x \<$\> y)@ concatenates document @x@ and @y@ with
392 -- a 'line' in between. (infixr 5)
393 (<$>) :: Doc -> Doc -> Doc
394 (<$>) = splitWithLine False
396 -- | The document @(x \<$$\> y)@ concatenates document @x@ and @y@
397 -- with a 'linebreak' in between. (infixr 5)
398 (<$$>) :: Doc -> Doc -> Doc
399 (<$$>) = splitWithLine True
401 splitWithLine :: Bool -> Doc -> Doc -> Doc
402 splitWithLine _ Empty b = b
403 splitWithLine _ a Empty = a
404 splitWithLine f a b = a <> Line f <> b
406 -- | The document @softline@ behaves like 'space' if the resulting
407 -- output fits the page, otherwise it behaves like 'line'.
409 -- > softline = group line
411 softline = group line
413 -- | The document @softbreak@ behaves like 'empty' if the resulting
414 -- output fits the page, otherwise it behaves like 'line'.
416 -- > softbreak = group linebreak
418 softbreak = group linebreak
420 -- | The document @spacebreak@ behaves like 'space' when rendered normally
421 -- but like 'empty' when using 'renderCompact' or 'renderOneLine'.
423 spacebreak = Spaces 1
425 -- | Document @(squotes x)@ encloses document @x@ with single quotes
427 squotes :: Doc -> Doc
428 squotes = enclose squote squote
430 -- | Document @(dquotes x)@ encloses document @x@ with double quotes
432 dquotes :: Doc -> Doc
433 dquotes = enclose dquote dquote
435 -- | Document @(braces x)@ encloses document @x@ in braces, \"{\" and
438 braces = enclose lbrace rbrace
440 -- | Document @(parens x)@ encloses document @x@ in parenthesis, \"(\"
443 parens = enclose lparen rparen
445 -- | Document @(angles x)@ encloses document @x@ in angles, \"\<\" and
448 angles = enclose langle rangle
450 -- | Document @(brackets x)@ encloses document @x@ in square brackets,
452 brackets :: Doc -> Doc
453 brackets = enclose lbracket rbracket
455 -- | The document @(enclose l r x)@ encloses document @x@ between
456 -- documents @l@ and @r@ using @(\<\>)@.
458 -- > enclose l r x = l <> x <> r
459 enclose :: Doc -> Doc -> Doc -> Doc
460 enclose l r x = l <> x <> r
462 -- | The document @lparen@ contains a left parenthesis, \"(\".
466 -- | The document @rparen@ contains a right parenthesis, \")\".
470 -- | The document @langle@ contains a left angle, \"\<\".
474 -- | The document @rangle@ contains a right angle, \">\".
478 -- | The document @lbrace@ contains a left brace, \"{\".
482 -- | The document @rbrace@ contains a right brace, \"}\".
486 -- | The document @lbracket@ contains a left square bracket, \"[\".
490 -- | The document @rbracket@ contains a right square bracket, \"]\".
494 -- | The document @squote@ contains a single quote, \"'\".
498 -- | The document @dquote@ contains a double quote, '\"'.
502 -- | The document @semi@ contains a semi colon, \";\".
506 -- | The document @colon@ contains a colon, \":\".
510 -- | The document @comma@ contains a comma, \",\".
514 -- | The document @space@ contains a single space, \" \".
516 -- > x <+> y = x <> space <> y
520 -- | The document @dot@ contains a single dot, \".\".
524 -- | The document @backslash@ contains a back slash, \"\\\".
526 backslash = char '\\'
528 -- | The document @equals@ contains an equal sign, \"=\".
532 -----------------------------------------------------------
533 -- Combinators for prelude types
534 -----------------------------------------------------------
536 -- string is like "text" but replaces '\n' by "line"
538 -- | The document @(string s)@ concatenates all characters in @s@
539 -- using @line@ for newline characters and @char@ for all other
540 -- characters. It is used instead of 'text' whenever the text
541 -- contains newline characters.
542 string :: Text -> Doc
543 string str = case T.uncons str of
545 Just ('\n',str') -> line <> string str'
546 _ -> case (T.span (/='\n') str) of
547 (xs,ys) -> text xs <> string ys
549 -- | The document @(bool b)@ shows the literal boolean @b@ using
554 -- | The document @(int i)@ shows the literal integer @i@ using
559 -- | The document @(integer i)@ shows the literal integer @i@ using
561 integer :: Integer -> Doc
564 -- | The document @(float f)@ shows the literal float @f@ using
566 float :: Float -> Doc
569 -- | The document @(double d)@ shows the literal double @d@ using
571 double :: Double -> Doc
574 -- | The document @(rational r)@ shows the literal rational @r@ using
576 rational :: Rational -> Doc
579 text' :: (Show a) => a -> Doc
580 text' = text . T.pack . show
582 -----------------------------------------------------------
583 -- overloading "pretty"
584 -----------------------------------------------------------
586 -- | The member @prettyList@ is only used to define the @instance
587 -- Pretty a => Pretty [a]@. In normal circumstances only the
588 -- @pretty@ function is used.
592 prettyList :: [a] -> Doc
593 prettyList = list . map pretty
595 instance Pretty a => Pretty [a] where
598 instance Pretty Doc where
601 instance Pretty Text where
604 instance Pretty () where
607 instance Pretty Bool where
610 instance Pretty Char where
613 prettyList s = string $ T.pack s
615 instance Pretty Int where
618 instance Pretty Integer where
621 instance Pretty Float where
624 instance Pretty Double where
627 --instance Pretty Rational where
628 -- pretty r = rational r
630 instance (Pretty a,Pretty b) => Pretty (a,b) where
631 pretty (x,y) = tupled [pretty x, pretty y]
633 instance (Pretty a,Pretty b,Pretty c) => Pretty (a,b,c) where
634 pretty (x,y,z)= tupled [pretty x, pretty y, pretty z]
636 instance Pretty a => Pretty (Maybe a) where
637 pretty Nothing = empty
639 pretty (Just x) = pretty x
641 -----------------------------------------------------------
642 -- semi primitive: fill and fillBreak
643 -----------------------------------------------------------
645 -- | The document @(fillBreak i x)@ first renders document @x@. It
646 -- then appends @space@s until the width is equal to @i@. If the
647 -- width of @x@ is already larger than @i@, the nesting level is
648 -- increased by @i@ and a @line@ is appended. When we redefine
649 -- @ptype@ in the previous example to use @fillBreak@, we get a
650 -- useful variation of the previous output:
653 -- > = fillBreak 6 (text name) <+> text "::" <+> text tp
655 -- The output will now be:
659 -- nest :: Int -> Doc -> Doc
663 fillBreak :: Int -> Doc -> Doc
664 fillBreak f x = width x (\w ->
666 then nest f linebreak
671 -- | The document @(fill i x)@ renders document @x@. It then appends
672 -- @space@s until the width is equal to @i@. If the width of @x@ is
673 -- already larger, nothing is appended. This combinator is quite
674 -- useful in practice to output a list of bindings. The following
675 -- example demonstrates this.
677 -- > types = [("empty","Doc")
678 -- > ,("nest","Int -> Doc -> Doc")
679 -- > ,("linebreak","Doc")]
682 -- > = fill 6 (text name) <+> text "::" <+> text tp
684 -- > test = text "let" <+> align (vcat (map ptype types))
686 -- Which is laid out as:
690 -- nest :: Int -> Doc -> Doc
693 fill :: Int -> Doc -> Doc
694 fill f d = width d (\w ->
701 width :: Doc -> (Int -> Doc) -> Doc
702 width d f = column (\k1 -> d <> column (\k2 -> f (k2 - k1)))
704 -----------------------------------------------------------
705 -- semi primitive: Alignment and indentation
706 -----------------------------------------------------------
708 -- | The document @(indent i x)@ indents document @x@ with @i@ spaces.
710 -- > test = indent 4 (fillSep (map text
711 -- > (words "the indent combinator indents these words !")))
713 -- Which lays out with a page width of 20 as:
721 indent :: Int -> Doc -> Doc
722 indent _ Empty = Empty
723 indent i d = hang i (spaced i <> d)
725 -- | The hang combinator implements hanging indentation. The document
726 -- @(hang i x)@ renders document @x@ with a nesting level set to the
727 -- current column plus @i@. The following example uses hanging
728 -- indentation for some text:
730 -- > test = hang 4 (fillSep (map text
731 -- > (words "the hang combinator indents these words !")))
733 -- Which lays out on a page with a width of 20 characters as:
736 -- the hang combinator
741 -- The @hang@ combinator is implemented as:
743 -- > hang i x = align (nest i x)
744 hang :: Int -> Doc -> Doc
745 hang i d = align (nest i d)
747 -- | The document @(align x)@ renders document @x@ with the nesting
748 -- level set to the current column. It is used for example to
751 -- As an example, we will put a document right above another one,
752 -- regardless of the current nesting level:
754 -- > x $$ y = align (x <$> y)
756 -- > test = text "hi" <+> (text "nice" $$ text "world")
758 -- which will be laid out as:
765 align d = column (\k ->
766 nesting (\i -> nest (k - i) d)) --nesting might be negative :-)
768 -----------------------------------------------------------
770 -----------------------------------------------------------
772 -- | The abstract data type @Doc@ represents pretty documents.
774 -- @Doc@ is an instance of the 'Show' class. @(show doc)@ pretty
775 -- prints document @doc@ with a page width of 100 characters and a
776 -- ribbon width of 40 characters.
778 -- > show (text "hello" <$> text "world")
780 -- Which would return the string \"hello\\nworld\", i.e.
787 | Char Char -- invariant: char is not '\n'
788 | Text !Int64 Builder -- invariant: text doesn't contain '\n'
789 | Line !Bool -- True <=> when undone by group, do not insert a space
790 -- | FlatAlt Doc Doc -- Render the first doc, but when
791 -- flattened, render the second.
794 | Union Doc Doc -- invariant: first lines of first doc longer than the first lines of the second doc
795 | Column (Int64 -> Doc)
796 | Nesting (Int64 -> Doc)
798 | Color ConsoleLayer ColorIntensity -- Introduces coloring /around/ the embedded document
801 | Intensify ConsoleIntensity Doc
803 | Underline Underlining Doc
804 | RestoreFormat (Maybe (ColorIntensity, Color)) -- Only used during the rendered phase, to signal a SGR should be issued to restore the terminal formatting.
805 (Maybe (ColorIntensity, Color)) -- These are the colors to revert the current forecolor/backcolor to (i.e. those from before the start of the Color block).
806 (Maybe ConsoleIntensity) -- Intensity to revert to.
807 (Maybe Bool) -- Italicization to revert to.
808 (Maybe Underlining) -- Underlining to revert to.
810 instance IsString Doc where
811 fromString = string . T.pack
813 -- | In particular, note that the document @(x '<>' y)@ concatenates
814 -- document @x@ and document @y@. It is an associative operation
815 -- having 'empty' as a left and right unit. (infixr 6)
816 instance Monoid Doc where
820 -- | The data type @SimpleDoc@ represents rendered documents and is
821 -- used by the display functions.
823 -- The @Int@ in @SText@ contains the length of the string. The @Int@
824 -- in @SLine@ contains the indentation for that line. The library
825 -- provides two default display functions 'displayS' and
826 -- 'displayIO'. You can provide your own display function by writing
827 -- a function from a @SimpleDoc@ to your own output format.
828 data SimpleDoc = SEmpty
829 | SChar Char SimpleDoc
830 | SText !Int64 Builder SimpleDoc
831 | SLine !Int64 SimpleDoc
832 | SSGR [SGR] SimpleDoc
834 -- | The empty document is, indeed, empty. Although @empty@ has no
835 -- content, it does have a \'height\' of 1 and behaves exactly like
836 -- @(text \"\")@ (and is therefore not a unit of @\<$\>@).
840 is_empty :: Doc -> Bool
841 is_empty doc = case doc of
845 if_color :: Doc -> Doc -> Doc
848 -- | The document @(char c)@ contains the literal character @c@. The
849 -- character shouldn't be a newline (@'\n'@), the function 'line'
850 -- should be used for line breaks.
855 -- | The document @(text s)@ contains the literal string @s@. The
856 -- string shouldn't contain any newline (@'\n'@) characters. If the
857 -- string contains newline characters, the function 'string' should
862 | otherwise = Text (T.length s) (B.fromLazyText s)
864 -- | The @line@ document advances to the next line and indents to the
865 -- current nesting level. Document @line@ behaves like @(text \"
866 -- \")@ if the line break is undone by 'group' or if rendered with
870 --line = FlatAlt Line space
872 -- | The @linebreak@ document advances to the next line and indents to
873 -- the current nesting level. Document @linebreak@ behaves like
874 -- 'empty' if the line break is undone by 'group'.
876 linebreak = Line True
877 --linebreak = FlatAlt Line empty
879 beside :: Doc -> Doc -> Doc
884 -- | The document @(nest i x)@ renders document @x@ with the current
885 -- indentation level increased by @i@ (See also 'hang', 'align' and
888 -- > nest 2 (text "hello" <$> text "world") <$> text "!"
897 nest :: Int -> Doc -> Doc
899 nest i x = Nest (fromIntegral i) x
901 -- | Specifies how to create the document based upon which column it is in.
902 column :: (Int -> Doc) -> Doc
903 column f = Column (f . fromIntegral)
905 -- | Specifies how to nest the document based upon which column it is
907 nesting :: (Int -> Doc) -> Doc
908 nesting f = Nesting (f . fromIntegral)
910 -- | The @group@ combinator is used to specify alternative
911 -- layouts. The document @(group x)@ undoes all line breaks in
912 -- document @x@. The resulting line is added to the current line if
913 -- that fits the page. Otherwise, the document @x@ is rendered
914 -- without any changes.
916 group x = Union (flatten x) x
918 flatten :: Doc -> Doc
919 flatten (Cat x y) = Cat (flatten x) (flatten y)
920 flatten (Nest i x) = Nest i (flatten x)
921 flatten (Line brk) = if brk then Empty else Text 1 (B.singleton ' ')
922 flatten (Union x _) = flatten x
923 flatten (Column f) = Column (flatten . f)
924 flatten (Nesting f) = Nesting (flatten . f)
925 flatten (Color l i c x) = Color l i c (flatten x)
926 flatten (IfColor t f) = IfColor (flatten t) (flatten f)
927 flatten (Intensify i x) = Intensify i (flatten x)
928 flatten (Italicize b x) = Italicize b (flatten x)
929 flatten (Underline u x) = Underline u (flatten x)
930 -- flatten (FlatAlt x y) = y
931 flatten other = other --Empty,Char,Text,RestoreFormat
934 -----------------------------------------------------------
936 -----------------------------------------------------------
938 -- | Displays a document with the black forecolor
940 -- | Displays a document with the red forecolor
942 -- | Displays a document with the green forecolor
944 -- | Displays a document with the yellow forecolor
946 -- | Displays a document with the blue forecolor
948 -- | Displays a document with the magenta forecolor
949 magenta :: Doc -> Doc
950 -- | Displays a document with the cyan forecolor
952 -- | Displays a document with the white forecolor
954 -- | Displays a document with the dull black forecolor
955 dullblack :: Doc -> Doc
956 -- | Displays a document with the dull red forecolor
957 dullred :: Doc -> Doc
958 -- | Displays a document with the dull green forecolor
959 dullgreen :: Doc -> Doc
960 -- | Displays a document with the dull yellow forecolor
961 dullyellow :: Doc -> Doc
962 -- | Displays a document with the dull blue forecolor
963 dullblue :: Doc -> Doc
964 -- | Displays a document with the dull magenta forecolor
965 dullmagenta :: Doc -> Doc
966 -- | Displays a document with the dull cyan forecolor
967 dullcyan :: Doc -> Doc
968 -- | Displays a document with the dull white forecolor
969 dullwhite :: Doc -> Doc
970 (black, dullblack) = colorFunctions Black
971 (red, dullred) = colorFunctions Red
972 (green, dullgreen) = colorFunctions Green
973 (yellow, dullyellow) = colorFunctions Yellow
974 (blue, dullblue) = colorFunctions Blue
975 (magenta, dullmagenta) = colorFunctions Magenta
976 (cyan, dullcyan) = colorFunctions Cyan
977 (white, dullwhite) = colorFunctions White
979 -- | Displays a document with a forecolor given in the first parameter
980 color :: Color -> Doc -> Doc
981 -- | Displays a document with a dull forecolor given in the first parameter
982 dullcolor :: Color -> Doc -> Doc
983 color = Color Foreground Vivid
984 dullcolor = Color Foreground Dull
986 colorFunctions :: Color -> (Doc -> Doc, Doc -> Doc)
987 colorFunctions what = (color what, dullcolor what)
989 -- | Displays a document with the black backcolor
990 onblack :: Doc -> Doc
991 -- | Displays a document with the red backcolor
993 -- | Displays a document with the green backcolor
994 ongreen :: Doc -> Doc
995 -- | Displays a document with the yellow backcolor
996 onyellow :: Doc -> Doc
997 -- | Displays a document with the blue backcolor
999 -- | Displays a document with the magenta backcolor
1000 onmagenta :: Doc -> Doc
1001 -- | Displays a document with the cyan backcolor
1002 oncyan :: Doc -> Doc
1003 -- | Displays a document with the white backcolor
1004 onwhite :: Doc -> Doc
1005 -- | Displays a document with the dull block backcolor
1006 ondullblack :: Doc -> Doc
1007 -- | Displays a document with the dull red backcolor
1008 ondullred :: Doc -> Doc
1009 -- | Displays a document with the dull green backcolor
1010 ondullgreen :: Doc -> Doc
1011 -- | Displays a document with the dull yellow backcolor
1012 ondullyellow :: Doc -> Doc
1013 -- | Displays a document with the dull blue backcolor
1014 ondullblue :: Doc -> Doc
1015 -- | Displays a document with the dull magenta backcolor
1016 ondullmagenta :: Doc -> Doc
1017 -- | Displays a document with the dull cyan backcolor
1018 ondullcyan :: Doc -> Doc
1019 -- | Displays a document with the dull white backcolor
1020 ondullwhite :: Doc -> Doc
1021 (onblack, ondullblack) = oncolorFunctions Black
1022 (onred, ondullred) = oncolorFunctions Red
1023 (ongreen, ondullgreen) = oncolorFunctions Green
1024 (onyellow, ondullyellow) = oncolorFunctions Yellow
1025 (onblue, ondullblue) = oncolorFunctions Blue
1026 (onmagenta, ondullmagenta) = oncolorFunctions Magenta
1027 (oncyan, ondullcyan) = oncolorFunctions Cyan
1028 (onwhite, ondullwhite) = oncolorFunctions White
1030 -- | Displays a document with a backcolor given in the first parameter
1031 oncolor :: Color -> Doc -> Doc
1032 -- | Displays a document with a dull backcolor given in the first parameter
1033 ondullcolor :: Color -> Doc -> Doc
1034 oncolor = Color Background Vivid
1035 ondullcolor = Color Background Dull
1037 oncolorFunctions :: Color -> (Doc -> Doc, Doc -> Doc)
1038 oncolorFunctions what = (oncolor what, ondullcolor what)
1041 -----------------------------------------------------------
1042 -- Console Intensity
1043 -----------------------------------------------------------
1045 -- | Displays a document in a heavier font weight
1047 bold = Intensify BoldIntensity
1049 -- | Displays a document in the normal font weight
1050 debold :: Doc -> Doc
1051 debold = Intensify NormalIntensity
1053 -- NB: I don't support FaintIntensity here because it is not widely supported by terminals.
1056 -----------------------------------------------------------
1058 -----------------------------------------------------------
1062 I'm in two minds about providing these functions, since italicization is so rarely implemented.
1063 It is especially bad because "italicization" may cause the meaning of colors to flip, which will
1064 look a bit weird, to say the least...
1067 -- | Displays a document in italics. This is not widely supported, and it's use is not recommended
1068 italicize :: Doc -> Doc
1069 italicize = Italicize True
1071 -- | Displays a document with no italics
1072 deitalicize :: Doc -> Doc
1073 deitalicize = Italicize False
1077 -----------------------------------------------------------
1079 -----------------------------------------------------------
1081 -- | Displays a document with underlining
1082 underline :: Doc -> Doc
1083 underline = Underline SingleUnderline
1085 -- | Displays a document with no underlining
1086 deunderline :: Doc -> Doc
1087 deunderline = Underline NoUnderline
1089 -- NB: I don't support DoubleUnderline here because it is not widely supported by terminals.
1091 -----------------------------------------------------------
1092 -- Removing formatting
1093 -----------------------------------------------------------
1095 -- | Removes all colorisation, emboldening and underlining from a document
1097 -- plain Fail = Fail
1099 plain c@(Char _) = c
1100 plain t@(Text _ _) = t
1101 plain l@(Line _) = l
1102 -- plain (FlatAlt x y) = FlatAlt (plain x) (plain y)
1103 plain (Cat x y) = Cat (plain x) (plain y)
1104 plain (Nest i x) = Nest i (plain x)
1105 plain (Union x y) = Union (plain x) (plain y)
1106 plain (Column f) = Column (plain . f)
1107 -- plain (Columns f) = Columns (plain . f)
1108 plain (Nesting f) = Nesting (plain . f)
1109 plain (Spaces l) = Spaces l
1110 plain (Color _ _ _ x) = plain x
1111 plain (Intensify _ x) = plain x
1112 plain (IfColor t f) = IfColor (plain t) (plain f)
1113 plain (Italicize _ x) = plain x
1114 plain (Underline _ x) = plain x
1115 plain (RestoreFormat{}) = Empty
1117 -----------------------------------------------------------
1119 -----------------------------------------------------------
1121 -----------------------------------------------------------
1122 -- renderPretty: the default pretty printing algorithm
1123 -----------------------------------------------------------
1125 -- list of indentation/document pairs; saves an indirection over [(Int,Doc)]
1127 | Cons !Int64 Doc Docs
1129 -- | This is the default pretty printer which is used by 'show',
1130 -- 'putDoc' and 'hPutDoc'. @(renderPretty ribbonfrac width x)@
1131 -- renders document @x@ with a page width of @width@ and a ribbon
1132 -- width of @(ribbonfrac * width)@ characters. The ribbon width is
1133 -- the maximal amount of non-indentation characters on a line. The
1134 -- parameter @ribbonfrac@ should be between @0.0@ and @1.0@. If it
1135 -- is lower or higher, the ribbon width will be 0 or @width@
1137 renderPretty :: Bool -> Float -> Int -> Doc -> SimpleDoc
1138 renderPretty = renderFits fits1
1140 -- | A slightly smarter rendering algorithm with more lookahead. It provides
1141 -- provide earlier breaking on deeply nested structures
1142 -- For example, consider this python-ish pseudocode:
1143 -- @fun(fun(fun(fun(fun([abcdefg, abcdefg])))))@
1144 -- If we put a softbreak (+ nesting 2) after each open parenthesis, and align
1145 -- the elements of the list to match the opening brackets, this will render with
1146 -- @renderPretty@ and a page width of 20 as:
1148 -- fun(fun(fun(fun(fun([
1154 -- Where the 20c. boundary has been marked with |.
1155 -- Because @renderPretty@ only uses one-line lookahead, it sees that the first
1156 -- line fits, and is stuck putting the second and third lines after the 20-c
1157 -- mark. In contrast, @renderSmart@ will continue to check that the potential
1158 -- document up to the end of the indentation level. Thus, it will format the
1172 -- Which fits within the 20c. boundary.
1173 renderSmart :: Bool -> Float -> Int -> Doc -> SimpleDoc
1174 renderSmart = renderFits fitsR
1176 renderFits :: (Int64 -> Int64 -> Int64 -> SimpleDoc -> Bool)
1177 -> Bool -> Float -> Int -> Doc -> SimpleDoc
1178 renderFits fits with_color rfrac w doc
1179 -- I used to do a @SSGR [Reset]@ here, but if you do that it will result
1180 -- in any rendered @Doc@ containing at least some ANSI control codes. This
1181 -- may be undesirable if you want to render to non-ANSI devices by simply
1182 -- not making use of the ANSI color combinators I provide.
1184 -- What I "really" want to do here is do an initial Reset iff there is some
1185 -- ANSI color within the Doc, but that's a bit fiddly. I'll fix it if someone
1187 = best 0 0 Nothing Nothing Nothing Nothing Nothing (Cons 0 doc Nil)
1189 -- r :: the ribbon width in characters
1190 r = max 0 (min w64 (round (fromIntegral w * rfrac)))
1192 w64 = fromIntegral w
1194 -- best :: n = indentation of current line
1195 -- k = current column
1196 -- (ie. (k >= n) && (k - n == count of inserted characters)
1197 best _n _k _mb_fc _mb_bc _mb_in _mb_it _mb_un Nil = SEmpty
1198 best n k mb_fc mb_bc mb_in mb_it mb_un (Cons i d ds)
1201 Empty -> best_typical n k ds
1202 Char c -> let k' = k+1 in seq k' (SChar c (best_typical n k' ds))
1203 Text l s -> let k' = k+l in seq k' (SText l s (best_typical n k' ds))
1204 Line _ -> SLine i (best_typical i i ds)
1205 -- FlatAlt x _ -> best_typical n k (Cons i x ds)
1206 Cat x y -> best_typical n k (Cons i x (Cons i y ds))
1207 Nest j x -> let i' = i+j in seq i' (best_typical n k (Cons i' x ds))
1208 Union x y -> nicest n k (best_typical n k (Cons i x ds))
1209 (best_typical n k (Cons i y ds))
1210 Column f -> best_typical n k (Cons i (f k) ds)
1211 -- Columns f -> best_typical n k (Cons i (f (Just w)) ds)
1212 Nesting f -> best_typical n k (Cons i (f i) ds)
1213 Spaces l -> let k' = k+l in seq k' $ SText l (spaces l) (best_typical n k' ds)
1214 Color _ _ _ x | not with_color -> best_typical n k (Cons i x ds)
1215 Color l t c x -> SSGR [SetColor l t c] (best n k mb_fc' mb_bc' mb_in mb_it mb_un (Cons i x ds_restore))
1217 mb_fc' = case l of { Background -> mb_fc; Foreground -> Just (t, c) }
1218 mb_bc' = case l of { Background -> Just (t, c); Foreground -> mb_bc }
1219 IfColor xt xf -> best_typical n k (if with_color then Cons i xt ds else Cons i xf ds)
1220 Intensify _ x | not with_color -> best_typical n k (Cons i x ds)
1221 Intensify t x -> SSGR [SetConsoleIntensity t] (best n k mb_fc mb_bc (Just t) mb_it mb_un (Cons i x ds_restore))
1222 Italicize _ x | not with_color -> best_typical n k (Cons i x ds)
1223 Italicize t x -> SSGR [SetItalicized t] (best n k mb_fc mb_bc mb_in (Just t) mb_un (Cons i x ds_restore))
1224 Underline _ x | not with_color -> best_typical n k (Cons i x ds)
1225 Underline u x -> SSGR [SetUnderlining u] (best n k mb_fc mb_bc mb_in mb_it (Just u) (Cons i x ds_restore))
1226 RestoreFormat{} | not with_color -> best_typical n k ds
1227 RestoreFormat mb_fc' mb_bc' mb_in' mb_it' mb_un' -> SSGR sgrs (best n k mb_fc' mb_bc' mb_in' mb_it' mb_un' ds)
1229 -- We need to be able to restore the entire SGR state, hence we carry around what we believe
1230 -- that state should be in all the arguments to this function. Note that in some cases we could
1231 -- avoid the Reset of the entire state, but not in general.
1232 sgrs = Reset : catMaybes [
1233 fmap (uncurry (SetColor Foreground)) mb_fc',
1234 fmap (uncurry (SetColor Background)) mb_bc',
1235 fmap SetConsoleIntensity mb_in',
1236 fmap SetItalicized mb_it',
1237 fmap SetUnderlining mb_un'
1240 best_typical n' k' ds' = best n' k' mb_fc mb_bc mb_in mb_it mb_un ds'
1241 ds_restore = Cons i (RestoreFormat mb_fc mb_bc mb_in mb_it mb_un) ds
1243 --nicest :: r = ribbon width, w = page width,
1244 -- n = indentation of current line, k = current column
1245 -- x and y, the (simple) documents to chose from.
1246 -- precondition: first lines of x are longer than the first lines of y.
1247 nicest n k x y | fits w64 (min n k) width_ x = x
1250 width_ = min (w64 - k) (r - k + n)
1252 -- @fits1@ does 1 line lookahead.
1253 fits1 :: Int64 -> Int64 -> Int64 -> SimpleDoc -> Bool
1254 fits1 _ _ w _x | w < 0 = False
1255 --fits1 _ _ w SFail = False
1256 fits1 _ _ _w SEmpty = True
1257 fits1 p m w (SChar _c x) = fits1 p m (w - 1) x
1258 fits1 p m w (SText l _s x) = fits1 p m (w - l) x
1259 fits1 _ _ _w (SLine _i _x) = True
1260 fits1 p m w (SSGR _ x) = fits1 p m w x
1262 -- @fitsR@ has a little more lookahead: assuming that nesting roughly
1263 -- corresponds to syntactic depth, @fitsR@ checks that not only the current line
1264 -- fits, but the entire syntactic structure being formatted at this level of
1265 -- indentation fits. If we were to remove the second case for @SLine@, we would
1266 -- check that not only the current structure fits, but also the rest of the
1267 -- document, which would be slightly more intelligent but would have exponential
1268 -- runtime (and is prohibitively expensive in practice).
1270 -- m = minimum nesting level to fit in
1271 -- w = the width in which to fit the first line
1272 fitsR :: Int64 -> Int64 -> Int64 -> SimpleDoc -> Bool
1273 fitsR _p _m w _x | w < 0 = False
1274 --fitsR p m w SFail = False
1275 fitsR _p _m _w SEmpty = True
1276 fitsR p m w (SChar _c x) = fitsR p m (w - 1) x
1277 fitsR p m w (SText l _s x) = fitsR p m (w - l) x
1278 fitsR p m _w (SLine i x) | m < i = fitsR p m (p - i) x
1280 fitsR p m w (SSGR _ x) = fitsR p m w x
1282 -----------------------------------------------------------
1283 -- renderCompact: renders documents without indentation
1284 -- fast and fewer characters output, good for machines
1285 -----------------------------------------------------------
1288 -- | @(renderCompact x)@ renders document @x@ without adding any
1289 -- indentation. Since no \'pretty\' printing is involved, this
1290 -- renderer is very fast. The resulting output contains fewer
1291 -- characters than a pretty printed version and can be used for
1292 -- output that is read by other programs.
1293 renderCompact :: Bool -> Doc -> SimpleDoc
1294 renderCompact with_color dc
1295 = scan 0 Nothing Nothing Nothing Nothing Nothing [dc]
1297 scan _ _mb_fc _mb_bc _mb_in _mb_it _mb_un [] = SEmpty
1298 scan k mb_fc mb_bc mb_in mb_it mb_un (d:ds)
1301 Char c -> let k' = k+1 in seq k' (SChar c (scan' k' ds))
1302 Text l s -> let k' = k+l in seq k' (SText l s (scan' k' ds))
1303 Line _ -> SLine 0 (scan' 0 ds)
1304 -- FlatAlt x _ -> scan' k (x:ds)
1305 Cat x y -> scan' k (x:y:ds)
1306 Nest _ x -> scan' k (x:ds)
1307 Union _ y -> scan' k (y:ds)
1308 Column f -> scan' k (f k:ds)
1309 -- Columns f -> scan' k (f Nothing:ds)
1310 Nesting f -> scan' k (f 0:ds)
1311 Spaces _ -> scan' k ds
1312 Color _ _ _ x | not with_color -> scan' k (x:ds)
1313 Color l t c x -> SSGR [SetColor l t c] (scan k mb_fc' mb_bc' mb_in mb_it mb_un (x:ds_restore))
1315 mb_fc' = case l of { Background -> mb_fc; Foreground -> Just (t, c) }
1316 mb_bc' = case l of { Background -> Just (t, c); Foreground -> mb_bc }
1317 IfColor x _ | not with_color -> scan' k (x:ds)
1318 IfColor _ x -> scan' k (x:ds)
1319 Intensify _ x | not with_color -> scan' k (x:ds)
1320 Intensify t x -> SSGR [SetConsoleIntensity t] (scan k mb_fc mb_bc (Just t) mb_it mb_un (x:ds_restore))
1321 Italicize _ x | not with_color -> scan' k (x:ds)
1322 Italicize t x -> SSGR [SetItalicized t] (scan k mb_fc mb_bc mb_in (Just t) mb_un (x:ds_restore))
1323 Underline _ x | not with_color -> scan' k (x:ds)
1324 Underline u x -> SSGR [SetUnderlining u] (scan k mb_fc mb_bc mb_in mb_it (Just u) (x:ds_restore))
1325 RestoreFormat{} | not with_color -> scan' k ds
1326 RestoreFormat mb_fc' mb_bc' mb_in' mb_it' mb_un' -> SSGR sgrs (scan k mb_fc' mb_bc' mb_in' mb_it' mb_un' ds)
1328 sgrs = Reset : catMaybes [
1329 fmap (uncurry (SetColor Foreground)) mb_fc',
1330 fmap (uncurry (SetColor Background)) mb_bc',
1331 fmap SetConsoleIntensity mb_in',
1332 fmap SetItalicized mb_it',
1333 fmap SetUnderlining mb_un'
1336 scan' k' ds' = scan k' mb_fc mb_bc mb_in mb_it mb_un ds'
1337 ds_restore = RestoreFormat mb_fc mb_bc mb_in mb_it mb_un:ds
1339 -- | @(renderOneLine x)@ renders document @x@ without adding any
1340 -- indentation or newlines.
1341 renderOneLine :: Bool -> Doc -> SimpleDoc
1342 renderOneLine with_color dc
1343 = scan 0 Nothing Nothing Nothing Nothing Nothing [dc]
1345 scan _ _mb_fc _mb_bc _mb_in _mb_it _mb_un [] = SEmpty
1346 scan k mb_fc mb_bc mb_in mb_it mb_un (d:ds)
1349 Char c -> let k' = k+1 in seq k' (SChar c (scan' k' ds))
1350 Text l s -> let k' = k+l in seq k' (SText l s (scan' k' ds))
1351 Line False -> let k' = k+1 in seq k' (SChar ' ' (scan' k' ds))
1352 Line _ -> scan' k ds
1353 Cat x y -> scan' k (x:y:ds)
1354 Nest _ x -> scan' k (x:ds)
1355 Union _ y -> scan' k (y:ds)
1356 Column f -> scan' k (f k:ds)
1357 Nesting f -> scan' k (f 0:ds)
1358 Spaces _ -> scan' k ds
1359 Color _ _ _ x | not with_color -> scan' k (x:ds)
1360 Color l t c x -> SSGR [SetColor l t c] (scan k mb_fc' mb_bc' mb_in mb_it mb_un (x:ds_restore))
1362 mb_fc' = case l of { Background -> mb_fc; Foreground -> Just (t, c) }
1363 mb_bc' = case l of { Background -> Just (t, c); Foreground -> mb_bc }
1364 IfColor x _ | with_color -> scan' k (x:ds)
1365 IfColor _ x -> scan' k (x:ds)
1366 Intensify _ x | with_color -> scan' k (x:ds)
1367 Intensify t x -> SSGR [SetConsoleIntensity t] (scan k mb_fc mb_bc (Just t) mb_it mb_un (x:ds_restore))
1368 Italicize _ x | with_color -> scan' k (x:ds)
1369 Italicize t x -> SSGR [SetItalicized t] (scan k mb_fc mb_bc mb_in (Just t) mb_un (x:ds_restore))
1370 Underline _ x | with_color -> scan' k (x:ds)
1371 Underline u x -> SSGR [SetUnderlining u] (scan k mb_fc mb_bc mb_in mb_it (Just u) (x:ds_restore))
1372 RestoreFormat{} | with_color -> scan' k ds
1373 RestoreFormat mb_fc' mb_bc' mb_in' mb_it' mb_un' -> SSGR sgrs (scan k mb_fc' mb_bc' mb_in' mb_it' mb_un' ds)
1375 sgrs = Reset : catMaybes [
1376 fmap (uncurry (SetColor Foreground)) mb_fc',
1377 fmap (uncurry (SetColor Background)) mb_bc',
1378 fmap SetConsoleIntensity mb_in',
1379 fmap SetItalicized mb_it',
1380 fmap SetUnderlining mb_un'
1383 scan' k' ds' = scan k' mb_fc mb_bc mb_in mb_it mb_un ds'
1384 ds_restore = RestoreFormat mb_fc mb_bc mb_in mb_it mb_un:ds
1386 -----------------------------------------------------------
1387 -- Displayers: displayS and displayIO
1388 -----------------------------------------------------------
1391 -- | @(displayB simpleDoc)@ takes the output @simpleDoc@ from a
1392 -- rendering function and transforms it to a 'Builder' type (for
1393 -- further manipulation before converting to a lazy 'Text').
1394 displayB :: SimpleDoc -> Builder
1395 displayB SEmpty = mempty
1396 displayB (SChar c x) = c `consB` displayB x
1397 displayB (SText _ s x) = s `mappend` displayB x
1398 displayB (SLine i x) = '\n' `consB` (indentation i `mappend` displayB x)
1399 displayB (SSGR s x) = B.fromLazyText (T.pack (setSGRCode s)) `mappend` displayB x
1401 consB :: Char -> Builder -> Builder
1402 c `consB` b = B.singleton c `mappend` b
1404 -- | @(displayT simpleDoc)@ takes the output @simpleDoc@ from a
1405 -- rendering function and transforms it to a lazy 'Text' value.
1407 -- > showWidth :: Int -> Doc -> Text
1408 -- > showWidth w x = displayT (renderPretty 0.4 w x)
1409 displayT :: SimpleDoc -> Text
1410 displayT = B.toLazyText . displayB
1412 -- | @(displayIO handle simpleDoc)@ writes @simpleDoc@ to the
1413 -- file handle @handle@. This function is used for example by
1416 -- > hPutDoc handle doc = displayIO handle (renderPretty 0.4 100 doc)
1417 displayIO :: Handle -> SimpleDoc -> IO ()
1418 displayIO handle simpleDoc
1421 display SEmpty = return ()
1422 display (SChar c x) = hPutChar handle c >> display x
1423 display (SText _ s x) = T.hPutStr handle (B.toLazyText s) >> display x
1424 display (SLine i x) = T.hPutStr handle newLine >> display x
1426 newLine = B.toLazyText $ '\n' `consB` indentation i
1427 display (SSGR s x) = hSetSGR handle s >> display x
1429 -----------------------------------------------------------
1430 -- default pretty printers: show, putDoc and hPutDoc
1431 -----------------------------------------------------------
1433 instance Show Doc where
1434 showsPrec d doc = showsPrec d (displayT $ renderPretty True 0.4 80 doc)
1435 show doc = T.unpack (displayT $ renderPretty True 0.4 80 doc)
1437 instance Show SimpleDoc where
1438 show simpleDoc = T.unpack (displayT simpleDoc)
1440 -- | The action @(putDoc doc)@ pretty prints document @doc@ to the
1441 -- standard output, with a page width of 100 characters and a ribbon
1442 -- width of 40 characters.
1445 -- > main = do{ putDoc (text "hello" <+> text "world") }
1447 -- Which would output
1452 putDoc :: Doc -> IO ()
1453 putDoc doc = hPutDoc stdout doc
1455 -- | @(hPutDoc handle doc)@ pretty prints document @doc@ to the file
1456 -- handle @handle@ with a page width of 100 characters and a ribbon
1457 -- width of 40 characters.
1459 -- > main = do handle <- 'openFile' "MyFile" 'WriteMode'
1460 -- > 'hPutDoc' handle ('vcat' ('map' 'text'
1461 -- > ['T.pack' "vertical", 'T.pack' "text"]))
1462 -- > 'hClose' handle
1463 hPutDoc :: Handle -> Doc -> IO ()
1464 hPutDoc handle doc = displayIO handle (renderPretty True 0.4 80 doc)
1466 -----------------------------------------------------------
1468 -- "indentation" used to insert tabs but tabs seem to cause
1469 -- more trouble than they solve :-)
1470 -----------------------------------------------------------
1471 spaces :: Int64 -> Builder
1474 | otherwise = B.fromLazyText $ T.replicate n (T.singleton ' ')
1476 spaced :: Int -> Doc
1477 spaced l = Spaces l'
1481 -- An alias for readability purposes
1482 indentation :: Int64 -> Builder
1483 indentation = spaces
1485 -- | Return a 'Doc' from a strict 'Text'
1486 strict_text :: Data.Text.Text -> Doc
1487 strict_text = text . T.fromStrict
1489 -- | Return a 'Doc' concatenating converted values of a 'Foldable'
1490 -- separated by a given 'Doc'.
1492 :: Data.Foldable.Foldable t
1493 => Doc -> (a -> Doc) -> t a -> Doc
1494 intercalate separator f =
1496 (\doc x -> doc <> (if is_empty doc then empty else separator) <> f x)
1499 class ToDoc m a where
1500 toDoc :: m -> a -> Doc
1501 instance ToDoc m Doc where
1504 -- LocalWords: PPrint combinators Wadler Wadler's encloseSep