~alcinnz/haskell-stylist

90cf1ea6e0d277a6dd30cc5f9599d43984068cc5 — Adrian Cochrane 4 years ago fcbba23
Substitute in counters for any CSS textual property, not just `content`.

Will be required by Rhapsode for navigational markers.
1 files changed, 29 insertions(+), 14 deletions(-)

M src/Data/CSS/Preprocessor/Text.hs
M src/Data/CSS/Preprocessor/Text.hs => src/Data/CSS/Preprocessor/Text.hs +29 -14
@@ 18,7 18,7 @@ type Counters = [(Text, Integer)]
-- | `PropertyParser` decorator that parses & lowers certain CSS properties to plain text.
data TextStyle p = TextStyle {
    inner :: p,
    content :: [Token],
    counterProps :: [(Text, [Token])],

    counterReset :: Counters,
    counterIncrement :: Counters,


@@ 31,7 31,7 @@ data TextStyle p = TextStyle {
instance PropertyParser p => PropertyParser (TextStyle p) where
    temp = TextStyle {
            inner = temp,
            content = [],
            counterProps = [],
            counterReset = [],
            counterIncrement = [],
            counterSet = [],


@@ 40,7 40,7 @@ instance PropertyParser p => PropertyParser (TextStyle p) where
        }
    inherit parent = TextStyle {
            inner = inherit $ inner parent,
            content = [],
            counterProps = [],
            counterReset = [],
            counterIncrement = [],
            counterSet = [],


@@ 48,14 48,13 @@ instance PropertyParser p => PropertyParser (TextStyle p) where
            newlineCollapse = newlineCollapse parent
        }

    shorthand self "content" value = shorthand (inner self) "content" $ removeCounters value
    shorthand _ key value
        | key `elem` ["counter-reset", "counter-increment", "counter-set"],
            Just _ <- parseCounters 0 value = [(key, value)]
    shorthand self "white-space" [Ident val]
        | val `elem` ["normal", "pre", "pre-wrap", "pre-line"] = [("white-space", [Ident val])]
        | otherwise = shorthand (inner self) "white-space" [Ident val]
    shorthand self key value = shorthand (inner self) key value
    shorthand self key value = shorthand (inner self) key $ removeCounters value

    longhand _ self "counter-reset" value = (\v -> self {counterReset = v}) <$> parseCounters 0 value
    longhand _ self "counter-increment" value = (\v -> self {counterIncrement = v}) <$> parseCounters 1 value


@@ 68,8 67,16 @@ instance PropertyParser p => PropertyParser (TextStyle p) where
    longhand p self "white-space" [Ident "pre-wrap"] = setWhiteSpace p self False False "normal"
    longhand p self "white-space" [Ident "pre-line"] = setWhiteSpace p self True False "normal"

    longhand _ self "content" value = Just $ self {content = value}
    longhand parent self key value = (\v -> self {inner = v}) <$> longhand (inner parent ) (inner self) key value
    -- Capture `content` properties & anything else using counter(s) functions.
    -- This is important in Rhapsode for the sake of navigational markers.
    longhand parent self key value
        | key == "content" || Function "counter" `elem` value || Function "counters" `elem` value =
            Just $ self { counterProps = insertList key value $ counterProps self }
        | otherwise = (\v -> self {inner = v}) <$> longhand (inner parent ) (inner self) key value

insertList :: Eq a => a -> b -> [(a, b)] -> [(a, b)]
insertList key value list | Nothing <- lookup key list = (key, value) : list
    | otherwise = [(k, if k == key then value else v) | (k, v) <- list]

removeCounters :: [Token] -> [Token]
removeCounters (Function "counter":Ident _:RightParen:toks) = String "" : removeCounters toks


@@ 96,9 103,9 @@ parseCounters _ _ = Nothing
resolve :: PropertyParser p => StyleTree (TextStyle p) -> StyleTree p
resolve = resolve' . collapseWS . applyCounters
resolve' :: PropertyParser p => StyleTree (TextStyle p) -> StyleTree p
resolve' = treeMap $ \TextStyle {inner = inner', content = content'} -> (
        fromMaybe inner' $ longhand temp inner' "content" content'
    )
resolve' = treeMap $ \TextStyle {inner = inner', counterProps = props} -> foldl resolveProp inner' props
resolveProp :: PropertyParser p => p -> (Text, [Token]) -> p
resolveProp sty (key, value) = sty `fromMaybe` longhand temp sty key value

--------
---- Counters


@@ 163,21 170,29 @@ applyCounters0 counterSource valueSource path node =
            instantiateCounters path (counterReset node) &
            incrementCounters path (counterIncrement node) &
            setCounters path (counterSet node)
    in (counters, node {content = renderCounters counters $ content node})
    in (counters, node {
        counterProps = [(k, renderCounters counters v) | (k, v) <- counterProps node]
    })

--------
---- white-space
--------
content :: TextStyle p -> [Token]
content = fromMaybe [] . lookup "content" . counterProps
setContent :: [Token] -> TextStyle p -> TextStyle p
setContent value self = self {
        counterProps = [(k, if k == "content" then value else v) | (k, v) <- counterProps self]
    }

collapseWS :: StyleTree (TextStyle p) -> StyleTree (TextStyle p)
collapseWS = treeOrder collapseWS0 True
collapseWS0 :: Bool -> Bool -> Path -> TextStyle p -> (Bool, TextStyle p)
collapseWS0 _ _ _ node@(TextStyle {whiteSpaceCollapse = False, newlineCollapse = False}) = (False, node)
collapseWS0 _ inSpace _ node@(TextStyle {
        content = content0,
        whiteSpaceCollapse = wsCollapse,
        newlineCollapse = nlCollapse
    }) = (trailingSpace, node {content = content'})
  where (trailingSpace, content') = collapseWSToks inSpace wsCollapse nlCollapse content0
    }) = (trailingSpace, setContent content' node)
  where (trailingSpace, content') = collapseWSToks inSpace wsCollapse nlCollapse $ content node

collapseWSToks :: Bool -> Bool -> Bool -> [Token] -> (Bool, [Token])
collapseWSToks stripStart wsCollapse nlCollapse (String txt:toks) =