1 {-# LANGUAGE DeriveFunctor #-}
2 {-# OPTIONS_GHC -fno-warn-orphans #-}
4 module Webc.Layouter where
6 import Control.Applicative (Applicative (..))
7 import Data.Either (Either (..))
8 import Data.Eq (Eq (..))
9 import Data.Function (id, ($), (.))
10 import Data.Functor (Functor, (<$>))
11 import Data.List qualified as List
12 import Data.Ord (Ord (..))
13 import Data.Semigroup (Semigroup (..))
14 import Data.Tree (Forest, Tree (..), drawForest)
15 import Network.URI.Slug
16 import Symantic.Classes (Iso (..), IsoFunctor (..), ProductFunctor (..), SumFunctor ((<+>)))
17 import Text.Show (Show (..))
21 -- * The 'Layouter' interpreter
23 newtype Layouter a = Layouter
25 LayoutBranch (Forest LayoutNode)
29 layout :: Layouter a -> Forest LayoutNode
30 layout = collapseLayoutBranch . unLayouter
32 layouter :: Layouter a -> Layouter a
35 {- | Keep the path in the 'Tree'
36 where to append new branches;
37 in reverse order to simplify appending.
39 type LayoutBranch = []
41 {- | Fold 'LayoutBranch' maintained for appending;
42 to be done when there is no more appending.
44 collapseLayoutBranch ::
45 LayoutBranch (Forest LayoutNode) ->
47 collapseLayoutBranch =
49 (\ts acc -> ((\(Node n ns) -> Node n (ns <> acc)) <$> ts))
52 instance Show a => Show (Layouter a) where
53 show = drawForest . ((show <$>) <$>) . layout
55 instance IsoFunctor Layouter where
56 Iso{..} <%> x = a2b <$> x
58 -- ** Type 'LayoutNode'
61 deriving (Eq, Ord, Show)
63 layoutNode :: LayoutNode -> Layouter a
64 layoutNode = Layouter . pure . pure . pure
66 coerceLayout :: Layouter a -> Layouter b
67 coerceLayout = Layouter . unLayouter
69 instance ProductFunctor Layouter where
70 x <.> y = Layouter $ unLayouter (coerceLayout x) <> unLayouter (coerceLayout y)
71 x .> y = Layouter $ unLayouter (coerceLayout x) <> unLayouter y
72 x <. y = Layouter $ unLayouter x <> unLayouter (coerceLayout y)
73 instance SumFunctor Layouter where
76 [ collapseLayoutBranch (unLayouter (Left <$> x))
77 <> collapseLayoutBranch (unLayouter (Right <$> y))
79 instance Slugable Layouter where
80 slug = layoutNode . LayoutNodeSlug