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
166 infixr 5 </>,<//>,<$>,<$$>
170 -----------------------------------------------------------
171 -- list, tupled and semiBraces pretty print a list of
172 -- documents either horizontally or vertically aligned.
173 -----------------------------------------------------------
176 -- | The document @(list xs)@ comma separates the documents @xs@ and
177 -- encloses them in square brackets. The documents are rendered
178 -- horizontally if that fits the page. Otherwise they are aligned
179 -- vertically. All comma separators are put in front of the
182 list = encloseSep lbracket rbracket comma
184 -- | The document @(tupled xs)@ comma separates the documents @xs@ and
185 -- encloses them in parenthesis. The documents are rendered
186 -- horizontally if that fits the page. Otherwise they are aligned
187 -- vertically. All comma separators are put in front of the
189 tupled :: [Doc] -> Doc
190 tupled = encloseSep lparen rparen comma
192 -- | The document @(semiBraces xs)@ separates the documents @xs@ with
193 -- semi colons and encloses them in braces. The documents are
194 -- rendered horizontally if that fits the page. Otherwise they are
195 -- aligned vertically. All semi colons are put in front of the
197 semiBraces :: [Doc] -> Doc
198 semiBraces = encloseSep lbrace rbrace semi
200 -- | The document @(encloseSep l r sep xs)@ concatenates the documents
201 -- @xs@ separated by @sep@ and encloses the resulting document by
202 -- @l@ and @r@. The documents are rendered horizontally if that fits
203 -- the page. Otherwise they are aligned vertically. All separators
204 -- are put in front of the elements. For example, the combinator
205 -- 'list' can be defined with @encloseSep@:
207 -- > list xs = encloseSep lbracket rbracket comma xs
208 -- > test = text "list" <+> (list (map int [10,200,3000]))
210 -- Which is laid out with a page width of 20 as:
213 -- list [10,200,3000]
216 -- But when the page width is 15, it is laid out as:
223 encloseSep :: Doc -> Doc -> Doc -> [Doc] -> Doc
224 encloseSep left right sp ds
227 [d] -> left <> d <> right
228 _ -> align (cat (zipWith (<>) (left : repeat sp) ds) <> right)
230 -----------------------------------------------------------
231 -- punctuate p [d1,d2,...,dn] => [d1 <> p,d2 <> p, ... ,dn]
232 -----------------------------------------------------------
235 -- | @(punctuate p xs)@ concatenates all documents in @xs@ with
236 -- document @p@ except for the last document.
238 -- > someText = map text ["words","in","a","tuple"]
239 -- > test = parens (align (cat (punctuate comma someText)))
241 -- This is laid out on a page width of 20 as:
244 -- (words,in,a,tuple)
247 -- But when the page width is 15, it is laid out as:
256 -- (If you want put the commas in front of their elements instead of
257 -- at the end, you should use 'tupled' or, in general, 'encloseSep'.)
258 punctuate :: Doc -> [Doc] -> [Doc]
260 punctuate _ [d] = [d]
261 punctuate p (d:ds) = (d <> p) : punctuate p ds
264 -----------------------------------------------------------
265 -- high-level combinators
266 -----------------------------------------------------------
269 -- | The document @(sep xs)@ concatenates all documents @xs@ either
270 -- horizontally with @(\<+\>)@, if it fits the page, or vertically
273 -- > sep xs = group (vsep xs)
277 -- | The document @(fillSep xs)@ concatenates documents @xs@
278 -- horizontally with @(\<+\>)@ as long as its fits the page, then
279 -- inserts a @line@ and continues doing that for all documents in
282 -- > fillSep xs = foldr (</>) empty xs
283 fillSep :: [Doc] -> Doc
286 -- | The document @(hsep xs)@ concatenates all documents @xs@
287 -- horizontally with @(\<+\>)@.
291 -- | The document @(vsep xs)@ concatenates all documents @xs@
292 -- vertically with @(\<$\>)@. If a 'group' undoes the line breaks
293 -- inserted by @vsep@, all documents are separated with a space.
295 -- > someText = map text (words ("text to lay out"))
297 -- > test = text "some" <+> vsep someText
299 -- This is laid out as:
308 -- The 'align' combinator can be used to align the documents under
309 -- their first element
311 -- > test = text "some" <+> align (vsep someText)
313 -- Which is printed as:
324 -- | The document @(cat xs)@ concatenates all documents @xs@ either
325 -- horizontally with @(\<\>)@, if it fits the page, or vertically
328 -- > cat xs = group (vcat xs)
332 -- | The document @(fillCat xs)@ concatenates documents @xs@
333 -- horizontally with @(\<\>)@ as long as its fits the page, then
334 -- inserts a @linebreak@ and continues doing that for all documents
337 -- > fillCat xs = foldr (<//>) empty xs
338 fillCat :: [Doc] -> Doc
339 fillCat = fold (<//>)
341 -- | The document @(hcat xs)@ concatenates all documents @xs@
342 -- horizontally with @(\<\>)@.
346 -- | The document @(vcat xs)@ concatenates all documents @xs@
347 -- vertically with @(\<$$\>)@. If a 'group' undoes the line breaks
348 -- inserted by @vcat@, all documents are directly concatenated.
352 fold :: (Doc -> Doc -> Doc) -> [Doc] -> Doc
354 fold f ds = foldr1 f ds
356 -- | The document @(x \<+\> y)@ concatenates document @x@ and @y@ with
357 -- a 'space' in between. (infixr 6)
358 (<+>) :: Doc -> Doc -> Doc
361 x <+> y = x <> space <> y
363 -- | The document @(x \<++\> y)@ concatenates document @x@ and @y@ with
364 -- a 'spacebreak' in between. (infixr 6)
365 (<++>) :: Doc -> Doc -> Doc
368 x <++> y = x <> spacebreak <> y
371 -- | The document @(x \<\/\> y)@ concatenates document @x@ and @y@
372 -- with a 'softline' in between. This effectively puts @x@ and @y@
373 -- either next to each other (with a @space@ in between) or
374 -- underneath each other. (infixr 5)
375 (</>) :: Doc -> Doc -> Doc
376 (</>) = splitWithBreak False
378 -- | The document @(x \<\/\/\> y)@ concatenates document @x@ and @y@
379 -- with a 'softbreak' in between. This effectively puts @x@ and @y@
380 -- either right next to each other or underneath each other. (infixr
382 (<//>) :: Doc -> Doc -> Doc
383 (<//>) = splitWithBreak True
385 splitWithBreak :: Bool -> Doc -> Doc -> Doc
386 splitWithBreak _ Empty b = b
387 splitWithBreak _ a Empty = a
388 splitWithBreak f a b = a <> group (Line f) <> b
390 -- | The document @(x \<$\> y)@ concatenates document @x@ and @y@ with
391 -- a 'line' in between. (infixr 5)
392 (<$>) :: Doc -> Doc -> Doc
393 (<$>) = splitWithLine False
395 -- | The document @(x \<$$\> y)@ concatenates document @x@ and @y@
396 -- with a 'linebreak' in between. (infixr 5)
397 (<$$>) :: Doc -> Doc -> Doc
398 (<$$>) = splitWithLine True
400 splitWithLine :: Bool -> Doc -> Doc -> Doc
401 splitWithLine _ Empty b = b
402 splitWithLine _ a Empty = a
403 splitWithLine f a b = a <> Line f <> b
405 -- | The document @softline@ behaves like 'space' if the resulting
406 -- output fits the page, otherwise it behaves like 'line'.
408 -- > softline = group line
410 softline = group line
412 -- | The document @softbreak@ behaves like 'empty' if the resulting
413 -- output fits the page, otherwise it behaves like 'line'.
415 -- > softbreak = group linebreak
417 softbreak = group linebreak
419 -- | The document @spacebreak@ behaves like 'space' when rendered normally
420 -- but like 'empty' when using 'renderCompact' or 'renderOneLine'.
422 spacebreak = Spaces 1
424 -- | Document @(squotes x)@ encloses document @x@ with single quotes
426 squotes :: Doc -> Doc
427 squotes = enclose squote squote
429 -- | Document @(dquotes x)@ encloses document @x@ with double quotes
431 dquotes :: Doc -> Doc
432 dquotes = enclose dquote dquote
434 -- | Document @(braces x)@ encloses document @x@ in braces, \"{\" and
437 braces = enclose lbrace rbrace
439 -- | Document @(parens x)@ encloses document @x@ in parenthesis, \"(\"
442 parens = enclose lparen rparen
444 -- | Document @(angles x)@ encloses document @x@ in angles, \"\<\" and
447 angles = enclose langle rangle
449 -- | Document @(brackets x)@ encloses document @x@ in square brackets,
451 brackets :: Doc -> Doc
452 brackets = enclose lbracket rbracket
454 -- | The document @(enclose l r x)@ encloses document @x@ between
455 -- documents @l@ and @r@ using @(\<\>)@.
457 -- > enclose l r x = l <> x <> r
458 enclose :: Doc -> Doc -> Doc -> Doc
459 enclose l r x = l <> x <> r
461 -- | The document @lparen@ contains a left parenthesis, \"(\".
465 -- | The document @rparen@ contains a right parenthesis, \")\".
469 -- | The document @langle@ contains a left angle, \"\<\".
473 -- | The document @rangle@ contains a right angle, \">\".
477 -- | The document @lbrace@ contains a left brace, \"{\".
481 -- | The document @rbrace@ contains a right brace, \"}\".
485 -- | The document @lbracket@ contains a left square bracket, \"[\".
489 -- | The document @rbracket@ contains a right square bracket, \"]\".
493 -- | The document @squote@ contains a single quote, \"'\".
497 -- | The document @dquote@ contains a double quote, '\"'.
501 -- | The document @semi@ contains a semi colon, \";\".
505 -- | The document @colon@ contains a colon, \":\".
509 -- | The document @comma@ contains a comma, \",\".
513 -- | The document @space@ contains a single space, \" \".
515 -- > x <+> y = x <> space <> y
519 -- | The document @dot@ contains a single dot, \".\".
523 -- | The document @backslash@ contains a back slash, \"\\\".
525 backslash = char '\\'
527 -- | The document @equals@ contains an equal sign, \"=\".
531 -----------------------------------------------------------
532 -- Combinators for prelude types
533 -----------------------------------------------------------
535 -- string is like "text" but replaces '\n' by "line"
537 -- | The document @(string s)@ concatenates all characters in @s@
538 -- using @line@ for newline characters and @char@ for all other
539 -- characters. It is used instead of 'text' whenever the text
540 -- contains newline characters.
541 string :: Text -> Doc
542 string str = case T.uncons str of
544 Just ('\n',str') -> line <> string str'
545 _ -> case (T.span (/='\n') str) of
546 (xs,ys) -> text xs <> string ys
548 -- | The document @(bool b)@ shows the literal boolean @b@ using
553 -- | The document @(int i)@ shows the literal integer @i@ using
558 -- | The document @(integer i)@ shows the literal integer @i@ using
560 integer :: Integer -> Doc
563 -- | The document @(float f)@ shows the literal float @f@ using
565 float :: Float -> Doc
568 -- | The document @(double d)@ shows the literal double @d@ using
570 double :: Double -> Doc
573 -- | The document @(rational r)@ shows the literal rational @r@ using
575 rational :: Rational -> Doc
578 text' :: (Show a) => a -> Doc
579 text' = text . T.pack . show
581 -----------------------------------------------------------
582 -- overloading "pretty"
583 -----------------------------------------------------------
585 -- | The member @prettyList@ is only used to define the @instance
586 -- Pretty a => Pretty [a]@. In normal circumstances only the
587 -- @pretty@ function is used.
591 prettyList :: [a] -> Doc
592 prettyList = list . map pretty
594 instance Pretty a => Pretty [a] where
597 instance Pretty Doc where
600 instance Pretty Text where
603 instance Pretty () where
606 instance Pretty Bool where
609 instance Pretty Char where
612 prettyList s = string $ T.pack s
614 instance Pretty Int where
617 instance Pretty Integer where
620 instance Pretty Float where
623 instance Pretty Double where
626 --instance Pretty Rational where
627 -- pretty r = rational r
629 instance (Pretty a,Pretty b) => Pretty (a,b) where
630 pretty (x,y) = tupled [pretty x, pretty y]
632 instance (Pretty a,Pretty b,Pretty c) => Pretty (a,b,c) where
633 pretty (x,y,z)= tupled [pretty x, pretty y, pretty z]
635 instance Pretty a => Pretty (Maybe a) where
636 pretty Nothing = empty
638 pretty (Just x) = pretty x
640 -----------------------------------------------------------
641 -- semi primitive: fill and fillBreak
642 -----------------------------------------------------------
644 -- | The document @(fillBreak i x)@ first renders document @x@. It
645 -- then appends @space@s until the width is equal to @i@. If the
646 -- width of @x@ is already larger than @i@, the nesting level is
647 -- increased by @i@ and a @line@ is appended. When we redefine
648 -- @ptype@ in the previous example to use @fillBreak@, we get a
649 -- useful variation of the previous output:
652 -- > = fillBreak 6 (text name) <+> text "::" <+> text tp
654 -- The output will now be:
658 -- nest :: Int -> Doc -> Doc
662 fillBreak :: Int -> Doc -> Doc
663 fillBreak f x = width x (\w ->
665 then nest f linebreak
670 -- | The document @(fill i x)@ renders document @x@. It then appends
671 -- @space@s until the width is equal to @i@. If the width of @x@ is
672 -- already larger, nothing is appended. This combinator is quite
673 -- useful in practice to output a list of bindings. The following
674 -- example demonstrates this.
676 -- > types = [("empty","Doc")
677 -- > ,("nest","Int -> Doc -> Doc")
678 -- > ,("linebreak","Doc")]
681 -- > = fill 6 (text name) <+> text "::" <+> text tp
683 -- > test = text "let" <+> align (vcat (map ptype types))
685 -- Which is laid out as:
689 -- nest :: Int -> Doc -> Doc
692 fill :: Int -> Doc -> Doc
693 fill f d = width d (\w ->
700 width :: Doc -> (Int -> Doc) -> Doc
701 width d f = column (\k1 -> d <> column (\k2 -> f (k2 - k1)))
703 -----------------------------------------------------------
704 -- semi primitive: Alignment and indentation
705 -----------------------------------------------------------
707 -- | The document @(indent i x)@ indents document @x@ with @i@ spaces.
709 -- > test = indent 4 (fillSep (map text
710 -- > (words "the indent combinator indents these words !")))
712 -- Which lays out with a page width of 20 as:
720 indent :: Int -> Doc -> Doc
721 indent _ Empty = Empty
722 indent i d = hang i (spaced i <> d)
724 -- | The hang combinator implements hanging indentation. The document
725 -- @(hang i x)@ renders document @x@ with a nesting level set to the
726 -- current column plus @i@. The following example uses hanging
727 -- indentation for some text:
729 -- > test = hang 4 (fillSep (map text
730 -- > (words "the hang combinator indents these words !")))
732 -- Which lays out on a page with a width of 20 characters as:
735 -- the hang combinator
740 -- The @hang@ combinator is implemented as:
742 -- > hang i x = align (nest i x)
743 hang :: Int -> Doc -> Doc
744 hang i d = align (nest i d)
746 -- | The document @(align x)@ renders document @x@ with the nesting
747 -- level set to the current column. It is used for example to
750 -- As an example, we will put a document right above another one,
751 -- regardless of the current nesting level:
753 -- > x $$ y = align (x <$> y)
755 -- > test = text "hi" <+> (text "nice" $$ text "world")
757 -- which will be laid out as:
764 align d = column (\k ->
765 nesting (\i -> nest (k - i) d)) --nesting might be negative :-)
767 -----------------------------------------------------------
769 -----------------------------------------------------------
771 -- | The abstract data type @Doc@ represents pretty documents.
773 -- @Doc@ is an instance of the 'Show' class. @(show doc)@ pretty
774 -- prints document @doc@ with a page width of 100 characters and a
775 -- ribbon width of 40 characters.
777 -- > show (text "hello" <$> text "world")
779 -- Which would return the string \"hello\\nworld\", i.e.
786 | Char Char -- invariant: char is not '\n'
787 | Text !Int64 Builder -- invariant: text doesn't contain '\n'
788 | Line !Bool -- True <=> when undone by group, do not insert a space
789 -- | FlatAlt Doc Doc -- Render the first doc, but when
790 -- flattened, render the second.
793 | Union Doc Doc -- invariant: first lines of first doc longer than the first lines of the second doc
794 | Column (Int64 -> Doc)
795 | Nesting (Int64 -> Doc)
797 | Color ConsoleLayer ColorIntensity -- Introduces coloring /around/ the embedded document
800 | Intensify ConsoleIntensity Doc
802 | Underline Underlining Doc
803 | RestoreFormat (Maybe (ColorIntensity, Color)) -- Only used during the rendered phase, to signal a SGR should be issued to restore the terminal formatting.
804 (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).
805 (Maybe ConsoleIntensity) -- Intensity to revert to.
806 (Maybe Bool) -- Italicization to revert to.
807 (Maybe Underlining) -- Underlining to revert to.
809 instance IsString Doc where
810 fromString = string . T.pack
812 -- | In particular, note that the document @(x '<>' y)@ concatenates
813 -- document @x@ and document @y@. It is an associative operation
814 -- having 'empty' as a left and right unit. (infixr 6)
815 instance Monoid Doc where
819 -- | The data type @SimpleDoc@ represents rendered documents and is
820 -- used by the display functions.
822 -- The @Int@ in @SText@ contains the length of the string. The @Int@
823 -- in @SLine@ contains the indentation for that line. The library
824 -- provides two default display functions 'displayS' and
825 -- 'displayIO'. You can provide your own display function by writing
826 -- a function from a @SimpleDoc@ to your own output format.
827 data SimpleDoc = SEmpty
828 | SChar Char SimpleDoc
829 | SText !Int64 Builder SimpleDoc
830 | SLine !Int64 SimpleDoc
831 | SSGR [SGR] SimpleDoc
833 -- | The empty document is, indeed, empty. Although @empty@ has no
834 -- content, it does have a \'height\' of 1 and behaves exactly like
835 -- @(text \"\")@ (and is therefore not a unit of @\<$\>@).
839 is_empty :: Doc -> Bool
840 is_empty doc = case doc of
844 if_color :: Doc -> Doc -> Doc
847 -- | The document @(char c)@ contains the literal character @c@. The
848 -- character shouldn't be a newline (@'\n'@), the function 'line'
849 -- should be used for line breaks.
854 -- | The document @(text s)@ contains the literal string @s@. The
855 -- string shouldn't contain any newline (@'\n'@) characters. If the
856 -- string contains newline characters, the function 'string' should
861 | otherwise = Text (T.length s) (B.fromLazyText s)
863 -- | The @line@ document advances to the next line and indents to the
864 -- current nesting level. Document @line@ behaves like @(text \"
865 -- \")@ if the line break is undone by 'group' or if rendered with
869 --line = FlatAlt Line space
871 -- | The @linebreak@ document advances to the next line and indents to
872 -- the current nesting level. Document @linebreak@ behaves like
873 -- 'empty' if the line break is undone by 'group'.
875 linebreak = Line True
876 --linebreak = FlatAlt Line empty
878 beside :: Doc -> Doc -> Doc
883 -- | The document @(nest i x)@ renders document @x@ with the current
884 -- indentation level increased by @i@ (See also 'hang', 'align' and
887 -- > nest 2 (text "hello" <$> text "world") <$> text "!"
896 nest :: Int -> Doc -> Doc
898 nest i x = Nest (fromIntegral i) x
900 -- | Specifies how to create the document based upon which column it is in.
901 column :: (Int -> Doc) -> Doc
902 column f = Column (f . fromIntegral)
904 -- | Specifies how to nest the document based upon which column it is
906 nesting :: (Int -> Doc) -> Doc
907 nesting f = Nesting (f . fromIntegral)
909 -- | The @group@ combinator is used to specify alternative
910 -- layouts. The document @(group x)@ undoes all line breaks in
911 -- document @x@. The resulting line is added to the current line if
912 -- that fits the page. Otherwise, the document @x@ is rendered
913 -- without any changes.
915 group x = Union (flatten x) x
917 flatten :: Doc -> Doc
918 flatten (Cat x y) = Cat (flatten x) (flatten y)
919 flatten (Nest i x) = Nest i (flatten x)
920 flatten (Line brk) = if brk then Empty else Text 1 (B.singleton ' ')
921 flatten (Union x _) = flatten x
922 flatten (Column f) = Column (flatten . f)
923 flatten (Nesting f) = Nesting (flatten . f)
924 flatten (Color l i c x) = Color l i c (flatten x)
925 flatten (IfColor t f) = IfColor (flatten t) (flatten f)
926 flatten (Intensify i x) = Intensify i (flatten x)
927 flatten (Italicize b x) = Italicize b (flatten x)
928 flatten (Underline u x) = Underline u (flatten x)
929 -- flatten (FlatAlt x y) = y
930 flatten other = other --Empty,Char,Text,RestoreFormat
933 -----------------------------------------------------------
935 -----------------------------------------------------------
937 -- | Displays a document with the black forecolor
939 -- | Displays a document with the red forecolor
941 -- | Displays a document with the green forecolor
943 -- | Displays a document with the yellow forecolor
945 -- | Displays a document with the blue forecolor
947 -- | Displays a document with the magenta forecolor
948 magenta :: Doc -> Doc
949 -- | Displays a document with the cyan forecolor
951 -- | Displays a document with the white forecolor
953 -- | Displays a document with the dull black forecolor
954 dullblack :: Doc -> Doc
955 -- | Displays a document with the dull red forecolor
956 dullred :: Doc -> Doc
957 -- | Displays a document with the dull green forecolor
958 dullgreen :: Doc -> Doc
959 -- | Displays a document with the dull yellow forecolor
960 dullyellow :: Doc -> Doc
961 -- | Displays a document with the dull blue forecolor
962 dullblue :: Doc -> Doc
963 -- | Displays a document with the dull magenta forecolor
964 dullmagenta :: Doc -> Doc
965 -- | Displays a document with the dull cyan forecolor
966 dullcyan :: Doc -> Doc
967 -- | Displays a document with the dull white forecolor
968 dullwhite :: Doc -> Doc
969 (black, dullblack) = colorFunctions Black
970 (red, dullred) = colorFunctions Red
971 (green, dullgreen) = colorFunctions Green
972 (yellow, dullyellow) = colorFunctions Yellow
973 (blue, dullblue) = colorFunctions Blue
974 (magenta, dullmagenta) = colorFunctions Magenta
975 (cyan, dullcyan) = colorFunctions Cyan
976 (white, dullwhite) = colorFunctions White
978 -- | Displays a document with a forecolor given in the first parameter
979 color :: Color -> Doc -> Doc
980 -- | Displays a document with a dull forecolor given in the first parameter
981 dullcolor :: Color -> Doc -> Doc
982 color = Color Foreground Vivid
983 dullcolor = Color Foreground Dull
985 colorFunctions :: Color -> (Doc -> Doc, Doc -> Doc)
986 colorFunctions what = (color what, dullcolor what)
988 -- | Displays a document with the black backcolor
989 onblack :: Doc -> Doc
990 -- | Displays a document with the red backcolor
992 -- | Displays a document with the green backcolor
993 ongreen :: Doc -> Doc
994 -- | Displays a document with the yellow backcolor
995 onyellow :: Doc -> Doc
996 -- | Displays a document with the blue backcolor
998 -- | Displays a document with the magenta backcolor
999 onmagenta :: Doc -> Doc
1000 -- | Displays a document with the cyan backcolor
1001 oncyan :: Doc -> Doc
1002 -- | Displays a document with the white backcolor
1003 onwhite :: Doc -> Doc
1004 -- | Displays a document with the dull block backcolor
1005 ondullblack :: Doc -> Doc
1006 -- | Displays a document with the dull red backcolor
1007 ondullred :: Doc -> Doc
1008 -- | Displays a document with the dull green backcolor
1009 ondullgreen :: Doc -> Doc
1010 -- | Displays a document with the dull yellow backcolor
1011 ondullyellow :: Doc -> Doc
1012 -- | Displays a document with the dull blue backcolor
1013 ondullblue :: Doc -> Doc
1014 -- | Displays a document with the dull magenta backcolor
1015 ondullmagenta :: Doc -> Doc
1016 -- | Displays a document with the dull cyan backcolor
1017 ondullcyan :: Doc -> Doc
1018 -- | Displays a document with the dull white backcolor
1019 ondullwhite :: Doc -> Doc
1020 (onblack, ondullblack) = oncolorFunctions Black
1021 (onred, ondullred) = oncolorFunctions Red
1022 (ongreen, ondullgreen) = oncolorFunctions Green
1023 (onyellow, ondullyellow) = oncolorFunctions Yellow
1024 (onblue, ondullblue) = oncolorFunctions Blue
1025 (onmagenta, ondullmagenta) = oncolorFunctions Magenta
1026 (oncyan, ondullcyan) = oncolorFunctions Cyan
1027 (onwhite, ondullwhite) = oncolorFunctions White
1029 -- | Displays a document with a backcolor given in the first parameter
1030 oncolor :: Color -> Doc -> Doc
1031 -- | Displays a document with a dull backcolor given in the first parameter
1032 ondullcolor :: Color -> Doc -> Doc
1033 oncolor = Color Background Vivid
1034 ondullcolor = Color Background Dull
1036 oncolorFunctions :: Color -> (Doc -> Doc, Doc -> Doc)
1037 oncolorFunctions what = (oncolor what, ondullcolor what)
1040 -----------------------------------------------------------
1041 -- Console Intensity
1042 -----------------------------------------------------------
1044 -- | Displays a document in a heavier font weight
1046 bold = Intensify BoldIntensity
1048 -- | Displays a document in the normal font weight
1049 debold :: Doc -> Doc
1050 debold = Intensify NormalIntensity
1052 -- NB: I don't support FaintIntensity here because it is not widely supported by terminals.
1055 -----------------------------------------------------------
1057 -----------------------------------------------------------
1061 I'm in two minds about providing these functions, since italicization is so rarely implemented.
1062 It is especially bad because "italicization" may cause the meaning of colors to flip, which will
1063 look a bit weird, to say the least...
1066 -- | Displays a document in italics. This is not widely supported, and it's use is not recommended
1067 italicize :: Doc -> Doc
1068 italicize = Italicize True
1070 -- | Displays a document with no italics
1071 deitalicize :: Doc -> Doc
1072 deitalicize = Italicize False
1076 -----------------------------------------------------------
1078 -----------------------------------------------------------
1080 -- | Displays a document with underlining
1081 underline :: Doc -> Doc
1082 underline = Underline SingleUnderline
1084 -- | Displays a document with no underlining
1085 deunderline :: Doc -> Doc
1086 deunderline = Underline NoUnderline
1088 -- NB: I don't support DoubleUnderline here because it is not widely supported by terminals.
1090 -----------------------------------------------------------
1091 -- Removing formatting
1092 -----------------------------------------------------------
1094 -- | Removes all colorisation, emboldening and underlining from a document
1096 -- plain Fail = Fail
1098 plain c@(Char _) = c
1099 plain t@(Text _ _) = t
1100 plain l@(Line _) = l
1101 -- plain (FlatAlt x y) = FlatAlt (plain x) (plain y)
1102 plain (Cat x y) = Cat (plain x) (plain y)
1103 plain (Nest i x) = Nest i (plain x)
1104 plain (Union x y) = Union (plain x) (plain y)
1105 plain (Column f) = Column (plain . f)
1106 -- plain (Columns f) = Columns (plain . f)
1107 plain (Nesting f) = Nesting (plain . f)
1108 plain (Spaces l) = Spaces l
1109 plain (Color _ _ _ x) = plain x
1110 plain (Intensify _ x) = plain x
1111 plain (IfColor t f) = IfColor (plain t) (plain f)
1112 plain (Italicize _ x) = plain x
1113 plain (Underline _ x) = plain x
1114 plain (RestoreFormat _ _ _ _ _) = Empty
1116 -----------------------------------------------------------
1118 -----------------------------------------------------------
1120 -----------------------------------------------------------
1121 -- renderPretty: the default pretty printing algorithm
1122 -----------------------------------------------------------
1124 -- list of indentation/document pairs; saves an indirection over [(Int,Doc)]
1126 | Cons !Int64 Doc Docs
1128 -- | This is the default pretty printer which is used by 'show',
1129 -- 'putDoc' and 'hPutDoc'. @(renderPretty ribbonfrac width x)@
1130 -- renders document @x@ with a page width of @width@ and a ribbon
1131 -- width of @(ribbonfrac * width)@ characters. The ribbon width is
1132 -- the maximal amount of non-indentation characters on a line. The
1133 -- parameter @ribbonfrac@ should be between @0.0@ and @1.0@. If it
1134 -- is lower or higher, the ribbon width will be 0 or @width@
1136 renderPretty :: Bool -> Float -> Int -> Doc -> SimpleDoc
1137 renderPretty = renderFits fits1
1139 -- | A slightly smarter rendering algorithm with more lookahead. It provides
1140 -- provide earlier breaking on deeply nested structures
1141 -- For example, consider this python-ish pseudocode:
1142 -- @fun(fun(fun(fun(fun([abcdefg, abcdefg])))))@
1143 -- If we put a softbreak (+ nesting 2) after each open parenthesis, and align
1144 -- the elements of the list to match the opening brackets, this will render with
1145 -- @renderPretty@ and a page width of 20 as:
1147 -- fun(fun(fun(fun(fun([
1153 -- Where the 20c. boundary has been marked with |.
1154 -- Because @renderPretty@ only uses one-line lookahead, it sees that the first
1155 -- line fits, and is stuck putting the second and third lines after the 20-c
1156 -- mark. In contrast, @renderSmart@ will continue to check that the potential
1157 -- document up to the end of the indentation level. Thus, it will format the
1171 -- Which fits within the 20c. boundary.
1172 renderSmart :: Bool -> Float -> Int -> Doc -> SimpleDoc
1173 renderSmart = renderFits fitsR
1175 renderFits :: (Int64 -> Int64 -> Int64 -> SimpleDoc -> Bool)
1176 -> Bool -> Float -> Int -> Doc -> SimpleDoc
1177 renderFits fits with_color rfrac w doc
1178 -- I used to do a @SSGR [Reset]@ here, but if you do that it will result
1179 -- in any rendered @Doc@ containing at least some ANSI control codes. This
1180 -- may be undesirable if you want to render to non-ANSI devices by simply
1181 -- not making use of the ANSI color combinators I provide.
1183 -- What I "really" want to do here is do an initial Reset iff there is some
1184 -- ANSI color within the Doc, but that's a bit fiddly. I'll fix it if someone
1186 = best 0 0 Nothing Nothing Nothing Nothing Nothing (Cons 0 doc Nil)
1188 -- r :: the ribbon width in characters
1189 r = max 0 (min w64 (round (fromIntegral w * rfrac)))
1191 w64 = fromIntegral w
1193 -- best :: n = indentation of current line
1194 -- k = current column
1195 -- (ie. (k >= n) && (k - n == count of inserted characters)
1196 best _n _k _mb_fc _mb_bc _mb_in _mb_it _mb_un Nil = SEmpty
1197 best n k mb_fc mb_bc mb_in mb_it mb_un (Cons i d ds)
1200 Empty -> best_typical n k ds
1201 Char c -> let k' = k+1 in seq k' (SChar c (best_typical n k' ds))
1202 Text l s -> let k' = k+l in seq k' (SText l s (best_typical n k' ds))
1203 Line _ -> SLine i (best_typical i i ds)
1204 -- FlatAlt x _ -> best_typical n k (Cons i x ds)
1205 Cat x y -> best_typical n k (Cons i x (Cons i y ds))
1206 Nest j x -> let i' = i+j in seq i' (best_typical n k (Cons i' x ds))
1207 Union x y -> nicest n k (best_typical n k (Cons i x ds))
1208 (best_typical n k (Cons i y ds))
1209 Column f -> best_typical n k (Cons i (f k) ds)
1210 -- Columns f -> best_typical n k (Cons i (f (Just w)) ds)
1211 Nesting f -> best_typical n k (Cons i (f i) ds)
1212 Spaces l -> let k' = k+l in seq k' $ SText l (spaces l) (best_typical n k' ds)
1213 Color _ _ _ x | not with_color -> best_typical n k (Cons i x ds)
1214 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))
1216 mb_fc' = case l of { Background -> mb_fc; Foreground -> Just (t, c) }
1217 mb_bc' = case l of { Background -> Just (t, c); Foreground -> mb_bc }
1218 IfColor xt xf -> best_typical n k (if with_color then Cons i xt ds else Cons i xf ds)
1219 Intensify _ x | not with_color -> best_typical n k (Cons i x ds)
1220 Intensify t x -> SSGR [SetConsoleIntensity t] (best n k mb_fc mb_bc (Just t) mb_it mb_un (Cons i x ds_restore))
1221 Italicize _ x | not with_color -> best_typical n k (Cons i x ds)
1222 Italicize t x -> SSGR [SetItalicized t] (best n k mb_fc mb_bc mb_in (Just t) mb_un (Cons i x ds_restore))
1223 Underline _ x | not with_color -> best_typical n k (Cons i x ds)
1224 Underline u x -> SSGR [SetUnderlining u] (best n k mb_fc mb_bc mb_in mb_it (Just u) (Cons i x ds_restore))
1225 RestoreFormat _ _ _ _ _ | not with_color -> best_typical n k ds
1226 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)
1228 -- We need to be able to restore the entire SGR state, hence we carry around what we believe
1229 -- that state should be in all the arguments to this function. Note that in some cases we could
1230 -- avoid the Reset of the entire state, but not in general.
1231 sgrs = Reset : catMaybes [
1232 fmap (uncurry (SetColor Foreground)) mb_fc',
1233 fmap (uncurry (SetColor Background)) mb_bc',
1234 fmap SetConsoleIntensity mb_in',
1235 fmap SetItalicized mb_it',
1236 fmap SetUnderlining mb_un'
1239 best_typical n' k' ds' = best n' k' mb_fc mb_bc mb_in mb_it mb_un ds'
1240 ds_restore = Cons i (RestoreFormat mb_fc mb_bc mb_in mb_it mb_un) ds
1242 --nicest :: r = ribbon width, w = page width,
1243 -- n = indentation of current line, k = current column
1244 -- x and y, the (simple) documents to chose from.
1245 -- precondition: first lines of x are longer than the first lines of y.
1246 nicest n k x y | fits w64 (min n k) width_ x = x
1249 width_ = min (w64 - k) (r - k + n)
1251 -- @fits1@ does 1 line lookahead.
1252 fits1 :: Int64 -> Int64 -> Int64 -> SimpleDoc -> Bool
1253 fits1 _ _ w _x | w < 0 = False
1254 --fits1 _ _ w SFail = False
1255 fits1 _ _ _w SEmpty = True
1256 fits1 p m w (SChar _c x) = fits1 p m (w - 1) x
1257 fits1 p m w (SText l _s x) = fits1 p m (w - l) x
1258 fits1 _ _ _w (SLine _i _x) = True
1259 fits1 p m w (SSGR _ x) = fits1 p m w x
1261 -- @fitsR@ has a little more lookahead: assuming that nesting roughly
1262 -- corresponds to syntactic depth, @fitsR@ checks that not only the current line
1263 -- fits, but the entire syntactic structure being formatted at this level of
1264 -- indentation fits. If we were to remove the second case for @SLine@, we would
1265 -- check that not only the current structure fits, but also the rest of the
1266 -- document, which would be slightly more intelligent but would have exponential
1267 -- runtime (and is prohibitively expensive in practice).
1269 -- m = minimum nesting level to fit in
1270 -- w = the width in which to fit the first line
1271 fitsR :: Int64 -> Int64 -> Int64 -> SimpleDoc -> Bool
1272 fitsR _p _m w _x | w < 0 = False
1273 --fitsR p m w SFail = False
1274 fitsR _p _m _w SEmpty = True
1275 fitsR p m w (SChar _c x) = fitsR p m (w - 1) x
1276 fitsR p m w (SText l _s x) = fitsR p m (w - l) x
1277 fitsR p m _w (SLine i x) | m < i = fitsR p m (p - i) x
1279 fitsR p m w (SSGR _ x) = fitsR p m w x
1281 -----------------------------------------------------------
1282 -- renderCompact: renders documents without indentation
1283 -- fast and fewer characters output, good for machines
1284 -----------------------------------------------------------
1287 -- | @(renderCompact x)@ renders document @x@ without adding any
1288 -- indentation. Since no \'pretty\' printing is involved, this
1289 -- renderer is very fast. The resulting output contains fewer
1290 -- characters than a pretty printed version and can be used for
1291 -- output that is read by other programs.
1292 renderCompact :: Bool -> Doc -> SimpleDoc
1293 renderCompact with_color dc
1294 = scan 0 Nothing Nothing Nothing Nothing Nothing [dc]
1296 scan _ _mb_fc _mb_bc _mb_in _mb_it _mb_un [] = SEmpty
1297 scan k mb_fc mb_bc mb_in mb_it mb_un (d:ds)
1300 Char c -> let k' = k+1 in seq k' (SChar c (scan' k' ds))
1301 Text l s -> let k' = k+l in seq k' (SText l s (scan' k' ds))
1302 Line _ -> SLine 0 (scan' 0 ds)
1303 -- FlatAlt x _ -> scan' k (x:ds)
1304 Cat x y -> scan' k (x:y:ds)
1305 Nest _ x -> scan' k (x:ds)
1306 Union _ y -> scan' k (y:ds)
1307 Column f -> scan' k (f k:ds)
1308 -- Columns f -> scan' k (f Nothing:ds)
1309 Nesting f -> scan' k (f 0:ds)
1310 Spaces _ -> scan' k ds
1311 Color _ _ _ x | not with_color -> scan' k (x:ds)
1312 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))
1314 mb_fc' = case l of { Background -> mb_fc; Foreground -> Just (t, c) }
1315 mb_bc' = case l of { Background -> Just (t, c); Foreground -> mb_bc }
1316 IfColor x _ | not with_color -> scan' k (x:ds)
1317 IfColor _ x -> scan' k (x:ds)
1318 Intensify _ x | not with_color -> scan' k (x:ds)
1319 Intensify t x -> SSGR [SetConsoleIntensity t] (scan k mb_fc mb_bc (Just t) mb_it mb_un (x:ds_restore))
1320 Italicize _ x | not with_color -> scan' k (x:ds)
1321 Italicize t x -> SSGR [SetItalicized t] (scan k mb_fc mb_bc mb_in (Just t) mb_un (x:ds_restore))
1322 Underline _ x | not with_color -> scan' k (x:ds)
1323 Underline u x -> SSGR [SetUnderlining u] (scan k mb_fc mb_bc mb_in mb_it (Just u) (x:ds_restore))
1324 RestoreFormat _ _ _ _ _ | not with_color -> scan' k ds
1325 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)
1327 sgrs = Reset : catMaybes [
1328 fmap (uncurry (SetColor Foreground)) mb_fc',
1329 fmap (uncurry (SetColor Background)) mb_bc',
1330 fmap SetConsoleIntensity mb_in',
1331 fmap SetItalicized mb_it',
1332 fmap SetUnderlining mb_un'
1335 scan' k' ds' = scan k' mb_fc mb_bc mb_in mb_it mb_un ds'
1336 ds_restore = RestoreFormat mb_fc mb_bc mb_in mb_it mb_un:ds
1338 -- | @(renderOneLine x)@ renders document @x@ without adding any
1339 -- indentation or newlines.
1340 renderOneLine :: Bool -> Doc -> SimpleDoc
1341 renderOneLine with_color dc
1342 = scan 0 Nothing Nothing Nothing Nothing Nothing [dc]
1344 scan _ _mb_fc _mb_bc _mb_in _mb_it _mb_un [] = SEmpty
1345 scan k mb_fc mb_bc mb_in mb_it mb_un (d:ds)
1348 Char c -> let k' = k+1 in seq k' (SChar c (scan' k' ds))
1349 Text l s -> let k' = k+l in seq k' (SText l s (scan' k' ds))
1350 Line False -> let k' = k+1 in seq k' (SChar ' ' (scan' k' ds))
1351 Line _ -> scan' k ds
1352 Cat x y -> scan' k (x:y:ds)
1353 Nest _ x -> scan' k (x:ds)
1354 Union _ y -> scan' k (y:ds)
1355 Column f -> scan' k (f k:ds)
1356 Nesting f -> scan' k (f 0:ds)
1357 Spaces _ -> scan' k ds
1358 Color _ _ _ x | not with_color -> scan' k (x:ds)
1359 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))
1361 mb_fc' = case l of { Background -> mb_fc; Foreground -> Just (t, c) }
1362 mb_bc' = case l of { Background -> Just (t, c); Foreground -> mb_bc }
1363 IfColor x _ | with_color -> scan' k (x:ds)
1364 IfColor _ x -> scan' k (x:ds)
1365 Intensify _ x | with_color -> scan' k (x:ds)
1366 Intensify t x -> SSGR [SetConsoleIntensity t] (scan k mb_fc mb_bc (Just t) mb_it mb_un (x:ds_restore))
1367 Italicize _ x | with_color -> scan' k (x:ds)
1368 Italicize t x -> SSGR [SetItalicized t] (scan k mb_fc mb_bc mb_in (Just t) mb_un (x:ds_restore))
1369 Underline _ x | with_color -> scan' k (x:ds)
1370 Underline u x -> SSGR [SetUnderlining u] (scan k mb_fc mb_bc mb_in mb_it (Just u) (x:ds_restore))
1371 RestoreFormat _ _ _ _ _ | with_color -> scan' k ds
1372 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)
1374 sgrs = Reset : catMaybes [
1375 fmap (uncurry (SetColor Foreground)) mb_fc',
1376 fmap (uncurry (SetColor Background)) mb_bc',
1377 fmap SetConsoleIntensity mb_in',
1378 fmap SetItalicized mb_it',
1379 fmap SetUnderlining mb_un'
1382 scan' k' ds' = scan k' mb_fc mb_bc mb_in mb_it mb_un ds'
1383 ds_restore = RestoreFormat mb_fc mb_bc mb_in mb_it mb_un:ds
1385 -----------------------------------------------------------
1386 -- Displayers: displayS and displayIO
1387 -----------------------------------------------------------
1390 -- | @(displayB simpleDoc)@ takes the output @simpleDoc@ from a
1391 -- rendering function and transforms it to a 'Builder' type (for
1392 -- further manipulation before converting to a lazy 'Text').
1393 displayB :: SimpleDoc -> Builder
1394 displayB SEmpty = mempty
1395 displayB (SChar c x) = c `consB` displayB x
1396 displayB (SText _ s x) = s `mappend` displayB x
1397 displayB (SLine i x) = '\n' `consB` (indentation i `mappend` displayB x)
1398 displayB (SSGR s x) = B.fromLazyText (T.pack (setSGRCode s)) `mappend` displayB x
1400 consB :: Char -> Builder -> Builder
1401 c `consB` b = B.singleton c `mappend` b
1403 -- | @(displayT simpleDoc)@ takes the output @simpleDoc@ from a
1404 -- rendering function and transforms it to a lazy 'Text' value.
1406 -- > showWidth :: Int -> Doc -> Text
1407 -- > showWidth w x = displayT (renderPretty 0.4 w x)
1408 displayT :: SimpleDoc -> Text
1409 displayT = B.toLazyText . displayB
1411 -- | @(displayIO handle simpleDoc)@ writes @simpleDoc@ to the
1412 -- file handle @handle@. This function is used for example by
1415 -- > hPutDoc handle doc = displayIO handle (renderPretty 0.4 100 doc)
1416 displayIO :: Handle -> SimpleDoc -> IO ()
1417 displayIO handle simpleDoc
1420 display SEmpty = return ()
1421 display (SChar c x) = hPutChar handle c >> display x
1422 display (SText _ s x) = T.hPutStr handle (B.toLazyText s) >> display x
1423 display (SLine i x) = T.hPutStr handle newLine >> display x
1425 newLine = B.toLazyText $ '\n' `consB` indentation i
1426 display (SSGR s x) = hSetSGR handle s >> display x
1428 -----------------------------------------------------------
1429 -- default pretty printers: show, putDoc and hPutDoc
1430 -----------------------------------------------------------
1432 instance Show Doc where
1433 showsPrec d doc = showsPrec d (displayT $ renderPretty True 0.4 80 doc)
1434 show doc = T.unpack (displayT $ renderPretty True 0.4 80 doc)
1436 instance Show SimpleDoc where
1437 show simpleDoc = T.unpack (displayT simpleDoc)
1439 -- | The action @(putDoc doc)@ pretty prints document @doc@ to the
1440 -- standard output, with a page width of 100 characters and a ribbon
1441 -- width of 40 characters.
1444 -- > main = do{ putDoc (text "hello" <+> text "world") }
1446 -- Which would output
1451 putDoc :: Doc -> IO ()
1452 putDoc doc = hPutDoc stdout doc
1454 -- | @(hPutDoc handle doc)@ pretty prints document @doc@ to the file
1455 -- handle @handle@ with a page width of 100 characters and a ribbon
1456 -- width of 40 characters.
1458 -- > main = do handle <- 'openFile' "MyFile" 'WriteMode'
1459 -- > 'hPutDoc' handle ('vcat' ('map' 'text'
1460 -- > ['T.pack' "vertical", 'T.pack' "text"]))
1461 -- > 'hClose' handle
1462 hPutDoc :: Handle -> Doc -> IO ()
1463 hPutDoc handle doc = displayIO handle (renderPretty True 0.4 80 doc)
1465 -----------------------------------------------------------
1467 -- "indentation" used to insert tabs but tabs seem to cause
1468 -- more trouble than they solve :-)
1469 -----------------------------------------------------------
1470 spaces :: Int64 -> Builder
1473 | otherwise = B.fromLazyText $ T.replicate n (T.singleton ' ')
1475 spaced :: Int -> Doc
1476 spaced l = Spaces l'
1480 -- An alias for readability purposes
1481 indentation :: Int64 -> Builder
1482 indentation = spaces
1484 -- | Return a 'Doc' from a strict 'Text'
1485 strict_text :: Data.Text.Text -> Doc
1486 strict_text = text . T.fromStrict
1488 -- | Return a 'Doc' concatenating converted values of a 'Foldable'
1489 -- separated by a given 'Doc'.
1491 :: Data.Foldable.Foldable t
1492 => Doc -> (a -> Doc) -> t a -> Doc
1493 intercalate separator f =
1495 (\doc x -> doc <> (if is_empty doc then empty else separator) <> f x)
1498 class ToDoc m a where
1499 toDoc :: m -> a -> Doc
1500 instance ToDoc m Doc where
1503 -- LocalWords: PPrint combinators Wadler Wadler's encloseSep