0 | module Libraries.Text.PrettyPrint.Prettyprinter.Doc
3 | import public Data.List1
6 | import public Libraries.Data.Span
7 | import Libraries.Data.String.Extra
12 | textReplicateChar : Int -> Char -> String
13 | textReplicateChar n = String.replicate (integerToNat $
cast n)
16 | textSpaces : Int -> String
17 | textSpaces n = textReplicateChar n ' '
21 | data PageWidth : Type where
24 | AvailablePerLine : Int -> Double -> PageWidth
26 | Unbounded : PageWidth
28 | data FlattenResult : Type -> Type where
29 | Flattened : a -> FlattenResult a
30 | AlreadyFlat : FlattenResult a
31 | NeverFlat : FlattenResult a
33 | Functor FlattenResult where
34 | map f (Flattened a) = Flattened (f a)
35 | map _ AlreadyFlat = AlreadyFlat
36 | map _ NeverFlat = NeverFlat
40 | data FusionDepth : Type where
42 | Shallow : FusionDepth
49 | data Doc : Type -> Type where
51 | Chara : (c : Char) -> Doc ann
52 | Text : (len : Int) -> (text : String) -> Doc ann
54 | FlatAlt : Lazy (Doc ann) -> Lazy (Doc ann) -> Doc ann
55 | Cat : Doc ann -> Doc ann -> Doc ann
56 | Nest : (i : Int) -> Doc ann -> Doc ann
57 | Union : Lazy (Doc ann) -> Lazy (Doc ann) -> Doc ann
59 | Column : (Int -> Doc ann) -> Doc ann
60 | WithPageWidth : (PageWidth -> Doc ann) -> Doc ann
61 | Nesting : (Int -> Doc ann) -> Doc ann
62 | Annotated : ann -> Doc ann -> Doc ann
65 | Semigroup (Doc ann) where
69 | Monoid (Doc ann) where
74 | column : (Int -> Doc ann) -> Doc ann
79 | nest : Int -> Doc ann -> Doc ann
85 | nesting : (Int -> Doc ann) -> Doc ann
90 | width : Doc ann -> (Int -> Doc ann) -> Doc ann
91 | width doc f = column (\colStart => doc <+> column (\colEnd => f (colEnd - colStart)))
95 | pageWidth : (PageWidth -> Doc ann) -> Doc ann
96 | pageWidth = WithPageWidth
100 | align : Doc ann -> Doc ann
101 | align d = column (\k => nesting (\i => nest (k - i) d))
106 | hang : Int -> Doc ann -> Doc ann
107 | hang i d = align (nest i d)
111 | replicateChar : (n : Int) -> Char -> Doc ann
112 | replicateChar n c =
117 | else Text n (textReplicateChar n c)
121 | spaces : Int -> Doc ann
122 | spaces n = replicateChar n ' '
126 | indent : Int -> Doc ann -> Doc ann
127 | indent i d = hang i (spaces i <+> d)
132 | fill : Int -> Doc ann -> Doc ann
133 | fill n doc = width doc (\w => spaces $
n - w)
135 | export infixr 6 <++>
138 | (<++>) : Doc ann -> Doc ann -> Doc ann
141 | x <++> y = x <+> Chara ' ' <+> y
151 | softline = Union (Chara ' ') Line
156 | softline' : Doc ann
157 | softline' = Union neutral Line
164 | flatten : Doc ann -> Doc ann
165 | flatten Empty = Empty
166 | flatten (Chara x) = Chara x
167 | flatten (Text len x) = Text len x
168 | flatten Line = Empty
169 | flatten (FlatAlt _ y) = flatten y
170 | flatten (Cat x y) = Cat (flatten x) (flatten y)
171 | flatten (Nest i x) = Nest i (flatten x)
172 | flatten (Union x _) = flatten x
173 | flatten (Column f) = Column (\x => flatten $
f x)
174 | flatten (WithPageWidth f) = WithPageWidth (\x => flatten $
f x)
175 | flatten (Nesting f) = Nesting (\x => flatten $
f x)
176 | flatten (Annotated ann x) = Annotated ann (flatten x)
178 | changesUponFlattening : Doc ann -> FlattenResult (Doc ann)
179 | changesUponFlattening Empty = AlreadyFlat
180 | changesUponFlattening (Chara x) = AlreadyFlat
181 | changesUponFlattening (Text x y) = AlreadyFlat
182 | changesUponFlattening Line = NeverFlat
183 | changesUponFlattening (FlatAlt _ y) = Flattened (flatten y)
184 | changesUponFlattening (Cat x y) = case (changesUponFlattening x, changesUponFlattening y) of
185 | (NeverFlat, _) => NeverFlat
186 | (_, NeverFlat) => NeverFlat
187 | (Flattened x', Flattened y') => Flattened (Cat x' y')
188 | (Flattened x', AlreadyFlat) => Flattened (Cat x' y)
189 | (AlreadyFlat , Flattened y') => Flattened (Cat x y')
190 | (AlreadyFlat , AlreadyFlat) => AlreadyFlat
191 | changesUponFlattening (Nest i x) = map (Nest i) (changesUponFlattening x)
192 | changesUponFlattening (Union x _) = Flattened x
193 | changesUponFlattening (Column f) = Flattened (Column (flatten . f))
194 | changesUponFlattening (WithPageWidth f) = Flattened (WithPageWidth (flatten . f))
195 | changesUponFlattening (Nesting f) = Flattened (Nesting (flatten . f))
196 | changesUponFlattening (Annotated ann x) = map (Annotated ann) (changesUponFlattening x)
202 | group : Doc ann -> Doc ann
203 | group (Union x y) = Union x y
204 | group (FlatAlt x y) = case changesUponFlattening y of
205 | Flattened y' => Union y' x
206 | AlreadyFlat => Union y x
208 | group x = case changesUponFlattening x of
209 | Flattened x' => Union x' x
216 | flatAlt : Lazy (Doc ann) -> Lazy (Doc ann) -> Doc ann
222 | line = FlatAlt Line (Chara ' ')
227 | line' = FlatAlt Line Empty
233 | fillBreak : Int -> Doc ann -> Doc ann
234 | fillBreak f x = width x (\w => if w > f
236 | else spaces $
f - w)
240 | concatWith : (Doc ann -> Doc ann -> Doc ann) -> List (Doc ann) -> Doc ann
241 | concatWith f [] = neutral
242 | concatWith f (x :: xs) = foldl f x xs
246 | hsep : List (Doc ann) -> Doc ann
247 | hsep = concatWith (<++>)
252 | vsep : List (Doc ann) -> Doc ann
253 | vsep = concatWith (\x, y => x <+> line <+> y)
258 | fillSep : List (Doc ann) -> Doc ann
259 | fillSep = concatWith (\x, y => x <+> softline <+> y)
264 | sep : List (Doc ann) -> Doc ann
269 | hcat : List (Doc ann) -> Doc ann
270 | hcat = concatWith (<+>)
274 | vcat : List (Doc ann) -> Doc ann
275 | vcat = concatWith (\x, y => x <+> line' <+> y)
280 | fillCat : List (Doc ann) -> Doc ann
281 | fillCat = concatWith (\x, y => x <+> softline' <+> y)
286 | cat : List (Doc ann) -> Doc ann
291 | punctuate : Doc ann -> List (Doc ann) -> List (Doc ann)
292 | punctuate _ [] = []
293 | punctuate _ [d] = [d]
294 | punctuate p (d :: ds) = (d <+> p) :: punctuate p ds
297 | plural : (Num amount, Eq amount) => doc -> doc -> amount -> doc
298 | plural one multiple n = if n == 1 then one else multiple
302 | enclose : Doc ann -> Doc ann -> Doc ann -> Doc ann
303 | enclose l r x = l <+> x <+> r
309 | surround : Doc ann -> Doc ann -> Doc ann -> Doc ann
310 | surround x l r = l <+> x <+> r
314 | encloseSep : Doc ann -> Doc ann -> Doc ann -> List (Doc ann) -> Doc ann
315 | encloseSep l r s [] = l <+> r
316 | encloseSep l r s [d] = l <+> d <+> r
317 | encloseSep l r s ds = cat (zipWith (<+>) (l :: replicate (length ds `minus` 1) s) ds) <+> r
319 | unsafeTextWithoutNewLines : String -> Doc ann
320 | unsafeTextWithoutNewLines str = case strM str of
322 | StrCons c cs => if cs == ""
324 | else Text (cast $
length str) str
328 | annotate : ann -> Doc ann -> Doc ann
329 | annotate = Annotated
334 | alterAnnotations : (ann -> List ann') -> Doc ann -> Doc ann'
335 | alterAnnotations re Empty = Empty
336 | alterAnnotations re (Chara c) = Chara c
337 | alterAnnotations re (Text l t) = Text l t
338 | alterAnnotations re Line = Line
339 | alterAnnotations re (FlatAlt x y) = FlatAlt (alterAnnotations re x) (alterAnnotations re y)
340 | alterAnnotations re (Cat x y) = Cat (alterAnnotations re x) (alterAnnotations re y)
341 | alterAnnotations re (Nest i x) = Nest i (alterAnnotations re x)
342 | alterAnnotations re (Union x y) = Union (alterAnnotations re x) (alterAnnotations re y)
343 | alterAnnotations re (Column f) = Column (\x => alterAnnotations re $
f x)
344 | alterAnnotations re (WithPageWidth f) = WithPageWidth (\x => alterAnnotations re $
f x)
345 | alterAnnotations re (Nesting f) = Nesting (\x => alterAnnotations re $
f x)
346 | alterAnnotations re (Annotated ann x) = foldr Annotated (alterAnnotations re x) (re ann)
350 | unAnnotate : Doc ann -> Doc xxx
351 | unAnnotate = alterAnnotations (const [])
355 | reAnnotate : (ann -> ann') -> Doc ann -> Doc ann'
356 | reAnnotate re = alterAnnotations (pure . re)
373 | interface Pretty ann a | a where
374 | pretty : a -> Doc ann
375 | pretty x = prettyPrec Open x
377 | prettyPrec : Prec -> a -> Doc ann
378 | prettyPrec _ x = pretty x
387 | prettyBy : Pretty ann1 a => (inj : ann1 -> ann2) -> a -> Doc ann2
388 | prettyBy inj a = reAnnotate inj (pretty a)
396 | Cast (Doc Void) (Doc ann) where
405 | pretty0 : Pretty Void a => a -> Doc ann
406 | pretty0 x = cast (pretty x)
409 | Pretty Void String where
410 | pretty str = let str' = if "\n" `isSuffixOf` str then dropLast 1 str else str in
411 | vsep $
map unsafeTextWithoutNewLines $
lines str'
414 | byShow : Show a => a -> Doc ann
415 | byShow = pretty0 . show
418 | FromString (Doc ann) where
419 | fromString = pretty0
422 | commaSep : List (Doc ann) -> Doc ann
423 | commaSep = concatWith (\x, y => x <+> pretty0 "," <++> y)
427 | list : List (Doc ann) -> Doc ann
428 | list = group . encloseSep (flatAlt (pretty0 "[ ") (pretty0 "["))
429 | (flatAlt (pretty0 " ]") (pretty0 "]"))
434 | tupled : List (Doc ann) -> Doc ann
435 | tupled = group . encloseSep (flatAlt (pretty0 "( ") (pretty0 "("))
436 | (flatAlt (pretty0 " )") (pretty0 ")"))
440 | prettyList : Pretty ann a => List a -> Doc ann
441 | prettyList = align . list . map pretty
444 | prettyList1 : Pretty ann a => List1 a -> Doc ann
445 | prettyList1 = prettyList . forget
448 | [prettyListMaybe] Pretty ann a => Pretty ann (List (Maybe a)) where
449 | pretty = prettyList . catMaybes
452 | Pretty Void Char where
457 | prettyMaybe : Pretty ann a => Maybe a -> Doc ann
458 | prettyMaybe = maybe neutral pretty
462 | fuse : FusionDepth -> Doc ann -> Doc ann
463 | fuse depth (Cat Empty x) = fuse depth x
464 | fuse depth (Cat x Empty) = fuse depth x
465 | fuse depth (Cat (Chara c1) (Chara c2)) = Text 2 (strCons c1 (strCons c2 ""))
466 | fuse depth (Cat (Text lt t) (Chara c)) = Text (lt + 1) (t ++ singleton c)
467 | fuse depth (Cat (Chara c) (Text lt t)) = Text (lt + 1) (strCons c t)
468 | fuse depth (Cat (Text l1 t1) (Text l2 t2)) = Text (l1 + l2) (t1 ++ t2)
469 | fuse depth (Cat (Chara x) (Cat (Chara y) z)) =
470 | let sub = Text 2 (strCons x (strCons y "")) in
471 | fuse depth $
assert_smaller (Cat (Chara x) (Cat (Chara y) z)) (Cat sub z)
472 | fuse depth (Cat (Text lx x) (Cat (Chara y) z)) =
473 | let sub = Text (lx + 1) (x ++ singleton y) in
474 | fuse depth $
assert_smaller (Cat (Text lx x) (Cat (Chara y) z)) (Cat sub z)
475 | fuse depth (Cat (Chara x) (Cat (Text ly y) z)) =
476 | let sub = Text (ly + 1) (strCons x y) in
477 | fuse depth $
assert_smaller (Cat (Chara x) (Cat (Text ly y) z)) (Cat sub z)
478 | fuse depth (Cat (Text lx x) (Cat (Text ly y) z)) =
479 | let sub = Text (lx + ly) (x ++ y) in
480 | fuse depth $
assert_smaller (Cat (Text lx x) (Cat (Text ly y) z)) (Cat sub z)
481 | fuse depth (Cat (Cat x (Chara y)) z) =
482 | let sub = fuse depth (Cat (Chara y) z) in
483 | assert_total $
fuse depth (Cat x sub)
484 | fuse depth (Cat (Cat x (Text ly y)) z) =
485 | let sub = fuse depth (Cat (Text ly y) z) in
486 | assert_total $
fuse depth (Cat x sub)
487 | fuse depth (Cat x y) = Cat (fuse depth x) (fuse depth y)
488 | fuse depth (Nest i (Nest j x)) = fuse depth $
assert_smaller (Nest i (Nest j x)) (Nest (i + j) x)
489 | fuse depth (Nest _ Empty) = Empty
490 | fuse depth (Nest _ (Text lx x)) = Text lx x
491 | fuse depth (Nest _ (Chara x)) = Chara x
492 | fuse depth (Nest 0 x) = fuse depth x
493 | fuse depth (Nest i x) = Nest i (fuse depth x)
494 | fuse depth (Annotated ann x) = Annotated ann (fuse depth x)
495 | fuse depth (FlatAlt x y) = FlatAlt (fuse depth x) (fuse depth y)
496 | fuse depth (Union x y) = Union (fuse depth x) (fuse depth y)
497 | fuse Shallow (Column f) = Column f
498 | fuse depth (Column f) = Column (\x => fuse depth $
f x)
499 | fuse Shallow (WithPageWidth f) = WithPageWidth f
500 | fuse depth (WithPageWidth f) = WithPageWidth (\x => fuse depth $
f x)
501 | fuse Shallow (Nesting f) = Nesting f
502 | fuse depth (Nesting f) = Nesting (\x => fuse depth $
f x)
507 | data SimpleDocStream : Type -> Type where
508 | SEmpty : SimpleDocStream ann
509 | SChar : (c : Char) -> (rest : Lazy (SimpleDocStream ann)) -> SimpleDocStream ann
510 | SText : (len : Int) -> (text : String) -> (rest : Lazy (SimpleDocStream ann)) -> SimpleDocStream ann
511 | SLine : (i : Int) -> (rest : SimpleDocStream ann) -> SimpleDocStream ann
512 | SAnnPush : ann -> (rest : SimpleDocStream ann) -> SimpleDocStream ann
513 | SAnnPop : (rest : SimpleDocStream ann) -> SimpleDocStream ann
515 | internalError : SimpleDocStream ann
516 | internalError = let msg = "<internal pretty printing error>" in
517 | SText (cast $
length msg) msg SEmpty
519 | data AnnotationRemoval = Remove | DontRemove
523 | alterAnnotationsS : (ann -> Maybe ann') -> SimpleDocStream ann -> SimpleDocStream ann'
524 | alterAnnotationsS re = fromMaybe internalError . go []
526 | go : List AnnotationRemoval -> SimpleDocStream ann -> Maybe (SimpleDocStream ann')
527 | go stack SEmpty = pure SEmpty
528 | go stack (SChar c rest) = SChar c . delay <$> go stack rest
529 | go stack (SText l t rest) = SText l t . delay <$> go stack rest
530 | go stack (SLine l rest) = SLine l <$> go stack rest
531 | go stack (SAnnPush ann rest) = case re ann of
532 | Nothing => go (Remove :: stack) rest
533 | Just ann' => SAnnPush ann' <$> go (DontRemove :: stack) rest
534 | go stack (SAnnPop rest) = case stack of
536 | DontRemove :: stack' => SAnnPop <$> go stack' rest
537 | Remove :: stack' => go stack' rest
541 | unAnnotateS : SimpleDocStream ann -> SimpleDocStream xxx
542 | unAnnotateS SEmpty = SEmpty
543 | unAnnotateS (SChar c rest) = SChar c (unAnnotateS rest)
544 | unAnnotateS (SText l t rest) = SText l t (unAnnotateS rest)
545 | unAnnotateS (SLine l rest) = SLine l (unAnnotateS rest)
546 | unAnnotateS (SAnnPush ann rest) = unAnnotateS rest
547 | unAnnotateS (SAnnPop rest) = unAnnotateS rest
551 | reAnnotateS : (ann -> ann') -> SimpleDocStream ann -> SimpleDocStream ann'
552 | reAnnotateS re SEmpty = SEmpty
553 | reAnnotateS re (SChar c rest) = SChar c (reAnnotateS re rest)
554 | reAnnotateS re (SText l t rest) = SText l t (reAnnotateS re rest)
555 | reAnnotateS re (SLine l rest) = SLine l (reAnnotateS re rest)
556 | reAnnotateS re (SAnnPush ann rest) = SAnnPush (re ann) (reAnnotateS re rest)
557 | reAnnotateS re (SAnnPop rest) = SAnnPop (reAnnotateS re rest)
560 | Functor SimpleDocStream where
565 | collectAnnotations : Monoid m => (ann -> m) -> SimpleDocStream ann -> m
566 | collectAnnotations f SEmpty = neutral
567 | collectAnnotations f (SChar c rest) = collectAnnotations f rest
568 | collectAnnotations f (SText l t rest) = collectAnnotations f rest
569 | collectAnnotations f (SLine l rest) = collectAnnotations f rest
570 | collectAnnotations f (SAnnPush ann rest) = f ann <+> collectAnnotations f rest
571 | collectAnnotations f (SAnnPop rest) = collectAnnotations f rest
575 | traverse : Applicative f => (ann -> f ann') -> SimpleDocStream ann -> f (SimpleDocStream ann')
576 | traverse f SEmpty = pure SEmpty
577 | traverse f (SChar c rest) = SChar c . delay <$> traverse f rest
578 | traverse f (SText l t rest) = SText l t . delay <$> traverse f rest
579 | traverse f (SLine l rest) = SLine l <$> traverse f rest
580 | traverse f (SAnnPush ann rest) = SAnnPush <$> f ann <*> traverse f rest
581 | traverse f (SAnnPop rest) = SAnnPop <$> traverse f rest
583 | data WhitespaceStrippingState = AnnotationLevel Int | RecordedWithespace (List Int) Int
585 | dropWhileEnd : (a -> Bool) -> List a -> List a
586 | dropWhileEnd p = foldr (\x, xs => if p x && isNil xs then [] else x :: xs) []
590 | removeTrailingWhitespace : SimpleDocStream ann -> SimpleDocStream ann
591 | removeTrailingWhitespace = fromMaybe internalError . go (RecordedWithespace [] 0)
593 | prependEmptyLines : List Int -> SimpleDocStream ann -> SimpleDocStream ann
594 | prependEmptyLines is sds0 = foldr (\_, sds => SLine 0 sds) sds0 is
596 | commitWhitespace : List Int -> Int -> SimpleDocStream ann -> SimpleDocStream ann
597 | commitWhitespace [] 0 sds = sds
598 | commitWhitespace [] 1 sds = SChar ' ' sds
599 | commitWhitespace [] n sds = SText n (textSpaces n) sds
600 | commitWhitespace (i :: is) n sds = prependEmptyLines is (SLine (i + n) sds)
602 | go : WhitespaceStrippingState -> SimpleDocStream ann -> Maybe (SimpleDocStream ann)
603 | go (AnnotationLevel _) SEmpty = pure SEmpty
604 | go l@(AnnotationLevel _) (SChar c rest) = SChar c . delay <$> go l rest
605 | go l@(AnnotationLevel _) (SText lt text rest) = SText lt text . delay <$> go l rest
606 | go l@(AnnotationLevel _) (SLine i rest) = SLine i <$> go l rest
607 | go (AnnotationLevel l) (SAnnPush ann rest) = SAnnPush ann <$> go (AnnotationLevel (l + 1)) rest
608 | go (AnnotationLevel l) (SAnnPop rest) =
610 | then SAnnPop <$> go (AnnotationLevel (l - 1)) rest
611 | else SAnnPop <$> go (RecordedWithespace [] 0) rest
612 | go (RecordedWithespace {}) SEmpty = pure SEmpty
613 | go (RecordedWithespace lines spaces) (SChar ' ' rest) = go (RecordedWithespace lines (spaces + 1)) rest
614 | go (RecordedWithespace lines spaces) (SChar c rest) =
615 | do rest' <- go (RecordedWithespace [] 0) rest
616 | pure $
commitWhitespace lines spaces (SChar c rest')
617 | go (RecordedWithespace lines spaces) (SText l text rest) =
618 | let stripped = pack $
dropWhileEnd (== ' ') $
unpack text
619 | strippedLength = cast $
length stripped
620 | trailingLength = l - strippedLength in
621 | if strippedLength == 0
622 | then go (RecordedWithespace lines (spaces + l)) rest
623 | else do rest' <- go (RecordedWithespace [] trailingLength) rest
624 | pure $
commitWhitespace lines spaces (SText strippedLength stripped rest')
625 | go (RecordedWithespace lines spaces) (SLine i rest) = go (RecordedWithespace (i :: lines) 0) rest
626 | go (RecordedWithespace lines spaces) (SAnnPush ann rest) =
627 | do rest' <- go (AnnotationLevel 1) rest
628 | pure $
commitWhitespace lines spaces (SAnnPush ann rest')
629 | go (RecordedWithespace lines spaces) (SAnnPop _) = Nothing
632 | FittingPredicate : Type -> Type
633 | FittingPredicate ann = Int -> Int -> Maybe Int -> SimpleDocStream ann -> Bool
635 | data LayoutPipeline ann = Nil | Cons Int (Doc ann) (LayoutPipeline ann) | UndoAnn (LayoutPipeline ann)
638 | defaultPageWidth : PageWidth
639 | defaultPageWidth = AvailablePerLine 80 1
641 | round : Double -> Int
643 | then if x - floor x < 0.5 then cast $
floor x else cast $
ceiling x
644 | else if ceiling x - x < 0.5 then cast $
ceiling x else cast $
floor x
647 | remainingWidth : Int -> Double -> Int -> Int -> Int
648 | remainingWidth lineLength ribbonFraction lineIndent currentColumn =
649 | let columnsLeftInLine = lineLength - currentColumn
650 | ribbonWidth = (max 0 . min lineLength . round) (cast lineLength * ribbonFraction)
651 | columnsLeftInRibbon = lineIndent + ribbonWidth - currentColumn in
652 | min columnsLeftInLine columnsLeftInRibbon
655 | record LayoutOptions where
656 | constructor MkLayoutOptions
657 | layoutPageWidth : PageWidth
660 | defaultLayoutOptions : LayoutOptions
661 | defaultLayoutOptions = MkLayoutOptions defaultPageWidth
665 | layoutWadlerLeijen : FittingPredicate ann -> PageWidth -> Doc ann -> SimpleDocStream ann
666 | layoutWadlerLeijen fits pageWidth_ doc = best 0 0 (Cons 0 doc Nil)
668 | initialIndentation : SimpleDocStream ann -> Maybe Int
669 | initialIndentation (SLine i _) = Just i
670 | initialIndentation (SAnnPush _ s) = initialIndentation s
671 | initialIndentation (SAnnPop s) = initialIndentation s
672 | initialIndentation _ = Nothing
674 | selectNicer : Int -> Int -> SimpleDocStream ann -> Lazy (SimpleDocStream ann) -> SimpleDocStream ann
675 | selectNicer lineIndent currentColumn x y =
676 | if fits lineIndent currentColumn (initialIndentation y) x then x else y
678 | best : Int -> Int -> LayoutPipeline ann -> SimpleDocStream ann
679 | best _ _ Nil = SEmpty
680 | best nl cc (UndoAnn ds) = SAnnPop (best nl cc ds)
681 | best nl cc (Cons i Empty ds) = best nl cc ds
682 | best nl cc (Cons i (Chara c) ds) = SChar c (best nl (cc + 1) ds)
683 | best nl cc (Cons i (Text l t) ds) = SText l t (best nl (cc + l) ds)
684 | best nl cc (Cons i Line ds) = let x = best i i ds
690 | best nl cc c@(Cons i (FlatAlt x y) ds) = best nl cc $
assert_smaller c (Cons i x ds)
691 | best nl cc (Cons i (Cat x y) ds) = assert_total $
best nl cc (Cons i x (Cons i y ds))
692 | best nl cc c@(Cons i (Nest j x) ds) = best nl cc $
assert_smaller c (Cons (i + j) x ds)
693 | best nl cc c@(Cons i (Union x y) ds) = let x' = best nl cc $
assert_smaller c (Cons i x ds)
694 | y' = delay $
best nl cc $
assert_smaller c (Cons i y ds) in
695 | selectNicer nl cc x' y'
696 | best nl cc c@(Cons i (Column f) ds) = best nl cc $
assert_smaller c (Cons i (f cc) ds)
697 | best nl cc c@(Cons i (WithPageWidth f) ds) = best nl cc $
assert_smaller c (Cons i (f pageWidth_) ds)
698 | best nl cc c@(Cons i (Nesting f) ds) = best nl cc $
assert_smaller c (Cons i (f i) ds)
699 | best nl cc c@(Cons i (Annotated ann x) ds) = SAnnPush ann $
best nl cc $
assert_smaller c (Cons i x (UndoAnn ds))
703 | layoutUnbounded : Doc ann -> SimpleDocStream ann
704 | layoutUnbounded = layoutWadlerLeijen (\_, _, _, sdoc => True) Unbounded
706 | fits : Int -> SimpleDocStream ann -> Bool
707 | fits w s = if w < 0 then False
710 | SChar _ x => fits (w - 1) x
711 | SText l _ x => fits (w - l) x
713 | SAnnPush _ x => fits w x
714 | SAnnPop x => fits w x
718 | layoutPretty : LayoutOptions -> Doc ann -> SimpleDocStream ann
719 | layoutPretty (MkLayoutOptions pageWidth_@(AvailablePerLine lineLength ribbonFraction)) =
720 | layoutWadlerLeijen (\lineIndent, currentColumn, _, sdoc =>
721 | fits (remainingWidth lineLength ribbonFraction lineIndent currentColumn) sdoc) pageWidth_
722 | layoutPretty (MkLayoutOptions Unbounded) = layoutUnbounded
726 | layoutSmart : LayoutOptions -> Doc ann -> SimpleDocStream ann
727 | layoutSmart (MkLayoutOptions pageWidth_@(AvailablePerLine lineLength ribbonFraction)) =
728 | layoutWadlerLeijen fits pageWidth_
730 | fits : Int -> Int -> Maybe Int -> SimpleDocStream ann -> Bool
731 | fits lineIndent currentColumn initialIndentY sdoc = go availableWidth sdoc
733 | availableWidth : Int
734 | availableWidth = remainingWidth lineLength ribbonFraction lineIndent currentColumn
736 | minNestingLevel : Int
737 | minNestingLevel = case initialIndentY of
738 | Just i => min i currentColumn
739 | Nothing => currentColumn
741 | go : Int -> SimpleDocStream ann -> Bool
746 | SChar _ x => go (w - 1) $
assert_smaller s x
747 | SText l _ x => go (w - l) $
assert_smaller s x
748 | SLine i x => if minNestingLevel < i
749 | then go (lineLength - i) $
assert_smaller s x
751 | SAnnPush _ x => go w x
752 | SAnnPop x => go w x
753 | layoutSmart (MkLayoutOptions Unbounded) = layoutUnbounded
757 | layoutCompact : Doc ann -> SimpleDocStream ann
758 | layoutCompact doc = scan 0 [doc]
760 | scan : Int -> List (Doc ann) -> SimpleDocStream ann
762 | scan col (Empty :: ds) = scan col ds
763 | scan col ((Chara c) :: ds) = SChar c (scan (col + 1) ds)
764 | scan col ((Text l t) :: ds) = SText l t (scan (col + l) ds)
765 | scan col s@((FlatAlt x _) :: ds) = scan col $
assert_smaller s (x :: ds)
766 | scan col (Line :: ds) = SLine 0 (scan 0 ds)
767 | scan col s@((Cat x y) :: ds) = scan col $
assert_smaller s (x :: y :: ds)
768 | scan col s@((Nest _ x) :: ds) = scan col $
assert_smaller s (x :: ds)
769 | scan col s@((Union _ y) :: ds) = scan col $
assert_smaller s (y :: ds)
770 | scan col s@((Column f) :: ds) = scan col $
assert_smaller s (f col :: ds)
771 | scan col s@((WithPageWidth f) :: ds) = scan col $
assert_smaller s (f Unbounded :: ds)
772 | scan col s@((Nesting f) :: ds) = scan col $
assert_smaller s (f 0 :: ds)
773 | scan col s@((Annotated _ x) :: ds) = scan col $
assert_smaller s (x :: ds)
781 | renderShow : SimpleDocStream ann -> (String -> String)
782 | renderShow SEmpty = id
783 | renderShow (SChar c x) = (strCons c) . renderShow x
784 | renderShow (SText _ t x) = (t ++) . renderShow x
785 | renderShow (SLine i x) = ((strCons '\n' $
textSpaces i) ++) . renderShow x
786 | renderShow (SAnnPush _ x) = renderShow x
787 | renderShow (SAnnPop x) = renderShow x
790 | Show (Doc ann) where
791 | show doc = renderShow (layoutPretty defaultLayoutOptions doc) ""
798 | displaySpans : SimpleDocStream a -> (String, List (Span a))
800 | let (bits, anns) = go Z [<] [<] [] p in
801 | (concat bits, anns)
805 | go : (index : Nat) ->
806 | (doc : SnocList String) ->
807 | (spans : SnocList (Span a)) ->
808 | (ann : List (Nat, a)) ->
809 | SimpleDocStream a ->
810 | (List String, List (Span a))
811 | go index doc spans ann SEmpty = (doc <>> [], spans <>> [])
812 | go index doc spans ann (SChar c rest)
813 | = go (S index) (doc :< cast c) spans ann rest
814 | go index doc spans ann (SText len text rest)
815 | = go (integerToNat (cast len) + index) (doc :< text) spans ann rest
816 | go index doc spans ann (SLine i rest)
817 | = let text = strCons '\n' (textSpaces i) in
818 | go (S (integerToNat $
cast i) + index) (doc :< text) spans ann rest
819 | go index doc spans ann (SAnnPush a rest)
820 | = go index doc spans ((index, a) :: ann) rest
821 | go index doc spans ((start, a) :: ann) (SAnnPop rest)
822 | = let span = MkSpan start (minus index start) a in
823 | go index doc (spans :< span) ann rest
824 | go index doc spans [] (SAnnPop rest)
825 | = go index doc spans [] rest