0 | module Text.PrettyPrint.Bernardy.Core
13 | data NonEmptySnoc : SnocList a -> Type where
14 | IsNonEmptySnoc : NonEmptySnoc (sx :< x)
16 | 0 nonEmptyChips : {auto p : NonEmptySnoc sx} -> NonEmpty (sx <>> xs)
17 | nonEmptyChips {sx = Lin :< _} = %search
18 | nonEmptyChips {sx = h@(_ :< _) :< _} = nonEmptyChips {sx = h}
21 | kcap : SnocList Char -> String
22 | kcap = pack . (<>> [])
26 | -> (sc : SnocList Char)
29 | allLines [] sc sl = sl :< kcap sc
30 | allLines ('\n' :: '\r' :: xs) sc sl = allLines xs Lin (sl :< kcap sc)
31 | allLines ('\n' :: xs) sc sl = allLines xs Lin (sl :< kcap sc)
32 | allLines ('\r' :: xs) sc sl = allLines xs Lin (sl :< kcap sc)
33 | allLines (x :: xs) sc sl = allLines xs (sc :< x) sl
40 | record LayoutOpts where
52 | lstats : String -> Stats
53 | lstats s = let n := length s in MkStats n n 0
56 | addStats : String -> Stats -> Stats
57 | addStats s (MkStats ml ll h) = MkStats (max ml $
length s) ll (S h)
69 | compStats : LayoutOpts -> Stats -> Stats -> Ordering
70 | compStats (Opts ll) (MkStats mll lll hl) (MkStats mlr llr hr) =
72 | if mll < mlr && ll < mlr then LT
73 | else if mlr < mll && ll < mll then GT
76 | else if mll <= mlr && lll <= llr && hl <= hr then LT
77 | else if mlr <= mll && llr <= lll && hr <= hl then GT
86 | constructor MkLayout
94 | content : Lazy (SnocList String)
96 | {auto 0 prfNonEmptyContent : NonEmptySnoc content}
98 | layout : Lazy (Subset (SnocList String) NonEmptySnoc) -> Stats -> Layout
99 | layout ss st = MkLayout (fst ss) st @{snd ss}
105 | height : Layout -> Nat
106 | height = S . height . stats
110 | isMultiline : Layout -> Bool
111 | isMultiline = (> 1) . height
115 | width : Layout -> Nat
116 | width = maxLine . stats
119 | isEmpty : Layout -> Bool
120 | isEmpty l = height l == 0 && width l == 0
125 | empty = MkLayout [<""] (MkStats 0 0 0)
129 | render : Layout -> String
130 | render (MkLayout sl _) = unlines (sl <>> [])
136 | line : (str : String) -> Layout
137 | line s = MkLayout [<s] (lstats s)
144 | text : (str : String) -> Layout
145 | text str = case allLines (unpack str) Lin Lin of
147 | ls@(sx :< x) => MkLayout ls (foldr addStats (lstats x) sx)
150 | (sx : SnocList String)
151 | -> (xs : List String)
152 | -> {auto 0 p1 : NonEmptySnoc sx}
154 | -> Subset (SnocList String) NonEmptySnoc
155 | indentOnto sx [] _ = Element sx p1
156 | indentOnto sx (x :: xs) n = indentOnto (sx :< indent n x) xs n
159 | (sx : SnocList String)
160 | -> (xs : List String)
161 | -> {auto 0 p1 : NonEmptySnoc sx}
162 | -> {auto 0 p2 : NonEmpty xs}
164 | -> Subset (SnocList String) NonEmptySnoc
165 | appendOnto (sx :< x) (y :: ys) n = indentOnto (sx :< (x ++ y)) ys n
170 | Semigroup Layout where
171 | MkLayout c s <+> MkLayout d t =
173 | 0 prf := nonEmptyChips {xs = []} {sx = d}
177 | maxLine = max s.maxLine $
s.lastLine + t.maxLine
178 | , lastLine = s.lastLine + t.maxLine
179 | , height = s.height + t.height
182 | in layout (appendOnto c (d <>> []) s.lastLine) newStats
185 | Monoid Layout where
189 | FromString Layout where
193 | flush : Layout -> Layout
194 | flush (MkLayout sl $
MkStats ml _ h) =
195 | MkLayout (sl :< "") (MkStats ml 0 $
S h)
198 | indent : Nat -> Layout -> Layout
201 | indent k x = MkLayout [< replicate k ' '] (MkStats k k 0) <+> x
203 | shortest : Layout -> List Layout -> Layout
205 | foldl (\x,y => if x.stats.height <= y.stats.height then x else y) x xs
213 | record Doc (opts : LayoutOpts) where
219 | pure : Layout -> Doc opts
220 | pure l = MkDoc l []
223 | layouts : Doc opts -> List Layout
224 | layouts (MkDoc h t) = h :: t
229 | render : (opts : _) -> Doc opts -> String
230 | render opts (MkDoc x xs) = render $
shortest x xs
233 | chips1 : SnocList Layout -> Layout -> List Layout -> Doc opts
234 | chips1 (sx :< y) x xs = chips1 sx y (x :: xs)
235 | chips1 [<] x xs = MkDoc x xs
243 | insert sl [] x = chips1 sl x []
244 | insert sl (h :: t) x = case compStats opts x.stats h.stats of
245 | LT => insert sl t x
246 | EQ => insert (sl :< h) t x
247 | GT => chips1 sl h t
249 | combine : {opts : _} -> Doc opts -> List Layout -> Doc opts
250 | combine d (y :: ys) = combine (insert Lin (layouts d) y) ys
255 | (<|>) : {opts : _} -> Doc opts -> Doc opts -> Doc opts
256 | x <|> y = combine x $
layouts y
289 | (<+>) : {opts : _} -> Doc opts -> Doc opts -> Doc opts
290 | MkDoc x xs <+> MkDoc y ys =
291 | let appYs := \v => MkDoc (v <+> y) (map (v <+>) ys)
293 | in foldl (\acc,x => combine {opts} (appYs x) $
layouts acc) ini xs
296 | FromString (Doc opts) where
297 | fromString str = pure $
fromString str
302 | empty = pure neutral
305 | (>>=) : {opts : _} -> Doc opts -> (Layout -> Doc opts) -> Doc opts
306 | (>>=) (MkDoc x xs) f = foldl (\d,l => d <|> f l) (f x) xs
312 | line : (str : String) -> Doc opts
318 | flush : {opts : _} -> Doc opts -> Doc opts
319 | flush (MkDoc x xs) = MkDoc (flush x) $
map flush xs
323 | indent : {opts : _} -> Nat -> Doc opts -> Doc opts
324 | indent k (MkDoc x xs) = combine (pure $
indent k x) (indent k <$> xs)
328 | indent' : {opts : _} -> Nat -> Doc opts -> Doc opts
331 | pure $
if isEmpty l then l else indent k l
335 | text : String -> (Doc opts)