2 -----------------------------------------------------------------------------
4 -- Module : Text.PrettyPrint.Leijen.Text
5 -- Copyright : Ivan Lazar Miljenovic (c) 2010,
6 -- Daan Leijen (c) 2000, http://www.cs.uu.nl/~daan
7 -- License : BSD-style (see the file LICENSE)
9 -- Maintainer : Ivan.Miljenovic@gmail.com
10 -- Stability : provisional
11 -- Portability : portable
13 -- This library is a port of the /wl-pprint/ package to use 'Text' values rather than 'String's.
15 -- Pretty print module based on Philip Wadler's \"prettier printer\"
18 -- \"A prettier printer\"
19 -- Draft paper, April 1997, revised March 1998.
20 -- <http://cm.bell-labs.com/cm/cs/who/wadler/papers/prettier/prettier.ps>
23 -- PPrint is an implementation of the pretty printing combinators
24 -- described by Philip Wadler (1997). In their bare essence, the
25 -- combinators of Wadler are not expressive enough to describe some
26 -- commonly occurring layouts. The PPrint library adds new primitives
27 -- to describe these layouts and works well in practice.
29 -- The library is based on a single way to concatenate documents,
30 -- which is associative and has both a left and right unit. This
31 -- simple design leads to an efficient and short implementation. The
32 -- simplicity is reflected in the predictable behaviour of the
33 -- combinators which make them easy to use in practice.
35 -- A thorough description of the primitive combinators and their
36 -- implementation can be found in Philip Wadler's paper
37 -- (1997). Additions and the main differences with his original paper
40 -- * The nil document is called empty.
42 -- * The above combinator is called '<$>'. The operator '</>' is used
43 -- for soft line breaks.
45 -- * There are three new primitives: 'align', 'fill' and
46 -- 'fillBreak'. These are very useful in practice.
48 -- * Lots of other useful combinators, like 'fillSep' and 'list'.
50 -- * There are two renderers, 'renderPretty' for pretty printing and
51 -- 'renderCompact' for compact output. The pretty printing algorithm
52 -- also uses a ribbon-width now for even prettier output.
54 -- * There are two displayers, 'displayT' for 'Text' values and 'displayIO'
55 -- for file based output.
57 -- * There is a 'Pretty' class.
59 -- * The implementation uses optimised representations and strictness
62 -- Ways that this library differs from /wl-pprint/ (apart from using
63 -- 'Text' rather than 'String'):
65 -- * Smarter treatment of 'empty' sub-documents (partially copied over
66 -- from the /pretty/ library).
67 -----------------------------------------------------------
68 module Hcompta.Format.Text (
72 -- * Basic combinators
73 empty, char, text, (<>), nest, line, linebreak, group, softline,
74 softbreak, spacebreak,
78 -- | The combinators in this section can not be described by Wadler's
79 -- original combinators. They align their output relative to the
80 -- current output position - in contrast to @nest@ which always
81 -- aligns to the current nesting level. This deprives these
82 -- combinators from being \`optimal\'. In practice however they
83 -- prove to be very useful. The combinators in this section should
84 -- be used with care, since they are more expensive than the other
85 -- combinators. For example, @align@ shouldn't be used to pretty
86 -- print all top-level declarations of a language, but using @hang@
87 -- for let expressions is fine.
88 align, hang, indent, encloseSep, list, tupled, semiBraces,
91 (<+>), (<++>), (<$>), (</>), (<$$>), (<//>),
94 hsep, vsep, fillSep, sep, hcat, vcat, fillCat, cat, punctuate,
99 -- * Bracketing combinators
100 enclose, squotes, dquotes, parens, angles, braces, brackets,
102 -- * Character documents
103 lparen, rparen, langle, rangle, lbrace, rbrace, lbracket, rbracket,
104 squote, dquote, semi, colon, comma, space, dot, backslash, equals,
106 -- * Primitive type documents
107 string, int, integer, float, double, rational, bool,
109 -- * Position-based combinators
110 column, nesting, width,
116 SimpleDoc(..), renderPretty, renderCompact, renderOneLine,
117 displayB, displayT, displayIO, putDoc, hPutDoc
121 #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 710
122 import Prelude hiding ((<$>))
125 import Data.String (IsString (..))
126 import System.IO (Handle, hPutChar, stdout)
128 import Data.Int (Int64)
129 import Data.Monoid (Monoid (..), (<>))
130 import Data.Text.Lazy (Text)
131 import qualified Data.Text.Lazy as T
132 import Data.Text.Lazy.Builder (Builder)
133 import qualified Data.Text.Lazy.Builder as B
134 import qualified Data.Text.Lazy.IO as T
137 infixr 5 </>,<//>,<$>,<$$>
141 -----------------------------------------------------------
142 -- list, tupled and semiBraces pretty print a list of
143 -- documents either horizontally or vertically aligned.
144 -----------------------------------------------------------
147 -- | The document @(list xs)@ comma separates the documents @xs@ and
148 -- encloses them in square brackets. The documents are rendered
149 -- horizontally if that fits the page. Otherwise they are aligned
150 -- vertically. All comma separators are put in front of the
153 list = encloseSep lbracket rbracket comma
155 -- | The document @(tupled xs)@ comma separates the documents @xs@ and
156 -- encloses them in parenthesis. The documents are rendered
157 -- horizontally if that fits the page. Otherwise they are aligned
158 -- vertically. All comma separators are put in front of the
160 tupled :: [Doc] -> Doc
161 tupled = encloseSep lparen rparen comma
163 -- | The document @(semiBraces xs)@ separates the documents @xs@ with
164 -- semi colons and encloses them in braces. The documents are
165 -- rendered horizontally if that fits the page. Otherwise they are
166 -- aligned vertically. All semi colons are put in front of the
168 semiBraces :: [Doc] -> Doc
169 semiBraces = encloseSep lbrace rbrace semi
171 -- | The document @(encloseSep l r sep xs)@ concatenates the documents
172 -- @xs@ separated by @sep@ and encloses the resulting document by
173 -- @l@ and @r@. The documents are rendered horizontally if that fits
174 -- the page. Otherwise they are aligned vertically. All separators
175 -- are put in front of the elements. For example, the combinator
176 -- 'list' can be defined with @encloseSep@:
178 -- > list xs = encloseSep lbracket rbracket comma xs
179 -- > test = text "list" <+> (list (map int [10,200,3000]))
181 -- Which is laid out with a page width of 20 as:
184 -- list [10,200,3000]
187 -- But when the page width is 15, it is laid out as:
194 encloseSep :: Doc -> Doc -> Doc -> [Doc] -> Doc
195 encloseSep left right sp ds
198 [d] -> left <> d <> right
199 _ -> align (cat (zipWith (<>) (left : repeat sp) ds) <> right)
201 -----------------------------------------------------------
202 -- punctuate p [d1,d2,...,dn] => [d1 <> p,d2 <> p, ... ,dn]
203 -----------------------------------------------------------
206 -- | @(punctuate p xs)@ concatenates all documents in @xs@ with
207 -- document @p@ except for the last document.
209 -- > someText = map text ["words","in","a","tuple"]
210 -- > test = parens (align (cat (punctuate comma someText)))
212 -- This is laid out on a page width of 20 as:
215 -- (words,in,a,tuple)
218 -- But when the page width is 15, it is laid out as:
227 -- (If you want put the commas in front of their elements instead of
228 -- at the end, you should use 'tupled' or, in general, 'encloseSep'.)
229 punctuate :: Doc -> [Doc] -> [Doc]
231 punctuate _ [d] = [d]
232 punctuate p (d:ds) = (d <> p) : punctuate p ds
235 -----------------------------------------------------------
236 -- high-level combinators
237 -----------------------------------------------------------
240 -- | The document @(sep xs)@ concatenates all documents @xs@ either
241 -- horizontally with @(\<+\>)@, if it fits the page, or vertically
244 -- > sep xs = group (vsep xs)
248 -- | The document @(fillSep xs)@ concatenates documents @xs@
249 -- horizontally with @(\<+\>)@ as long as its fits the page, then
250 -- inserts a @line@ and continues doing that for all documents in
253 -- > fillSep xs = foldr (</>) empty xs
254 fillSep :: [Doc] -> Doc
257 -- | The document @(hsep xs)@ concatenates all documents @xs@
258 -- horizontally with @(\<+\>)@.
262 -- | The document @(vsep xs)@ concatenates all documents @xs@
263 -- vertically with @(\<$\>)@. If a 'group' undoes the line breaks
264 -- inserted by @vsep@, all documents are separated with a space.
266 -- > someText = map text (words ("text to lay out"))
268 -- > test = text "some" <+> vsep someText
270 -- This is laid out as:
279 -- The 'align' combinator can be used to align the documents under
280 -- their first element
282 -- > test = text "some" <+> align (vsep someText)
284 -- Which is printed as:
295 -- | The document @(cat xs)@ concatenates all documents @xs@ either
296 -- horizontally with @(\<\>)@, if it fits the page, or vertically
299 -- > cat xs = group (vcat xs)
303 -- | The document @(fillCat xs)@ concatenates documents @xs@
304 -- horizontally with @(\<\>)@ as long as its fits the page, then
305 -- inserts a @linebreak@ and continues doing that for all documents
308 -- > fillCat xs = foldr (<//>) empty xs
309 fillCat :: [Doc] -> Doc
310 fillCat = fold (<//>)
312 -- | The document @(hcat xs)@ concatenates all documents @xs@
313 -- horizontally with @(\<\>)@.
317 -- | The document @(vcat xs)@ concatenates all documents @xs@
318 -- vertically with @(\<$$\>)@. If a 'group' undoes the line breaks
319 -- inserted by @vcat@, all documents are directly concatenated.
323 fold :: (Doc -> Doc -> Doc) -> [Doc] -> Doc
325 fold f ds = foldr1 f ds
327 -- | The document @(x \<+\> y)@ concatenates document @x@ and @y@ with
328 -- a 'space' in between. (infixr 6)
329 (<+>) :: Doc -> Doc -> Doc
332 x <+> y = x <> space <> y
334 -- | The document @(x \<++\> y)@ concatenates document @x@ and @y@ with
335 -- a 'spacebreak' in between. (infixr 6)
336 (<++>) :: Doc -> Doc -> Doc
339 x <++> y = x <> spacebreak <> y
342 -- | The document @(x \<\/\> y)@ concatenates document @x@ and @y@
343 -- with a 'softline' in between. This effectively puts @x@ and @y@
344 -- either next to each other (with a @space@ in between) or
345 -- underneath each other. (infixr 5)
346 (</>) :: Doc -> Doc -> Doc
347 (</>) = splitWithBreak False
349 -- | The document @(x \<\/\/\> y)@ concatenates document @x@ and @y@
350 -- with a 'softbreak' in between. This effectively puts @x@ and @y@
351 -- either right next to each other or underneath each other. (infixr
353 (<//>) :: Doc -> Doc -> Doc
354 (<//>) = splitWithBreak True
356 splitWithBreak :: Bool -> Doc -> Doc -> Doc
357 splitWithBreak _ Empty b = b
358 splitWithBreak _ a Empty = a
359 splitWithBreak f a b = a <> group (Line f) <> b
361 -- | The document @(x \<$\> y)@ concatenates document @x@ and @y@ with
362 -- a 'line' in between. (infixr 5)
363 (<$>) :: Doc -> Doc -> Doc
364 (<$>) = splitWithLine False
366 -- | The document @(x \<$$\> y)@ concatenates document @x@ and @y@
367 -- with a 'linebreak' in between. (infixr 5)
368 (<$$>) :: Doc -> Doc -> Doc
369 (<$$>) = splitWithLine True
371 splitWithLine :: Bool -> Doc -> Doc -> Doc
372 splitWithLine _ Empty b = b
373 splitWithLine _ a Empty = a
374 splitWithLine f a b = a <> Line f <> b
376 -- | The document @softline@ behaves like 'space' if the resulting
377 -- output fits the page, otherwise it behaves like 'line'.
379 -- > softline = group line
381 softline = group line
383 -- | The document @softbreak@ behaves like 'empty' if the resulting
384 -- output fits the page, otherwise it behaves like 'line'.
386 -- > softbreak = group linebreak
388 softbreak = group linebreak
390 -- | The document @spacebreak@ behaves like 'space' when rendered normally
391 -- but like 'empty' when using 'renderCompact' or 'renderOneLine'.
393 spacebreak = Spaces 1
395 -- | Document @(squotes x)@ encloses document @x@ with single quotes
397 squotes :: Doc -> Doc
398 squotes = enclose squote squote
400 -- | Document @(dquotes x)@ encloses document @x@ with double quotes
402 dquotes :: Doc -> Doc
403 dquotes = enclose dquote dquote
405 -- | Document @(braces x)@ encloses document @x@ in braces, \"{\" and
408 braces = enclose lbrace rbrace
410 -- | Document @(parens x)@ encloses document @x@ in parenthesis, \"(\"
413 parens = enclose lparen rparen
415 -- | Document @(angles x)@ encloses document @x@ in angles, \"\<\" and
418 angles = enclose langle rangle
420 -- | Document @(brackets x)@ encloses document @x@ in square brackets,
422 brackets :: Doc -> Doc
423 brackets = enclose lbracket rbracket
425 -- | The document @(enclose l r x)@ encloses document @x@ between
426 -- documents @l@ and @r@ using @(\<\>)@.
428 -- > enclose l r x = l <> x <> r
429 enclose :: Doc -> Doc -> Doc -> Doc
430 enclose l r x = l <> x <> r
432 -- | The document @lparen@ contains a left parenthesis, \"(\".
436 -- | The document @rparen@ contains a right parenthesis, \")\".
440 -- | The document @langle@ contains a left angle, \"\<\".
444 -- | The document @rangle@ contains a right angle, \">\".
448 -- | The document @lbrace@ contains a left brace, \"{\".
452 -- | The document @rbrace@ contains a right brace, \"}\".
456 -- | The document @lbracket@ contains a left square bracket, \"[\".
460 -- | The document @rbracket@ contains a right square bracket, \"]\".
464 -- | The document @squote@ contains a single quote, \"'\".
468 -- | The document @dquote@ contains a double quote, '\"'.
472 -- | The document @semi@ contains a semi colon, \";\".
476 -- | The document @colon@ contains a colon, \":\".
480 -- | The document @comma@ contains a comma, \",\".
484 -- | The document @space@ contains a single space, \" \".
486 -- > x <+> y = x <> space <> y
490 -- | The document @dot@ contains a single dot, \".\".
494 -- | The document @backslash@ contains a back slash, \"\\\".
496 backslash = char '\\'
498 -- | The document @equals@ contains an equal sign, \"=\".
502 -----------------------------------------------------------
503 -- Combinators for prelude types
504 -----------------------------------------------------------
506 -- string is like "text" but replaces '\n' by "line"
508 -- | The document @(string s)@ concatenates all characters in @s@
509 -- using @line@ for newline characters and @char@ for all other
510 -- characters. It is used instead of 'text' whenever the text
511 -- contains newline characters.
512 string :: Text -> Doc
513 string str = case T.uncons str of
515 Just ('\n',str') -> line <> string str'
516 _ -> case (T.span (/='\n') str) of
517 (xs,ys) -> text xs <> string ys
519 -- | The document @(bool b)@ shows the literal boolean @b@ using
524 -- | The document @(int i)@ shows the literal integer @i@ using
529 -- | The document @(integer i)@ shows the literal integer @i@ using
531 integer :: Integer -> Doc
534 -- | The document @(float f)@ shows the literal float @f@ using
536 float :: Float -> Doc
539 -- | The document @(double d)@ shows the literal double @d@ using
541 double :: Double -> Doc
544 -- | The document @(rational r)@ shows the literal rational @r@ using
546 rational :: Rational -> Doc
549 text' :: (Show a) => a -> Doc
550 text' = text . T.pack . show
552 -----------------------------------------------------------
553 -- overloading "pretty"
554 -----------------------------------------------------------
556 -- | The member @prettyList@ is only used to define the @instance
557 -- Pretty a => Pretty [a]@. In normal circumstances only the
558 -- @pretty@ function is used.
562 prettyList :: [a] -> Doc
563 prettyList = list . map pretty
565 instance Pretty a => Pretty [a] where
568 instance Pretty Doc where
571 instance Pretty Text where
574 instance Pretty () where
577 instance Pretty Bool where
580 instance Pretty Char where
583 prettyList s = string $ T.pack s
585 instance Pretty Int where
588 instance Pretty Integer where
591 instance Pretty Float where
594 instance Pretty Double where
597 --instance Pretty Rational where
598 -- pretty r = rational r
600 instance (Pretty a,Pretty b) => Pretty (a,b) where
601 pretty (x,y) = tupled [pretty x, pretty y]
603 instance (Pretty a,Pretty b,Pretty c) => Pretty (a,b,c) where
604 pretty (x,y,z)= tupled [pretty x, pretty y, pretty z]
606 instance Pretty a => Pretty (Maybe a) where
607 pretty Nothing = empty
609 pretty (Just x) = pretty x
611 -----------------------------------------------------------
612 -- semi primitive: fill and fillBreak
613 -----------------------------------------------------------
615 -- | The document @(fillBreak i x)@ first renders document @x@. It
616 -- then appends @space@s until the width is equal to @i@. If the
617 -- width of @x@ is already larger than @i@, the nesting level is
618 -- increased by @i@ and a @line@ is appended. When we redefine
619 -- @ptype@ in the previous example to use @fillBreak@, we get a
620 -- useful variation of the previous output:
623 -- > = fillBreak 6 (text name) <+> text "::" <+> text tp
625 -- The output will now be:
629 -- nest :: Int -> Doc -> Doc
633 fillBreak :: Int -> Doc -> Doc
634 fillBreak f x = width x (\w ->
636 then nest f linebreak
641 -- | The document @(fill i x)@ renders document @x@. It then appends
642 -- @space@s until the width is equal to @i@. If the width of @x@ is
643 -- already larger, nothing is appended. This combinator is quite
644 -- useful in practice to output a list of bindings. The following
645 -- example demonstrates this.
647 -- > types = [("empty","Doc")
648 -- > ,("nest","Int -> Doc -> Doc")
649 -- > ,("linebreak","Doc")]
652 -- > = fill 6 (text name) <+> text "::" <+> text tp
654 -- > test = text "let" <+> align (vcat (map ptype types))
656 -- Which is laid out as:
660 -- nest :: Int -> Doc -> Doc
663 fill :: Int -> Doc -> Doc
664 fill f d = width d (\w ->
671 width :: Doc -> (Int -> Doc) -> Doc
672 width d f = column (\k1 -> d <> column (\k2 -> f (k2 - k1)))
674 -----------------------------------------------------------
675 -- semi primitive: Alignment and indentation
676 -----------------------------------------------------------
678 -- | The document @(indent i x)@ indents document @x@ with @i@ spaces.
680 -- > test = indent 4 (fillSep (map text
681 -- > (words "the indent combinator indents these words !")))
683 -- Which lays out with a page width of 20 as:
691 indent :: Int -> Doc -> Doc
692 indent _ Empty = Empty
693 indent i d = hang i (spaced i <> d)
695 -- | The hang combinator implements hanging indentation. The document
696 -- @(hang i x)@ renders document @x@ with a nesting level set to the
697 -- current column plus @i@. The following example uses hanging
698 -- indentation for some text:
700 -- > test = hang 4 (fillSep (map text
701 -- > (words "the hang combinator indents these words !")))
703 -- Which lays out on a page with a width of 20 characters as:
706 -- the hang combinator
711 -- The @hang@ combinator is implemented as:
713 -- > hang i x = align (nest i x)
714 hang :: Int -> Doc -> Doc
715 hang i d = align (nest i d)
717 -- | The document @(align x)@ renders document @x@ with the nesting
718 -- level set to the current column. It is used for example to
721 -- As an example, we will put a document right above another one,
722 -- regardless of the current nesting level:
724 -- > x $$ y = align (x <$> y)
726 -- > test = text "hi" <+> (text "nice" $$ text "world")
728 -- which will be laid out as:
735 align d = column (\k ->
736 nesting (\i -> nest (k - i) d)) --nesting might be negative :-)
738 -----------------------------------------------------------
740 -----------------------------------------------------------
742 -- | The abstract data type @Doc@ represents pretty documents.
744 -- @Doc@ is an instance of the 'Show' class. @(show doc)@ pretty
745 -- prints document @doc@ with a page width of 100 characters and a
746 -- ribbon width of 40 characters.
748 -- > show (text "hello" <$> text "world")
750 -- Which would return the string \"hello\\nworld\", i.e.
757 | Char Char -- invariant: char is not '\n'
758 | Text !Int64 Builder -- invariant: text doesn't contain '\n'
759 | Line !Bool -- True <=> when undone by group, do not insert a space
762 | Union Doc Doc -- invariant: first lines of first doc longer than the first lines of the second doc
763 | Column (Int64 -> Doc)
764 | Nesting (Int64 -> Doc)
767 instance IsString Doc where
768 fromString = string . T.pack
770 -- | In particular, note that the document @(x '<>' y)@ concatenates
771 -- document @x@ and document @y@. It is an associative operation
772 -- having 'empty' as a left and right unit. (infixr 6)
773 instance Monoid Doc where
777 -- | The data type @SimpleDoc@ represents rendered documents and is
778 -- used by the display functions.
780 -- The @Int@ in @SText@ contains the length of the string. The @Int@
781 -- in @SLine@ contains the indentation for that line. The library
782 -- provides two default display functions 'displayS' and
783 -- 'displayIO'. You can provide your own display function by writing
784 -- a function from a @SimpleDoc@ to your own output format.
785 data SimpleDoc = SEmpty
786 | SChar Char SimpleDoc
787 | SText !Int64 Builder SimpleDoc
788 | SLine !Int64 SimpleDoc
790 -- | The empty document is, indeed, empty. Although @empty@ has no
791 -- content, it does have a \'height\' of 1 and behaves exactly like
792 -- @(text \"\")@ (and is therefore not a unit of @\<$\>@).
796 -- | The document @(char c)@ contains the literal character @c@. The
797 -- character shouldn't be a newline (@'\n'@), the function 'line'
798 -- should be used for line breaks.
803 -- | The document @(text s)@ contains the literal string @s@. The
804 -- string shouldn't contain any newline (@'\n'@) characters. If the
805 -- string contains newline characters, the function 'string' should
810 | otherwise = Text (T.length s) (B.fromLazyText s)
812 -- | The @line@ document advances to the next line and indents to the
813 -- current nesting level. Document @line@ behaves like @(text \"
814 -- \")@ if the line break is undone by 'group' or if rendered with
819 -- | The @linebreak@ document advances to the next line and indents to
820 -- the current nesting level. Document @linebreak@ behaves like
821 -- 'empty' if the line break is undone by 'group'.
823 linebreak = Line True
825 beside :: Doc -> Doc -> Doc
830 -- | The document @(nest i x)@ renders document @x@ with the current
831 -- indentation level increased by @i@ (See also 'hang', 'align' and
834 -- > nest 2 (text "hello" <$> text "world") <$> text "!"
843 nest :: Int -> Doc -> Doc
845 nest i x = Nest (fromIntegral i) x
847 -- | Specifies how to create the document based upon which column it is in.
848 column :: (Int -> Doc) -> Doc
849 column f = Column (f . fromIntegral)
851 -- | Specifies how to nest the document based upon which column it is
853 nesting :: (Int -> Doc) -> Doc
854 nesting f = Nesting (f . fromIntegral)
856 -- | The @group@ combinator is used to specify alternative
857 -- layouts. The document @(group x)@ undoes all line breaks in
858 -- document @x@. The resulting line is added to the current line if
859 -- that fits the page. Otherwise, the document @x@ is rendered
860 -- without any changes.
862 group x = Union (flatten x) x
864 flatten :: Doc -> Doc
865 flatten (Cat x y) = Cat (flatten x) (flatten y)
866 flatten (Nest i x) = Nest i (flatten x)
867 flatten (Line brk) = if brk then Empty else Text 1 (B.singleton ' ')
868 flatten (Union x _) = flatten x
869 flatten (Column f) = Column (flatten . f)
870 flatten (Nesting f) = Nesting (flatten . f)
871 flatten other = other --Empty,Char,Text
873 -----------------------------------------------------------
875 -----------------------------------------------------------
877 -----------------------------------------------------------
878 -- renderPretty: the default pretty printing algorithm
879 -----------------------------------------------------------
881 -- list of indentation/document pairs; saves an indirection over [(Int,Doc)]
883 | Cons !Int64 Doc Docs
885 -- | This is the default pretty printer which is used by 'show',
886 -- 'putDoc' and 'hPutDoc'. @(renderPretty ribbonfrac width x)@
887 -- renders document @x@ with a page width of @width@ and a ribbon
888 -- width of @(ribbonfrac * width)@ characters. The ribbon width is
889 -- the maximal amount of non-indentation characters on a line. The
890 -- parameter @ribbonfrac@ should be between @0.0@ and @1.0@. If it
891 -- is lower or higher, the ribbon width will be 0 or @width@
893 renderPretty :: Float -> Int -> Doc -> SimpleDoc
894 renderPretty rfrac w doc
895 = best 0 0 (Cons 0 doc Nil)
897 -- r :: the ribbon width in characters
898 r = max 0 (min w64 (round (fromIntegral w * rfrac)))
902 -- best :: n = indentation of current line
903 -- k = current column
904 -- (ie. (k >= n) && (k - n == count of inserted characters)
905 best _ _ Nil = SEmpty
906 best n k (Cons i d ds)
909 Char c -> let k' = k+1 in seq k' $ SChar c (best n k' ds)
910 Text l s -> let k' = k+l in seq k' $ SText l s (best n k' ds)
911 Line _ -> SLine i (best i i ds)
912 Cat x y -> best n k (Cons i x (Cons i y ds))
913 Nest j x -> let i' = i+j in seq i' (best n k (Cons i' x ds))
914 Union x y -> nicest n k (best n k $ Cons i x ds)
915 (best n k $ Cons i y ds)
916 Column f -> best n k (Cons i (f k) ds)
917 Nesting f -> best n k (Cons i (f i) ds)
918 Spaces l -> let k' = k+l in seq k' $ SText l (spaces l) (best n k' ds)
920 --nicest :: r = ribbon width, w = page width,
921 -- n = indentation of current line, k = current column
922 -- x and y, the (simple) documents to chose from.
923 -- precondition: first lines of x are longer than the first lines of y.
928 wth = min (w64 - k) (r - k + n)
930 fits :: Int64 -> SimpleDoc -> Bool
931 fits w _ | w < 0 = False
933 fits w (SChar _ x) = fits (w - 1) x
934 fits w (SText l _ x) = fits (w - l) x
935 fits _ SLine{} = True
937 -----------------------------------------------------------
938 -- renderCompact: renders documents without indentation
939 -- fast and fewer characters output, good for machines
940 -----------------------------------------------------------
942 -- | @(renderCompact x)@ renders document @x@ without adding any
943 -- indentation. Since no \'pretty\' printing is involved, this
944 -- renderer is very fast. The resulting output contains fewer
945 -- characters than a pretty printed version and can be used for
946 -- output that is read by other programs.
947 renderCompact :: Doc -> SimpleDoc
955 Char c -> let k' = k+1 in seq k' (SChar c (scan k' ds))
956 Text l s -> let k' = k+l in seq k' (SText l s (scan k' ds))
957 Line _ -> SLine 0 (scan 0 ds)
958 Cat x y -> scan k (x:y:ds)
959 Nest _ x -> scan k (x:ds)
960 Union _ y -> scan k (y:ds)
961 Column f -> scan k (f k:ds)
962 Nesting f -> scan k (f 0:ds)
963 Spaces _ -> scan k ds
965 -- | @(renderOneLine x)@ renders document @x@ without adding any
966 -- indentation or newlines.
967 renderOneLine :: Doc -> SimpleDoc
975 Char c -> let k' = k+1 in seq k' (SChar c (scan k' ds))
976 Text l s -> let k' = k+l in seq k' (SText l s (scan k' ds))
977 Line False -> let k' = k+1 in seq k' (SChar ' ' (scan k' ds))
979 Cat x y -> scan k (x:y:ds)
980 Nest _ x -> scan k (x:ds)
981 Union _ y -> scan k (y:ds)
982 Column f -> scan k (f k:ds)
983 Nesting f -> scan k (f 0:ds)
984 Spaces _ -> scan k ds
986 -----------------------------------------------------------
987 -- Displayers: displayS and displayIO
988 -----------------------------------------------------------
991 -- | @(displayB simpleDoc)@ takes the output @simpleDoc@ from a
992 -- rendering function and transforms it to a 'Builder' type (for
993 -- further manipulation before converting to a lazy 'Text').
994 displayB :: SimpleDoc -> Builder
995 displayB SEmpty = mempty
996 displayB (SChar c x) = c `consB` displayB x
997 displayB (SText _ s x) = s `mappend` displayB x
998 displayB (SLine i x) = '\n' `consB` (indentation i `mappend` displayB x)
1000 consB :: Char -> Builder -> Builder
1001 c `consB` b = B.singleton c `mappend` b
1003 -- | @(displayT simpleDoc)@ takes the output @simpleDoc@ from a
1004 -- rendering function and transforms it to a lazy 'Text' value.
1006 -- > showWidth :: Int -> Doc -> Text
1007 -- > showWidth w x = displayT (renderPretty 0.4 w x)
1008 displayT :: SimpleDoc -> Text
1009 displayT = B.toLazyText . displayB
1011 -- | @(displayIO handle simpleDoc)@ writes @simpleDoc@ to the
1012 -- file handle @handle@. This function is used for example by
1015 -- > hPutDoc handle doc = displayIO handle (renderPretty 0.4 100 doc)
1016 displayIO :: Handle -> SimpleDoc -> IO ()
1017 displayIO handle simpleDoc
1020 display SEmpty = return ()
1021 display (SChar c x) = hPutChar handle c >> display x
1022 display (SText _ s x) = T.hPutStr handle (B.toLazyText s) >> display x
1023 display (SLine i x) = T.hPutStr handle newLine >> display x
1025 newLine = B.toLazyText $ '\n' `consB` indentation i
1027 -----------------------------------------------------------
1028 -- default pretty printers: show, putDoc and hPutDoc
1029 -----------------------------------------------------------
1031 instance Show Doc where
1032 showsPrec d doc = showsPrec d (displayT $ renderPretty 0.4 80 doc)
1033 show doc = T.unpack (displayT $ renderPretty 0.4 80 doc)
1035 instance Show SimpleDoc where
1036 show simpleDoc = T.unpack (displayT simpleDoc)
1038 -- | The action @(putDoc doc)@ pretty prints document @doc@ to the
1039 -- standard output, with a page width of 100 characters and a ribbon
1040 -- width of 40 characters.
1043 -- > main = do{ putDoc (text "hello" <+> text "world") }
1045 -- Which would output
1050 putDoc :: Doc -> IO ()
1051 putDoc doc = hPutDoc stdout doc
1053 -- | @(hPutDoc handle doc)@ pretty prints document @doc@ to the file
1054 -- handle @handle@ with a page width of 100 characters and a ribbon
1055 -- width of 40 characters.
1057 -- > main = do handle <- 'openFile' "MyFile" 'WriteMode'
1058 -- > 'hPutDoc' handle ('vcat' ('map' 'text'
1059 -- > ['T.pack' "vertical", 'T.pack' "text"]))
1060 -- > 'hClose' handle
1061 hPutDoc :: Handle -> Doc -> IO ()
1062 hPutDoc handle doc = displayIO handle (renderPretty 0.4 80 doc)
1064 -----------------------------------------------------------
1066 -- "indentation" used to insert tabs but tabs seem to cause
1067 -- more trouble than they solve :-)
1068 -----------------------------------------------------------
1069 spaces :: Int64 -> Builder
1072 | otherwise = B.fromLazyText $ T.replicate n (T.singleton ' ')
1074 spaced :: Int -> Doc
1075 spaced l = Spaces l'
1079 -- An alias for readability purposes
1080 indentation :: Int64 -> Builder
1081 indentation = spaces
1083 -- LocalWords: PPrint combinators Wadler Wadler's encloseSep