~alcinnz/haskell-stylist

16597996b170b910e57954ead3c9fc4602267955 — Adrian Cochrane 5 years ago df95162
Index style rules to quickly narrow down which ones match a given element.
2 files changed, 61 insertions(+), 2 deletions(-)

A src/Stylish/Style/Index.hs
M stylish-haskell.cabal
A src/Stylish/Style/Index.hs => src/Stylish/Style/Index.hs +59 -0
@@ 0,0 1,59 @@
module Stylish.Style.Index (
        StyleIndex
    ) where

-- TODO do performance tests to decide beside between strict/lazy.
import Data.HashMap.Strict
import Stylish.Parse

import Data.Hashable
import Data.Text (unpack)

data StyleIndex = StyleIndex {
    indexed :: HashMap SimpleSelector [StyleRule],
    unindexed :: [StyleRule]
}

styleIndex = StyleIndex {indexed = empty, unindexed = []}

lookup' :: SimpleSelector -> HashMap SimpleSelector [a] -> [a]
lookup' = lookupDefault []

instance StyleSheet StyleIndex where
    addRule self (StyleRule _ []) = self
    addRule self rule@(StyleRule selector _) = addRuleForSelector self rule $ simpleSelector selector

simpleSelector (Element s) = s
simpleSelector (Child _ s) = s
simpleSelector (Descendant _ s) = s
simpleSelector (Adjacent _ s) = s
simpleSelector (Sibling _ s) = s

addRuleForSelector self rule [] = self {unindexed = rule : unindexed self}
addRuleForSelector self rule selector = self {
        indexed = insert key (rule : lookup' key index) index
    } where
        key = selectorKey selector
        index = indexed self

selectorKey (tok@(Tag _) : _) = tok
selectorKey (tok@(Id _) : _) = tok
selectorKey (tok@(Class _) : _) = tok
selectorKey (Property prop _ : _) = Property prop Exists

-- Implement hashable for SimpleSelector here because it proved challenging to automatically derive it.
instance Hashable SimpleSelector where
    hashWithSalt seed (Tag tag) = seed `hashWithSalt` (0::Int) `hashWithSalt` unpack tag
    hashWithSalt seed (Id id) = seed `hashWithSalt` (1::Int) `hashWithSalt` unpack id
    hashWithSalt seed (Class class_) = seed `hashWithSalt` (2::Int) `hashWithSalt` unpack class_
    hashWithSalt seed (Property prop test) =
        seed `hashWithSalt` (3::Int) `hashWithSalt` unpack prop `hashWithSalt` test

instance Hashable PropertyTest where
    hashWithSalt seed Exists = seed `hashWithSalt` (0::Int)
    hashWithSalt seed (Equals val) = seed `hashWithSalt` (1::Int) `hashWithSalt` unpack val
    hashWithSalt seed (Suffix val) = seed `hashWithSalt` (2::Int) `hashWithSalt` unpack val
    hashWithSalt seed (Prefix val) = seed `hashWithSalt` (3::Int) `hashWithSalt` unpack val
    hashWithSalt seed (Substring val) = seed `hashWithSalt` (4::Int) `hashWithSalt` unpack val
    hashWithSalt seed (Include val) = seed `hashWithSalt` (5::Int) `hashWithSalt` unpack val
    hashWithSalt seed (Dash val) = seed `hashWithSalt` (6::Int) `hashWithSalt` unpack val

M stylish-haskell.cabal => stylish-haskell.cabal +2 -2
@@ 57,7 57,7 @@ library
  -- other-extensions:    
  
  -- Other library packages from which modules are imported.
  build-depends:       base >=4.9 && <4.10, css-syntax, text
  build-depends:       base >=4.9 && <4.10, css-syntax, text, unordered-containers, hashable
  
  -- Directories containing source files.
  hs-source-dirs:      src


@@ 71,4 71,4 @@ test-suite test-stylish
  type:     exitcode-stdio-1.0
  main-is:              Test.hs
  other-modules:        Stylish.Parse
  build-depends:       base >=4.9 && <4.10, css-syntax, text, hspec, QuickCheck
  build-depends:       base >=4.9 && <4.10, css-syntax, text, unordered-containers, hashable, hspec, QuickCheck