@@ -80,13 +80,8 @@ import Data.Text.Prettyprint.Doc.Render.Util.Panic
8080-- hello
8181-- world
8282data Doc ann =
83-
84- -- | Occurs when flattening a line. The layouter will reject this document,
85- -- choosing a more suitable rendering.
86- Fail
87-
8883 -- | The empty document; conceptually the unit of 'Cat'
89- | Empty
84+ Empty
9085
9186 -- | invariant: not '\n'
9287 | Char ! Char
@@ -523,88 +518,61 @@ hardline = Line
523518-- use of it.
524519group :: Doc ann -> Doc ann
525520-- See note [Group: special flattening]
526- group x = case changesUponFlattening x of
527- Flattened x' -> Union x' x
528- AlreadyFlat -> x
529- NeverFlat -> x
530-
531- -- Note [Group: special flattening]
532- --
533- -- Since certain documents do not change under removal of newlines etc, there is
534- -- no point in creating a 'Union' of the flattened and unflattened version – all
535- -- this does is introducing two branches for the layout algorithm to take,
536- -- resulting in potentially exponential behavior on deeply nested examples, such
537- -- as
538- --
539- -- pathological n = iterate (\x -> hsep [x, sep []] ) "foobar" !! n
540- --
541- -- See https://github.com/quchen/prettyprinter/issues/22 for the corresponding
542- -- ticket.
543-
544- data FlattenResult a
545- = Flattened a
546- -- ^ @a@ is likely flatter than the input.
547- | AlreadyFlat
548- -- ^ The input was already flat, e.g. a 'Text'.
549- | NeverFlat
550- -- ^ The input couldn't be flattened: It contained a 'Line' or 'Fail'.
521+ group = \ doc -> case doc of
522+ FlatAlt x y -> Union (group y) x
523+ x@ (Union _ _) -> x
524+
525+ x@ (Cat a b) -> case groupNoLine a of
526+ -- We could not flatten the left side
527+ HasLine -> x
528+ -- Left side flattened without a problem
529+ FlatNoLine a' -> Cat a' (group b)
530+ -- Left side may contain a Line, need to wrap in Union
531+ FlatMaybeLine a' -> Union (Cat a' (group b)) x
532+
533+ Annotated a x -> Annotated a (group x)
534+ Nest i x -> Nest i (group x)
535+ Column f -> Column (group . f)
536+ Nesting f -> Nesting (group . f)
537+ WithPageWidth f -> WithPageWidth (group . f)
538+
539+ x@ Text {} -> x
540+ x@ Char {} -> x
541+ x@ Empty -> x
542+ x@ Line -> x
543+ where
544+ groupNoLine :: Doc ann -> FlattenResult (Doc ann )
545+ groupNoLine = \ doc -> case doc of
546+ FlatAlt x y -> (flip Union $ x) <$> (groupNoLine y)
547+ Union x _ -> FlatNoLine x
548+ Line -> HasLine
549+ Cat x y -> case (groupNoLine x, groupNoLine y) of
550+ (HasLine , _ ) -> HasLine
551+ (_ , HasLine ) -> HasLine
552+ (FlatMaybeLine a , FlatMaybeLine b) -> FlatMaybeLine (Cat a b)
553+ (FlatMaybeLine a , FlatNoLine b ) -> FlatMaybeLine (Cat a b)
554+ (FlatNoLine a , FlatMaybeLine b) -> FlatMaybeLine (Cat a b)
555+ (FlatNoLine a , FlatNoLine b ) -> FlatNoLine (Cat a b)
556+
557+ Annotated a x -> Annotated a <$> groupNoLine x
558+ Nest i x -> Nest i <$> groupNoLine x
559+ Column f -> FlatMaybeLine (Column (group . f))
560+ Nesting f -> FlatMaybeLine (Nesting (group . f))
561+ WithPageWidth f -> FlatMaybeLine (WithPageWidth (group . f))
562+
563+ x@ Text {} -> FlatNoLine x
564+ x@ Char {} -> FlatNoLine x
565+ x@ Empty -> FlatNoLine x
566+
567+ data FlattenResult a =
568+ FlatNoLine a
569+ | FlatMaybeLine a
570+ | HasLine
551571
552572instance Functor FlattenResult where
553- fmap f (Flattened a) = Flattened (f a)
554- fmap _ AlreadyFlat = AlreadyFlat
555- fmap _ NeverFlat = NeverFlat
556-
557- -- | Choose the first element of each @Union@, and discard the first field of
558- -- all @FlatAlt@s.
559- --
560- -- The result is 'Flattened' if the element might change depending on the layout
561- -- algorithm (i.e. contains differently renderable sub-documents), and 'AlreadyFlat'
562- -- if the document is static (e.g. contains only a plain 'Empty' node).
563- -- 'NeverFlat' is returned when the document cannot be flattened because it
564- -- contains a hard 'Line' or 'Fail'.
565- -- See [Group: special flattening] for further explanations.
566- changesUponFlattening :: Doc ann -> FlattenResult (Doc ann )
567- changesUponFlattening = \ doc -> case doc of
568- FlatAlt _ y -> Flattened (flatten y)
569- Line -> NeverFlat
570- Union x _ -> Flattened x
571- Nest i x -> fmap (Nest i) (changesUponFlattening x)
572- Annotated ann x -> fmap (Annotated ann) (changesUponFlattening x)
573-
574- Column f -> Flattened (Column (flatten . f))
575- Nesting f -> Flattened (Nesting (flatten . f))
576- WithPageWidth f -> Flattened (WithPageWidth (flatten . f))
577-
578- Cat x y -> case (changesUponFlattening x, changesUponFlattening y) of
579- (NeverFlat , _ ) -> NeverFlat
580- (_ , NeverFlat ) -> NeverFlat
581- (Flattened x' , Flattened y') -> Flattened (Cat x' y')
582- (Flattened x' , AlreadyFlat ) -> Flattened (Cat x' y)
583- (AlreadyFlat , Flattened y') -> Flattened (Cat x y')
584- (AlreadyFlat , AlreadyFlat ) -> AlreadyFlat
585-
586- Empty -> AlreadyFlat
587- Char {} -> AlreadyFlat
588- Text {} -> AlreadyFlat
589- Fail -> NeverFlat
590- where
591- -- Flatten, but don’t report whether anything changes.
592- flatten :: Doc ann -> Doc ann
593- flatten = \ doc -> case doc of
594- FlatAlt _ y -> flatten y
595- Cat x y -> Cat (flatten x) (flatten y)
596- Nest i x -> Nest i (flatten x)
597- Line -> Fail
598- Union x _ -> flatten x
599- Column f -> Column (flatten . f)
600- WithPageWidth f -> WithPageWidth (flatten . f)
601- Nesting f -> Nesting (flatten . f)
602- Annotated ann x -> Annotated ann (flatten x)
603-
604- x@ Fail -> x
605- x@ Empty -> x
606- x@ Char {} -> x
607- x@ Text {} -> x
573+ fmap f (FlatNoLine a) = FlatNoLine (f a)
574+ fmap f (FlatMaybeLine a) = FlatMaybeLine (f a)
575+ fmap _ HasLine = HasLine
608576
609577
610578
@@ -1266,7 +1234,6 @@ alterAnnotations :: (ann -> [ann']) -> Doc ann -> Doc ann'
12661234alterAnnotations re = go
12671235 where
12681236 go = \ doc -> case doc of
1269- Fail -> Fail
12701237 Empty -> Empty
12711238 Char c -> Char c
12721239 Text l t -> Text l t
@@ -1292,7 +1259,6 @@ unAnnotateS :: SimpleDocStream ann -> SimpleDocStream xxx
12921259unAnnotateS = go
12931260 where
12941261 go = \ doc -> case doc of
1295- SFail -> SFail
12961262 SEmpty -> SEmpty
12971263 SChar c rest -> SChar c (go rest)
12981264 SText l t rest -> SText l t (go rest)
@@ -1305,7 +1271,6 @@ reAnnotateS :: (ann -> ann') -> SimpleDocStream ann -> SimpleDocStream ann'
13051271reAnnotateS re = go
13061272 where
13071273 go = \ doc -> case doc of
1308- SFail -> SFail
13091274 SEmpty -> SEmpty
13101275 SChar c rest -> SChar c (go rest)
13111276 SText l t rest -> SText l t (go rest)
@@ -1329,7 +1294,6 @@ alterAnnotationsS re = go []
13291294 -- We keep a stack of whether to remove a pop so that we can remove exactly
13301295 -- the pops corresponding to annotations that mapped to Nothing.
13311296 go stack = \ sds -> case sds of
1332- SFail -> SFail
13331297 SEmpty -> SEmpty
13341298 SChar c rest -> SChar c (go stack rest)
13351299 SText l t rest -> SText l t (go stack rest)
@@ -1445,8 +1409,7 @@ fuse depth = go
14451409-- convert from @'SimpleDocStream'@. The »Render« submodules provide some
14461410-- built-in converters to do so, and helpers to create own ones.
14471411data SimpleDocStream ann =
1448- SFail
1449- | SEmpty
1412+ SEmpty
14501413 | SChar Char (SimpleDocStream ann )
14511414
14521415 -- | Some layout algorithms use the Since the frequently used 'T.length' of
@@ -1494,7 +1457,6 @@ removeTrailingWhitespace = go (RecordedWhitespace [] 0)
14941457 -- We do not strip whitespace inside annotated documents, since it might
14951458 -- actually be relevant there.
14961459 go annLevel@ (AnnotationLevel annLvl) = \ sds -> case sds of
1497- SFail -> SFail
14981460 SEmpty -> SEmpty
14991461 SChar c rest -> SChar c (go annLevel rest)
15001462 SText l text rest -> SText l text (go annLevel rest)
@@ -1508,7 +1470,6 @@ removeTrailingWhitespace = go (RecordedWhitespace [] 0)
15081470 -- Record all spaces/lines encountered, and once proper text starts again,
15091471 -- release only the necessary ones.
15101472 go (RecordedWhitespace withheldLines withheldSpaces) = \ sds -> case sds of
1511- SFail -> SFail
15121473 SEmpty -> foldr (\ _i sds' -> SLine 0 sds') SEmpty withheldLines
15131474 SChar c rest
15141475 | c == ' ' -> go (RecordedWhitespace withheldLines (withheldSpaces+ 1 )) rest
@@ -1577,7 +1538,6 @@ instance Foldable SimpleDocStream where
15771538 foldMap f = go
15781539 where
15791540 go = \ sds -> case sds of
1580- SFail -> mempty
15811541 SEmpty -> mempty
15821542 SChar _ rest -> go rest
15831543 SText _ _ rest -> go rest
@@ -1591,7 +1551,6 @@ instance Traversable SimpleDocStream where
15911551 traverse f = go
15921552 where
15931553 go = \ sds -> case sds of
1594- SFail -> pure SFail
15951554 SEmpty -> pure SEmpty
15961555 SChar c rest -> SChar c <$> go rest
15971556 SText l t rest -> SText l t <$> go rest
@@ -1679,7 +1638,6 @@ layoutPretty = layoutWadlerLeijen
16791638 -> SimpleDocStream ann
16801639 -> Bool
16811640 fits w _ | w < 0 = False
1682- fits _ SFail = False
16831641 fits _ SEmpty = True
16841642 fits w (SChar _ x) = fits (w - 1 ) x
16851643 fits w (SText l _t x) = fits (w - l) x
@@ -1751,7 +1709,6 @@ layoutSmart = layoutWadlerLeijen (FittingPredicate fits)
17511709 -> SimpleDocStream ann
17521710 -> Bool
17531711 fits _ _ w _ | w < 0 = False
1754- fits _ _ _ SFail = False
17551712 fits _ _ _ SEmpty = True
17561713 fits pw m w (SChar _ x) = fits pw m (w - 1 ) x
17571714 fits pw m w (SText l _t x) = fits pw m (w - l) x
@@ -1784,7 +1741,6 @@ layoutWadlerLeijen
17841741 best ! _ ! _ Nil = SEmpty
17851742 best nl cc (UndoAnn ds) = SAnnPop (best nl cc ds)
17861743 best nl cc (Cons i d ds) = case d of
1787- Fail -> SFail
17881744 Empty -> best nl cc ds
17891745 Char c -> let ! cc' = cc+ 1 in SChar c (best nl cc' ds)
17901746 Text l t -> let ! cc' = cc+ l in SText l t (best nl cc' ds)
@@ -1827,41 +1783,9 @@ layoutWadlerLeijen
18271783 ribbonWidth =
18281784 (max 0 . min lineLength . round )
18291785 (fromIntegral lineLength * ribbonFraction)
1830- Unbounded
1831- -- See the Note [Detecting failure with Unbounded page width].
1832- | not (failsOnFirstLine x) -> x
1786+ Unbounded -> x
18331787 _ -> y
18341788
1835- failsOnFirstLine :: SimpleDocStream ann -> Bool
1836- failsOnFirstLine = go
1837- where
1838- go sds = case sds of
1839- SFail -> True
1840- SEmpty -> False
1841- SChar _ s -> go s
1842- SText _ _ s -> go s
1843- SLine _ _ -> False
1844- SAnnPush _ s -> go s
1845- SAnnPop s -> go s
1846-
1847-
1848- -- Note [Detecting failure with Unbounded page width]
1849- --
1850- -- To understand why it is sufficient to check the first line of the
1851- -- SimpleDocStream, trace how an SFail ends up there:
1852- --
1853- -- 1. We group a Doc containing a Line, producing a (Union x y) where
1854- -- x contains Fail.
1855- --
1856- -- 2. In best, any Unions are handled recursively, rejecting any
1857- -- alternatives that would result in SFail.
1858- --
1859- -- So once a SimpleDocStream reaches selectNicer, any SFail in it must
1860- -- appear before the first linebreak – any other SFail would have been
1861- -- detected and rejected in a previous iteration.
1862-
1863-
1864-
18651789-- | @(layoutCompact x)@ lays out the document @x@ without adding any
18661790-- indentation. Since no \'pretty\' printing is involved, this layouter is very
18671791-- fast. The resulting output contains fewer characters than a prettyprinted
@@ -1885,7 +1809,6 @@ layoutCompact doc = scan 0 [doc]
18851809 where
18861810 scan _ [] = SEmpty
18871811 scan ! col (d: ds) = case d of
1888- Fail -> SFail
18891812 Empty -> scan col ds
18901813 Char c -> SChar c (scan (col+ 1 ) ds)
18911814 Text l t -> let ! col' = col+ l in SText l t (scan col' ds)
@@ -1913,7 +1836,6 @@ instance Show (Doc ann) where
19131836-- @
19141837renderShowS :: SimpleDocStream ann -> ShowS
19151838renderShowS = \ sds -> case sds of
1916- SFail -> panicUncaughtFail
19171839 SEmpty -> id
19181840 SChar c x -> showChar c . renderShowS x
19191841 SText _l t x -> showString (T. unpack t) . renderShowS x
0 commit comments