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)
372 | , singleValue padCharacter
374 | , singleValue (right AsciiPairSyntax) ]
377 | Display2D a => Display2D (Pair' a) where
378 | display2D (() <| index) = besideAll padCharacter
379 | [ singleValue (left AsciiPairSyntax)
380 | , display2D (index False)
381 | , singleValue (separator AsciiPairSyntax)
382 | , display2D (index True)
383 | , singleValue (right AsciiPairSyntax) ]
386 | Display2D a => Display2D (List' a) where
387 | display2D (_ <| index) = besideAll padCharacter
388 | [ singleValue (left AsciiListSyntax)
389 | , horizontalListJoin {listSyntax = AsciiListSyntax}
390 | (display2D <$> toList' (tabulate index))
391 | , singleValue (right AsciiListSyntax) ]
400 | treeBranchPrefix : (tree : Tree) =>
401 | (connector, continuation : Char) -> (height : Nat) -> Grid Char
402 | treeBranchPrefix _ _ Z = emptyGrid
403 | treeBranchPrefix conn cont (S k) = mkGrid (S k) 2 $
\i, j =>
406 | (FZ, _ ) => tree.horizontal
408 | (_ , _ ) => tree.gap
411 | addBranch : Tree =>
412 | (connector, continuation : Char) -> Grid Char -> Grid Char
413 | addBranch conn cont g = besideAll padCharacter
414 | [treeBranchPrefix conn cont (gridHeight g), blankCol (gridHeight g), g]
417 | treeSiblingGapRow : (tree : Tree) => (w : Nat) -> Grid Char
418 | treeSiblingGapRow Z = emptyGrid
419 | treeSiblingGapRow (S k) = mkGrid 1 (S k) $
\_, j => case j of
420 | FZ => tree.vertical
424 | displayNodeWithBranches : (tree : Tree) =>
425 | (root, left, right : Grid Char) -> Grid Char
426 | displayNodeWithBranches root left right =
427 | let leftB = addBranch tree.branchMid tree.vertical left
428 | rightB = addBranch tree.branchLast tree.gap right
429 | top = aboveAll padCharacter
430 | [root, treeSiblingGapRow (maximum (gridWidth root) (gridWidth leftB)), leftB]
431 | in aboveAll padCharacter [top, treeSiblingGapRow (gridWidth top), rightB]
439 | collectBinTreeValues : Display2D a =>
441 | (List (Grid Char), List (Grid Char))
442 | collectBinTreeValues (LeafS <| index) = ([], [display2D (index AtLeaf)])
443 | collectBinTreeValues n@(NodeS l r <| index) =
444 | let (ln, ll) = collectBinTreeValues $
assert_smaller n (l <| (index . GoLeft))
445 | (rn, rl) = collectBinTreeValues $
assert_smaller n (r <| (index . GoRight))
446 | in (display2D (index AtNode) :: (ln ++ rn), ll ++ rl)
449 | displayBinTreeWith : Display2D a => (tree : Tree) =>
450 | (nodeBox, leafBox : Grid Char -> Grid Char) ->
451 | BinTree' a -> Grid Char
452 | displayBinTreeWith _ leafBox (LeafS <| index)
453 | = leafBox (display2D (index AtLeaf))
454 | displayBinTreeWith nodeBox leafBox n@(NodeS l r <| index) =
455 | displayNodeWithBranches (nodeBox (display2D (index AtNode)))
456 | (displayBinTreeWith nodeBox leafBox $
assert_smaller n (l <| (index . GoLeft)))
457 | (displayBinTreeWith nodeBox leafBox $
assert_smaller n (r <| (index . GoRight)))
459 | displayBinTree : Display2D a => (tree : Tree) => (box : Box) =>
460 | BinTree' a -> Grid Char
462 | let (nodeEGs, leafEGs) = collectBinTreeValues t
463 | in displayBinTreeWith (wrapAllIfAnyNonEmpty nodeEGs)
464 | (wrapAllIfAnyNonEmpty leafEGs) t
467 | Display2D a => Display2D (BinTree' a) where
468 | display2D = displayBinTree {tree = SingleLineTree, box = DoubleLineBox}
476 | collectLeafValues : Display2D a =>
479 | collectLeafValues (LeafS <| index) = [display2D (index AtLeaf)]
480 | collectLeafValues n@(NodeS l r <| index) =
481 | collectLeafValues (assert_smaller n (l <| index . GoLeft)) ++
482 | collectLeafValues (assert_smaller n (r <| index . GoRight))
484 | displayBinTreeLeafWith : Display2D a => (tree : Tree) =>
485 | (leafBox : Grid Char -> Grid Char) ->
486 | BinTreeLeaf' a -> Grid Char
487 | displayBinTreeLeafWith box (LeafS <| index) = box (display2D (index AtLeaf))
488 | displayBinTreeLeafWith box n@(NodeS l r <| index) =
489 | displayNodeWithBranches (singleValue tree.placeholder)
490 | (displayBinTreeLeafWith box $
assert_smaller n (l <| index . GoLeft))
491 | (displayBinTreeLeafWith box $
assert_smaller n (r <| index . GoRight))
494 | displayBinTreeLeaf : Display2D a => (tree : Tree) => (box : Box) =>
495 | BinTreeLeaf' a -> Grid Char
496 | displayBinTreeLeaf t =
497 | displayBinTreeLeafWith (wrapAllIfAnyNonEmpty (collectLeafValues t)) t
500 | Display2D a => Display2D (Ext BinTreeLeaf a) where
501 | display2D = displayBinTreeLeaf {tree = SingleLineTree, box = DoubleLineBox}
509 | collectNodeValues : Display2D a =>
510 | BinTreeNode' a -> List (Grid Char)
511 | collectNodeValues (LeafS <| _) = []
512 | collectNodeValues n@(NodeS l r <| index) =
513 | let leftValues = collectNodeValues $
assert_smaller n (l <| index . GoLeft)
514 | rightValues = collectNodeValues $
assert_smaller n (r <| index . GoRight)
515 | in display2D (index AtNode) :: (leftValues ++ rightValues)
518 | displayBinTreeNodeWith : Display2D a => (tree : Tree) =>
519 | (nodeBox : Grid Char -> Grid Char) ->
520 | BinTreeNode' a -> Grid Char
521 | displayBinTreeNodeWith _ (LeafS <| _) = singleValue tree.placeholder
522 | displayBinTreeNodeWith box n@(NodeS l r <| index) =
523 | displayNodeWithBranches (box (display2D (index AtNode)))
524 | (displayBinTreeNodeWith box $
assert_smaller n (l <| index . GoLeft))
525 | (displayBinTreeNodeWith box $
assert_smaller n (r <| index . GoRight))
528 | displayBinTreeNode : Display2D a => (tree : Tree) => (box : Box) =>
529 | BinTreeNode' a -> Grid Char
530 | displayBinTreeNode t =
531 | displayBinTreeNodeWith (wrapAllIfAnyNonEmpty (collectNodeValues t)) t
534 | Display2D a => Display2D (Ext BinTreeNode a) where
535 | display2D = displayBinTreeNode {tree = SingleLineTree, box = DoubleLineBox}
538 | {n : Nat} -> Display2D a => Display2D (Ext (Vect n) a) where
539 | display2D (() <| index) = display2D {a = Ext List a} (n <| index)
542 | showViaDisplay2D : Display2D a => a -> String
543 | showViaDisplay2D = showGrid . display2D
546 | Display2D a => Show (Scalar' a) where
547 | show = showViaDisplay2D
550 | Display2D a => Show (Pair' a) where
551 | show = showViaDisplay2D
554 | Display2D a => Show (List' a) where
555 | show = showViaDisplay2D
558 | {n : Nat} -> Display2D a => Show (Vect' n a) where
559 | show = showViaDisplay2D
562 | Display2D a => Show (BinTree' a) where
563 | show t = showViaDisplay2D t
566 | Display2D a => Show (BinTreeLeaf' a) where
567 | show t = showViaDisplay2D t
570 | Display2D a => Show (BinTreeNode' a) where
571 | show t = showViaDisplay2D t