about summary refs log tree commit diff stats
path: root/src/css/selector.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2021-11-23 13:01:23 +0100
committerbptato <nincsnevem662@gmail.com>2021-11-23 13:01:23 +0100
commit30f3b5deb3be13683e73175f241600c028910eaa (patch)
tree8524e4451cbf7ef4f8850f9b74f9df8bfd839ac0 /src/css/selector.nim
parentff1b68086d699510dcdbea6051460926556bd401 (diff)
downloadchawan-30f3b5deb3be13683e73175f241600c028910eaa.tar.gz
Support CSS child combinators
Diffstat (limited to 'src/css/selector.nim')
-rw-r--r--src/css/selector.nim49
1 files changed, 32 insertions, 17 deletions
diff --git a/src/css/selector.nim b/src/css/selector.nim
index 97c7d695..8489f240 100644
--- a/src/css/selector.nim
+++ b/src/css/selector.nim
@@ -12,13 +12,13 @@ type
 
   QueryMode* = enum
     QUERY_TYPE, QUERY_CLASS, QUERY_ATTR, QUERY_DELIM, QUERY_VALUE,
-    QUERY_PSEUDO, QUERY_PSELEM, QUERY_COMBINATOR
+    QUERY_PSEUDO, QUERY_PSELEM, QUERY_DESC_COMBINATOR, QUERY_CHILD_COMBINATOR
 
   PseudoElem* = enum
     PSEUDO_NONE, PSEUDO_BEFORE, PSEUDO_AFTER
 
   CombinatorType* = enum
-    DESCENDANT_COMBINATOR
+    DESCENDANT_COMBINATOR, CHILD_COMBINATOR
 
   SelectorParser = object
     selectors: seq[SelectorList]
@@ -86,10 +86,8 @@ func getSpecificity(sel: Selector): int =
   of UNIVERSAL_SELECTOR:
     discard
   of COMBINATOR_SELECTOR:
-    case sel.ct
-    of DESCENDANT_COMBINATOR:
-      for child in sel.csels:
-        result += getSpecificity(child)
+    for child in sel.csels:
+      result += getSpecificity(child)
 
 func getSpecificity*(sels: SelectorList): int =
   for sel in sels.sels:
@@ -135,17 +133,31 @@ proc addSelectorList(state: var SelectorParser) =
     state.combinator = nil
   state.selectors.add(SelectorList())
 
+proc parseSelectorCombinator(state: var SelectorParser, ct: CombinatorType, csstoken: CSSToken) =
+  if csstoken.tokenType in {CSS_IDENT_TOKEN, CSS_HASH_TOKEN,
+                            CSS_COLON_TOKEN}:
+    if state.combinator != nil and state.combinator.ct != ct:
+      let nc = Selector(t: COMBINATOR_SELECTOR, ct: ct)
+      nc.csels.add(SelectorList())
+      nc.csels[^1].add(state.combinator)
+      state.combinator = nc
+
+    if state.combinator == nil:
+      state.combinator = Selector(t: COMBINATOR_SELECTOR, ct: ct)
+
+    state.combinator.csels.add(state.selectors[^1])
+    if state.combinator.csels[^1].len > 0:
+      state.combinator.csels.add(SelectorList())
+    state.selectors[^1] = SelectorList()
+    state.query = QUERY_TYPE
+
 proc parseSelectorToken(state: var SelectorParser, csstoken: CSSToken) =
-  if state.query == QUERY_COMBINATOR:
-    if csstoken.tokenType in {CSS_IDENT_TOKEN, CSS_HASH_TOKEN,
-                              CSS_COLON_TOKEN}:
-      if state.combinator == nil:
-        state.combinator = Selector(t: COMBINATOR_SELECTOR, ct: DESCENDANT_COMBINATOR)
-      state.combinator.csels.add(state.selectors[^1])
-      if state.combinator.csels[^1].len > 0:
-        state.combinator.csels.add(SelectorList())
-      state.selectors[^1] = SelectorList()
-      state.query = QUERY_TYPE
+  if state.query == QUERY_DESC_COMBINATOR:
+    state.parseSelectorCombinator(DESCENDANT_COMBINATOR, csstoken)
+  elif state.query == QUERY_CHILD_COMBINATOR:
+    if csstoken.tokenType == CSS_WHITESPACE_TOKEN:
+      return
+    state.parseSelectorCombinator(CHILD_COMBINATOR, csstoken)
 
   case csstoken.tokenType
   of CSS_IDENT_TOKEN:
@@ -163,6 +175,9 @@ proc parseSelectorToken(state: var SelectorParser, csstoken: CSSToken) =
   of CSS_DELIM_TOKEN:
     if csstoken.rvalue == Rune('.'):
       state.query = QUERY_CLASS
+    elif csstoken.rvalue == Rune('>'):
+      if state.selectors[^1].len > 0 or state.combinator != nil:
+        state.query = QUERY_CHILD_COMBINATOR
   of CSS_HASH_TOKEN:
     state.addSelector(Selector(t: ID_SELECTOR, id: $csstoken.value))
   of CSS_COMMA_TOKEN:
@@ -170,7 +185,7 @@ proc parseSelectorToken(state: var SelectorParser, csstoken: CSSToken) =
       state.addSelectorList()
   of CSS_WHITESPACE_TOKEN:
     if state.selectors[^1].len > 0 or state.combinator != nil:
-      state.query = QUERY_COMBINATOR
+      state.query = QUERY_DESC_COMBINATOR
   of CSS_COLON_TOKEN:
     if state.query == QUERY_PSEUDO:
       state.query = QUERY_PSELEM