miso-css-0.0.1: src/Miso/Css/Segment.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Miso.Css.Segment where
import Miso.Css.List ( RemoveElem )
import Miso.Css.Prelude
data SubSeg
= C Symbol -- ^ Element Class
| T Symbol -- ^ Element Name (Tag)
| I Symbol -- ^ Element Id
| A Symbol -- ^ Attribute Name
| R -- ^ CSS :root
| B -- ^ Bottom is added to Seg to prevent matching branch later
-- used to support CSS '>' syntax
type family MbSymToMbI mbs where
MbSymToMbI Nothing = Nothing
MbSymToMbI (Just s) = Just (I s)
data MatchScope
= NowOrLater
| JustNow
| AutoClean -- ^ similar to JustNow but Segment is removed right away once UM list becomes empty.
-- an empty JustNow segment lives until </, this way
-- subseg constrains of tag to be applied
-- why JustNow cannot be replaced with AutoClean?
-- it cannot be replaced because following selector .a > p.c is indistiguishable from p.c.a
-- Seg.siblings are empty for AutoClean
deriving (Show, Eq)
-- | Composite segment
-- matched part is appended to unmatched when algorithm goes up to parent node
-- if unmatched is not empty
-- if unmatched is empty then list head is dropped
-- every SubSeg match step (ie class, id or tag name)
type Seg =
( MatchScope
, [SubSeg] -- unmatched
, [SubSeg] -- matched
, [[(MatchScope, [SubSeg])]] -- siblings
)
-- Initially Branch was [Seg] but it turned out that
-- selector ".a > .b" fails on hierarchy:
-- <p class="a">
-- <p class="b">
-- <p class="b">
-- The solution is to fork a branch if its head segment is JN when it matches
-- current element and match scope of previous segment in the branch is NL
newtype BRANCH = Branch [Seg]
type SegsOfBranch :: BRANCH -> [Seg]
type family SegsOfBranch b where
SegsOfBranch (Branch sgs) = sgs
type family UnwrapBranchesInElem e where
UnwrapBranchesInElem '[] = '[]
UnwrapBranchesInElem (b : bs) = SegsOfBranch b : UnwrapBranchesInElem bs
type family UnwrapBranches es where
UnwrapBranches '[] = '[]
UnwrapBranches (e : es) = UnwrapBranchesInElem e : UnwrapBranches es
type RemoveMatchScopeInSubSibling :: (MatchScope, [SubSeg]) -> [SubSeg]
type family RemoveMatchScopeInSubSibling sib where
RemoveMatchScopeInSubSibling '( _, sb) = sb
type RemoveMatchScopeInSibling :: [(MatchScope, [SubSeg])] -> [[SubSeg]]
type family RemoveMatchScopeInSibling sib where
RemoveMatchScopeInSibling '[] = '[]
RemoveMatchScopeInSibling (x : xs) =
RemoveMatchScopeInSubSibling x : RemoveMatchScopeInSibling xs
type family RemoveMatchScopeInSiblings sibs where
RemoveMatchScopeInSiblings '[] = '[]
RemoveMatchScopeInSiblings (s : ss) =
RemoveMatchScopeInSibling s : RemoveMatchScopeInSiblings ss
type family RemoveMatchScopeSegments e where
RemoveMatchScopeSegments '[] = '[]
RemoveMatchScopeSegments ( '(_, um, m, sibs) : bs) =
'(um, m, RemoveMatchScopeInSiblings sibs) : RemoveMatchScopeSegments bs
type family RemoveMatchScopeInBranch b where
RemoveMatchScopeInBranch sgs = RemoveMatchScopeSegments sgs
type family RemoveMatchScopeInElem e where
RemoveMatchScopeInElem '[] = '[]
RemoveMatchScopeInElem (b : bs) = RemoveMatchScopeInBranch b : RemoveMatchScopeInElem bs
type family RemoveMatchScope es where
RemoveMatchScope '[] = '[]
RemoveMatchScope (e : es) = RemoveMatchScopeInElem e : RemoveMatchScope es
type SegsToBranch :: [Seg] -> BRANCH
type family SegsToBranch segs where
SegsToBranch sgs = Branch sgs
type MkListOfranches :: [[Seg]] -> [BRANCH]
type family MkListOfranches segsList where
MkListOfranches '[] = '[]
MkListOfranches (segs : t) = SegsToBranch segs : MkListOfranches t
type AddSubSeg :: SubSeg -> [Seg] -> [Seg]
type family AddSubSeg c ac where
AddSubSeg c '[] =
-- unreachable
TypeError (Text "AddSubSeg " :<>: ShowType c :<>: Text " to empty list")
AddSubSeg c ( '( mtScope, um, m, sib) : t) =
( '( mtScope, c : um, m, sib) : t)
type family ApplySubSegToSeg removed ss sg where
ApplySubSegToSeg Nothing ss h = h
ApplySubSegToSeg (Just '(k, um')) _ss '( mts, um, m, sib) =
'( mts, um', k : m, sib)
type ApplyClassToBranch :: SubSeg -> BRANCH -> BRANCH
type family ApplyClassToBranch subSeg sgs where
ApplyClassToBranch _ (Branch '[]) = Branch '[]
ApplyClassToBranch ss (Branch ( '( mts, um, m, sib) : t)) =
Branch
(ApplySubSegToSeg (RemoveElem '[] ss um) ss '( mts, um, m, sib) : t)
type ApplyClassToElem :: SubSeg -> [BRANCH]-> [BRANCH]
type family ApplyClassToElem c bs where
ApplyClassToElem _ '[] = '[]
ApplyClassToElem c (b : bs) = ApplyClassToBranch c b : ApplyClassToElem c bs
type ApplyClass :: [[Seg]] -> SubSeg -> [[BRANCH]] -> [[BRANCH]]
type family ApplyClass acs c eacs where
ApplyClass '[] _ '[] = '[]
ApplyClass acs _ '[] = '[MkListOfranches acs]
ApplyClass acs c (h : eacs) = ApplyClassToElem c h : ApplyClass acs c eacs
type ApplySubSegToBranch :: SubSeg -> [Seg] -> [Seg]
type family ApplySubSegToBranch subSeg sgs where
ApplySubSegToBranch _ '[] = '[]
ApplySubSegToBranch ss ( '( mts, um, m, sib) : t) =
(ApplySubSegToSeg
(RemoveElem '[] ss um)
ss
'( mts, um, m, sib) : t)
type family ApplySubSegToElem c bs where
ApplySubSegToElem _ '[] = '[]
ApplySubSegToElem c (b : bs) =
ApplySubSegToBranch c b : ApplySubSegToElem c bs
type ApplySubSegsToElem :: [SubSeg] -> [[Seg]] -> [[Seg]]
type family ApplySubSegsToElem ss bs where
ApplySubSegsToElem '[] bs = bs
ApplySubSegsToElem (h : t) bs = ApplySubSegsToElem t (ApplySubSegToElem h bs)