0 | module Data.Container.Base.Display2D.Display2D
7 | import Data.Container.Base.Object.Definition
8 | import Data.Container.Base.Extension.Definition
9 | import Data.Container.Base.Product.Definition
11 | import Data.Container.Base.Object.Instances
12 | import Data.Container.Base.Extension.Instances
13 | import Data.Container.Base.Properties.Instances
15 | import public Data.Container.Base.Display2D.CharacterMap
16 | import Data.ScientificNotation
18 | import Data.Container.Base.TreeUtils
39 | defaultLineWidth : Nat
40 | defaultLineWidth = 75
50 | Grid = Ext (List >< List)
53 | gridHeight : Grid a -> Nat
54 | gridHeight ((h, _) <| _) = h
57 | gridWidth : Grid a -> Nat
58 | gridWidth ((_, w) <| _) = w
63 | gridIndex : (g : Grid a) -> Fin (gridHeight g) -> Fin (gridWidth g) -> a
64 | gridIndex ((_, _) <| f) i j = f (i, j)
68 | mkGrid : (h, w : Nat) -> (Fin h -> Fin w -> a) -> Grid a
69 | mkGrid h w f = (h, w) <| uncurry f
79 | gridRows : Grid a -> List (List a)
81 | toList' $
Fin.tabulate {len = gridHeight g} $
\i =>
82 | toList' $
Fin.tabulate {len = gridWidth g} $
\j =>
88 | showGrid : Grid Char -> String
90 | concat . intersperse "\n" . map (pack . dropFromEnd padCharacter) . gridRows
99 | emptyGrid = mkGrid 0 0 absurd
102 | singleValue : a -> Grid a
103 | singleValue v = mkGrid 1 1 (\_, _ => v)
106 | uniformCol : a -> Nat -> Grid a
107 | uniformCol v h = mkGrid h 1 (\_, _ => v)
110 | blankCol : Nat -> Grid Char
111 | blankCol = uniformCol padCharacter
115 | rowGrid : List a -> Grid a
116 | rowGrid xs = mkGrid 1 (length xs) (\_, j => index j (fromList xs))
121 | topMarkerCol : (marker : Char) -> (h : Nat) -> Grid Char
122 | topMarkerCol _ Z = emptyGrid
123 | topMarkerCol c (S k) = mkGrid (S k) 1 $
\i, _ => case i of
130 | bottomMarkerCol : (marker : Char) -> (h : Nat) -> Grid Char
131 | bottomMarkerCol _ Z = emptyGrid
132 | bottomMarkerCol c (S k) = mkGrid (S k) 1 $
\i, _ => case i == last of
134 | False => padCharacter
150 | locateChunk : (size : Grid a -> Nat) ->
152 | (gs : List (Grid a)) ->
154 | Maybe (g : Grid a ** Fin (size g))
155 | locateChunk _ _ [] _ = Nothing
156 | locateChunk size gap (g :: gs) i = case natToFin i (size g) of
157 | Just j => Just (
g ** j)
158 | Nothing => let sz = size g
159 | in case i < sz + gap of
161 | False => locateChunk size gap gs (minus i (sz + gap))
167 | besideAllGap : (padValue : a) -> (gap : Nat) -> List (Grid a) -> Grid a
168 | besideAllGap _ _ [] = emptyGrid
169 | besideAllGap _ _ [g] = g
170 | besideAllGap pad gap grids@(_ :: _) =
171 | let maxHeight = max (gridHeight <$> grids)
172 | sumWidths = List.sum (gridWidth <$> grids) + gap * pred (length grids)
173 | in mkGrid maxHeight sumWidths $
\i, j => fromMaybe pad $
do
174 | (
g ** j')
<- locateChunk gridWidth gap grids (finToNat j)
175 | i' <- natToFin (finToNat i) (gridHeight g)
176 | pure (gridIndex g i' j')
180 | besideAll : (padValue : a) -> List (Grid a) -> Grid a
181 | besideAll pad = besideAllGap pad 0
187 | aboveAllSep : (padValue : a) -> (sep : Nat) -> List (Grid a) -> Grid a
188 | aboveAllSep _ _ [] = emptyGrid
189 | aboveAllSep _ _ [g] = g
190 | aboveAllSep pad sep grids@(_ :: _) =
191 | let sumHeights = List.sum (gridHeight <$> grids) + sep * pred (length grids)
192 | maxWidth = max (gridWidth <$> grids)
193 | in mkGrid sumHeights maxWidth $
\i, j => fromMaybe pad $
do
194 | (
g ** i')
<- locateChunk gridHeight sep grids (finToNat i)
195 | j' <- natToFin (finToNat j) (gridWidth g)
196 | pure (gridIndex g i' j')
200 | aboveAll : (padValue : a) -> List (Grid a) -> Grid a
201 | aboveAll pad = aboveAllSep pad 0
206 | padGridLeft : (w : Nat) -> Grid Char -> Grid Char
207 | padGridLeft w g = besideAll padCharacter
208 | [mkGrid (gridHeight g) (w `minus` gridWidth g) (\_, _ => padCharacter), g]
216 | data Side : (k : Nat) -> Type where
219 | AtMid : Fin k -> Side k
221 | side : {k : Nat} -> Fin (S (S k)) -> Side k
223 | side (FS x) = maybe AtEnd AtMid (strengthen x)
227 | addBorderToGrid : (box : Box) => Grid Char -> Grid Char
228 | addBorderToGrid g = mkGrid (2 + gridHeight g) (2 + gridWidth g) $
\i, j =>
229 | case (side i, side j) of
230 | (AtMid i', AtMid j') => gridIndex g i' j'
231 | (AtMid _, _) => box.vertical
232 | (_, AtMid _) => box.horizontal
233 | (AtStart, AtStart) => box.topLeft
234 | (AtStart, AtEnd) => box.topRight
235 | (AtEnd, AtStart) => box.bottomLeft
236 | (AtEnd, AtEnd) => box.bottomRight
240 | wrapNonEmpty : Box => Grid Char -> Grid Char
241 | wrapNonEmpty g = applyWhen (gridHeight g > 1) addBorderToGrid g
246 | wrapAllIfAnyNonEmpty : Box =>
247 | List (Grid Char) -> (Grid Char -> Grid Char)
248 | wrapAllIfAnyNonEmpty grids =
249 | applyWhen (any (\g => gridHeight g > 1) grids) addBorderToGrid
258 | horizontalListJoin : (listSyntax : ListSyntax) => List (Grid Char) -> Grid Char
259 | horizontalListJoin [] = emptyGrid
260 | horizontalListJoin [g] = g
261 | horizontalListJoin gs = besideAll padCharacter (intersperse sep gs)
262 | where sep = besideAll padCharacter
263 | [singleValue listSyntax.separator, singleValue padCharacter]
274 | wrapListBrackets : (listSyntax : ListSyntax) =>
275 | (nSep : Nat) -> List (Grid Char) -> Grid Char
276 | wrapListBrackets _ [] = besideAll padCharacter
277 | [singleValue listSyntax.left, singleValue listSyntax.right]
278 | wrapListBrackets nSep (x :: xs) =
279 | let body = aboveAllSep padCharacter nSep (x :: xs)
280 | leftCol = aboveAll padCharacter $
281 | topMarkerCol listSyntax.left (gridHeight x) ::
282 | concatMap (\g => [ blankCol nSep
283 | , topMarkerCol listSyntax.separator (gridHeight g)
285 | rightCol = bottomMarkerCol listSyntax.right (gridHeight body)
286 | in besideAll padCharacter [leftCol, body, rightCol]
303 | wrappedInnerRow : (listSyntax : ListSyntax) =>
304 | (lineBudget, gap : Nat) -> List (Grid Char) -> Grid Char
305 | wrappedInnerRow _ _ [] = besideAll padCharacter
306 | [singleValue listSyntax.left, singleValue listSyntax.right]
307 | wrappedInnerRow lineBudget gap children@(c :: _) =
308 | let cellsPerLine = max 1 $
(lineBudget `minus` 2 + gap) `div` (gridWidth c + gap)
309 | chunks = chunksOf cellsPerLine children
310 | nChunks = length chunks
311 | chunkRow : Nat -> List (Grid Char) -> Grid Char
313 | let leftC = if i == 0 then listSyntax.left else padCharacter
314 | rightC = if S i == nChunks then listSyntax.right else padCharacter
315 | in besideAll padCharacter
316 | [ singleValue leftC
317 | , besideAllGap padCharacter gap cs
318 | , singleValue rightC ]
319 | in aboveAll padCharacter (mapWithIndex chunkRow chunks)
330 | interface Display2D (0 a : Type) where
331 | constructor MkDisplay2D
332 | display2D : a -> Grid Char
335 | Display2D (Grid Char) where
340 | display2DFromShow : Show a => a -> Grid Char
341 | display2DFromShow x = rowGrid (unpack (show x))
345 | display2DFromSci : ScientificDisplay a => a -> Grid Char
346 | display2DFromSci x = rowGrid (unpack (showSci x))
348 | public export Display2D Int where display2D = display2DFromShow
349 | public export Display2D Integer where display2D = display2DFromSci
350 | public export Display2D Double where display2D = display2DFromSci
351 | public export Display2D Nat where display2D = display2DFromSci
352 | public export Display2D Bool where display2D = display2DFromShow
353 | public export Display2D () where display2D = display2DFromShow
354 | public export Display2D Char where display2D = singleValue
355 | public export Display2D String where display2D s = rowGrid (unpack s)
363 | Display2D a => Display2D (Scalar' a) where
364 | display2D (() <| index) = display2D (index ())
367 | Display2D a => Display2D b => Display2D (a, b) where
368 | display2D (x, y) = besideAll padCharacter
369 | [ singleValue (left AsciiPairSyntax)
371 | , singleValue (separator AsciiPairSyntax)
373 | , singleValue (right AsciiPairSyntax) ]
376 | Display2D a => Display2D (Pair' a) where
377 | display2D (() <| index) = besideAll padCharacter
378 | [ singleValue (left AsciiPairSyntax)
379 | , display2D (index False)
380 | , singleValue (separator AsciiPairSyntax)
381 | , display2D (index True)
382 | , singleValue (right AsciiPairSyntax) ]
385 | Display2D a => Display2D (List' a) where
386 | display2D (_ <| index) = besideAll padCharacter
387 | [ singleValue (left AsciiListSyntax)
388 | , horizontalListJoin {listSyntax = AsciiListSyntax}
389 | (display2D <$> toList' (tabulate index))
390 | , singleValue (right AsciiListSyntax) ]
399 | treeBranchPrefix : (tree : Tree) =>
400 | (connector, continuation : Char) -> (height : Nat) -> Grid Char
401 | treeBranchPrefix _ _ Z = emptyGrid
402 | treeBranchPrefix conn cont (S k) = mkGrid (S k) 2 $
\i, j =>
405 | (FZ, _ ) => tree.horizontal
407 | (_ , _ ) => tree.gap
410 | addBranch : Tree =>
411 | (connector, continuation : Char) -> Grid Char -> Grid Char
412 | addBranch conn cont g = besideAll padCharacter
413 | [treeBranchPrefix conn cont (gridHeight g), blankCol (gridHeight g), g]
416 | treeSiblingGapRow : (tree : Tree) => (w : Nat) -> Grid Char
417 | treeSiblingGapRow Z = emptyGrid
418 | treeSiblingGapRow (S k) = mkGrid 1 (S k) $
\_, j => case j of
419 | FZ => tree.vertical
423 | displayNodeWithBranches : (tree : Tree) =>
424 | (root, left, right : Grid Char) -> Grid Char
425 | displayNodeWithBranches root left right =
426 | let leftB = addBranch tree.branchMid tree.vertical left
427 | rightB = addBranch tree.branchLast tree.gap right
428 | top = aboveAll padCharacter
429 | [root, treeSiblingGapRow (maximum (gridWidth root) (gridWidth leftB)), leftB]
430 | in aboveAll padCharacter [top, treeSiblingGapRow (gridWidth top), rightB]
438 | collectBinTreeValues : Display2D a =>
440 | (List (Grid Char), List (Grid Char))
441 | collectBinTreeValues (LeafS <| index) = ([], [display2D (index AtLeaf)])
442 | collectBinTreeValues n@(NodeS l r <| index) =
443 | let (ln, ll) = collectBinTreeValues $
assert_smaller n (l <| (index . GoLeft))
444 | (rn, rl) = collectBinTreeValues $
assert_smaller n (r <| (index . GoRight))
445 | in (display2D (index AtNode) :: (ln ++ rn), ll ++ rl)
448 | displayBinTreeWith : Display2D a => (tree : Tree) =>
449 | (nodeBox, leafBox : Grid Char -> Grid Char) ->
450 | BinTree' a -> Grid Char
451 | displayBinTreeWith _ leafBox (LeafS <| index)
452 | = leafBox (display2D (index AtLeaf))
453 | displayBinTreeWith nodeBox leafBox n@(NodeS l r <| index) =
454 | displayNodeWithBranches (nodeBox (display2D (index AtNode)))
455 | (displayBinTreeWith nodeBox leafBox $
assert_smaller n (l <| (index . GoLeft)))
456 | (displayBinTreeWith nodeBox leafBox $
assert_smaller n (r <| (index . GoRight)))
458 | displayBinTree : Display2D a => (tree : Tree) => (box : Box) =>
459 | BinTree' a -> Grid Char
461 | let (nodeEGs, leafEGs) = collectBinTreeValues t
462 | in displayBinTreeWith (wrapAllIfAnyNonEmpty nodeEGs)
463 | (wrapAllIfAnyNonEmpty leafEGs) t
466 | Display2D a => Display2D (BinTree' a) where
467 | display2D = displayBinTree {tree = SingleLineTree, box = DoubleLineBox}
475 | collectLeafValues : Display2D a =>
478 | collectLeafValues (LeafS <| index) = [display2D (index AtLeaf)]
479 | collectLeafValues n@(NodeS l r <| index) =
480 | collectLeafValues (assert_smaller n (l <| index . GoLeft)) ++
481 | collectLeafValues (assert_smaller n (r <| index . GoRight))
483 | displayBinTreeLeafWith : Display2D a => (tree : Tree) =>
484 | (leafBox : Grid Char -> Grid Char) ->
485 | BinTreeLeaf' a -> Grid Char
486 | displayBinTreeLeafWith box (LeafS <| index) = box (display2D (index AtLeaf))
487 | displayBinTreeLeafWith box n@(NodeS l r <| index) =
488 | displayNodeWithBranches (singleValue tree.placeholder)
489 | (displayBinTreeLeafWith box $
assert_smaller n (l <| index . GoLeft))
490 | (displayBinTreeLeafWith box $
assert_smaller n (r <| index . GoRight))
493 | displayBinTreeLeaf : Display2D a => (tree : Tree) => (box : Box) =>
494 | BinTreeLeaf' a -> Grid Char
495 | displayBinTreeLeaf t =
496 | displayBinTreeLeafWith (wrapAllIfAnyNonEmpty (collectLeafValues t)) t
499 | Display2D a => Display2D (Ext BinTreeLeaf a) where
500 | display2D = displayBinTreeLeaf {tree = SingleLineTree, box = DoubleLineBox}
508 | collectNodeValues : Display2D a =>
509 | BinTreeNode' a -> List (Grid Char)
510 | collectNodeValues (LeafS <| _) = []
511 | collectNodeValues n@(NodeS l r <| index) =
512 | let leftValues = collectNodeValues $
assert_smaller n (l <| index . GoLeft)
513 | rightValues = collectNodeValues $
assert_smaller n (r <| index . GoRight)
514 | in display2D (index AtNode) :: (leftValues ++ rightValues)
517 | displayBinTreeNodeWith : Display2D a => (tree : Tree) =>
518 | (nodeBox : Grid Char -> Grid Char) ->
519 | BinTreeNode' a -> Grid Char
520 | displayBinTreeNodeWith _ (LeafS <| _) = singleValue tree.placeholder
521 | displayBinTreeNodeWith box n@(NodeS l r <| index) =
522 | displayNodeWithBranches (box (display2D (index AtNode)))
523 | (displayBinTreeNodeWith box $
assert_smaller n (l <| index . GoLeft))
524 | (displayBinTreeNodeWith box $
assert_smaller n (r <| index . GoRight))
527 | displayBinTreeNode : Display2D a => (tree : Tree) => (box : Box) =>
528 | BinTreeNode' a -> Grid Char
529 | displayBinTreeNode t =
530 | displayBinTreeNodeWith (wrapAllIfAnyNonEmpty (collectNodeValues t)) t
533 | Display2D a => Display2D (Ext BinTreeNode a) where
534 | display2D = displayBinTreeNode {tree = SingleLineTree, box = DoubleLineBox}
537 | {n : Nat} -> Display2D a => Display2D (Ext (Vect n) a) where
538 | display2D (() <| index) = display2D {a = Ext List a} (n <| index)
541 | showViaDisplay2D : Display2D a => a -> String
542 | showViaDisplay2D = showGrid . display2D
545 | Display2D a => Show (Scalar' a) where
546 | show = showViaDisplay2D
549 | Display2D a => Show (Pair' a) where
550 | show = showViaDisplay2D
553 | Display2D a => Show (List' a) where
554 | show = showViaDisplay2D
557 | {n : Nat} -> Display2D a => Show (Vect' n a) where
558 | show = showViaDisplay2D
561 | Display2D a => Show (BinTree' a) where
562 | show t = showViaDisplay2D t
565 | Display2D a => Show (BinTreeLeaf' a) where
566 | show t = showViaDisplay2D t
569 | Display2D a => Show (BinTreeNode' a) where
570 | show t = showViaDisplay2D t