home
readme
diff
tree
note
docs
0commit b966b2a517365074e5c381dbdea05b3221dc0198
1Author: Mason Wright <mason@lakefox.net>
2Date: Sun Jul 6 20:33:11 2025 -0600
3
4 Testing hook
5
6diff --git a/notes b/notes
7new file mode 100644
8index 0000000..db68ba6
9--- /dev/null
10+++ b/notes
11@@ -0,0 +1,37 @@
12+ul > li::innerHTML {
13+// I think node templating would work the best, the parser is fast enough not to matter too much
14+// if I can't get the testSelector speed down, only use inline styles
15+ "<div class=\"li_internal_dot\"></div>{{$.innerHTML}}"
16+}
17+
18+.li_internal_dot {
19+ width: 10px;
20+ height: 10px;
21+ border-radius: 10px;
22+}
23+
24+
25+node.click()
26+ +
27+event handler
28+ +
29+class.toggle
30+ +
31+apply styles
32+ +
33+run templates
34+ +
35+compute rel position and size/color
36+ +
37+update adapter
38+
39+
40+or
41+
42+SELECT("ul > li::innerHTML") {
43+ WIDTH()
44+ HEIGHT()
45+ MARGIN_LEFT()
46+ BACKGROUND_COLOR()
47+ BACKGROUND_IMAGE()
48+}
49diff --git a/src/grim.cc b/src/grim.cc
50index 1bf4374..438e45d 100755
51--- a/src/grim.cc
52+++ b/src/grim.cc
53@@ -544,6 +544,12 @@ class StyleHandler {
54 }
55 };
56
57+
58+// Used for root node without a parent
59+const std::vector<std::unique_ptr<Node>> EMPTY_NODE_CHILDREN_VECTOR;
60+
61+// node: The node you are checking the selector against
62+// selector: output of parseSelector
63 bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
64 // By the time we get here, we know the right most selector some what matches
65 // so now if it is a compound selector we should see if the parent('s) some what match
66@@ -568,35 +574,48 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
67 std::string symbol;
68 bool symbolFound = false;
69
70+ // This is setup code for the rest of the process
71+ // parts is the part of the selector that applies to
72+ // the current node: If we had div > h1 we would get
73+ // "h1" and the div part would be stored in trimmed.
74+ // then the symbol we split at is symbol. See below
75 for (int i = selector[0].size()-1; i >= 0; i--) {
76 std::string part = selector[0][i];
77 if (symbolFound) {
78 trimmed.insert(trimmed.begin(), part);
79 } else {
80- if (part != ">" || part != " " || part != "+" || part != "~") {
81+ if (part != ">" && part != " " && part != "+" && part != "~") {
82 parts.insert(parts.begin(), part);
83 } else {
84 symbol = part;
85+ symbolFound = true;
86 }
87 }
88 }
89
90-
91 // Given our selector is: {{"div", ">", "h1"}}
92 // we should now have
93 // trimmed = {"div"}
94 // parts = {"h1"}
95 // symbol = ">"
96-
97-
98+
99 // matched is true here because the node matching logic
100 // returns if matched is false
101 bool matched = true;
102
103+ // Now we have prepped the selector, we need to get the
104+ // information for the node. We need to store them in variables
105+ // then loop through the parts to test them because at this
106+ // point we don't know what type of selector each part is.
107+ // Possibly in the future it could be reworked and we could
108+ // do the match detecting while adding. This would let us
109+ // return at the earliest possible part avoiding unnessisary
110+ // computing
111+
112 std::vector<std::string> nodeClasses;
113 size_t classLen = node->classList.length();
114 for (size_t i = 0; i < classLen; i++) {
115- nodeClasses.push_back("."+node->classList.item(i));
116+ nodeClasses.push_back(node->classList.item(i));
117 }
118
119
120@@ -605,15 +624,16 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
121
122 for (auto a : attributes) {
123 if (a.second != "") {
124- attrs.push_back("["+a.first+"=\""+a.second+"\"]");
125+ attrs.push_back(a.first+"=\""+a.second+"\"");
126 } else {
127
128- attrs.push_back("["+a.first+"]");
129+ attrs.push_back(a.first);
130 }
131 }
132
133 // Find the index of the child relative to it's parent
134- const auto& children = node->parent->children;
135+
136+ const std::vector<std::unique_ptr<Node>>& children = (node->parent != nullptr) ? node->parent->children : EMPTY_NODE_CHILDREN_VECTOR;
137 size_t childIndex = 0;
138 if (children.size() > 1) {
139 for (size_t i = 0; i < children.size(); i++) {
140@@ -625,15 +645,23 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
141 }
142 }
143
144+ // Add the auto pseudo classes like first-child/last-child
145+ if (childIndex == 0) {
146+ attrs.push_back("first-child");
147+ } else if (childIndex == children.size()-1) {
148+ attrs.push_back("last-child");
149+ }
150+
151
152 size_t i = 0;
153 for (auto p : parts) {
154- if (i == 0 && p[0] != '#' && p[0] != '.' && p[0] != '[') {
155+ if (i == 0 && p[0] != '#' && p[0] != '.' && p[0] != '[' && p[0] != ':') {
156 matched = node->getTagName() == p;
157 } else if (p[0] == '#') {
158 matched = "#"+node->getId() == p;
159 } else if (p[0] == '.') {
160 bool found = false;
161+ p.erase(0,1);
162 for (auto c : nodeClasses) {
163 if (p == c) {
164 found = true;
165@@ -647,6 +675,9 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
166 // without a ending ) to [name]:
167 // See tests/css_selector.cc for examples
168 bool found = false;
169+
170+ p.erase(0,1);
171+ p.erase(p.length()-1,1);
172 for (auto a : attrs) {
173 if (p == a) {
174 found = true;
175@@ -655,26 +686,41 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
176 }
177 matched = found;
178 } // !TODO: Need a case for : , this will run the :has... logic
179- else if (p[0] == ":") {
180- // This handles the relative pseudo classes
181- for :last-child and nth-child and the others we should get the position
182- of the node at the top. Then apply in attributes
183- // These will run through, parsing the inner part and recalling testSelector
184- // with it
185- if (p.starts_with(":has(")) {
186-
187- } else if (p.starts_with(":last-child")) {
188- } else if (p.starts_with(":first-child")) {
189-
190+ else if (p[0] == ':') {
191+ if (p.starts_with(":is(")) {
192+ std::string value = p.substr(4,p.length()-5);
193+ matched = testSelector(node, parseSelectorParts(value));
194 } else if (p.starts_with(":where(")) {
195- // where
196- } else if (p.starts_with(":is(")) {
197-
198+ // Per specification where and is differ in specificity only
199+ // however, grim does not support specificity
200+ // https://developer.mozilla.org/en-US/docs/Web/CSS/:is#difference_between_is_and_where
201+ std::string value = p.substr(7,p.length()-8);
202+ matched = testSelector(node, parseSelectorParts(value));
203 } else if (p.starts_with(":not(")) {
204- } else if (p.starts_with(":nth-child(")) {
205- } else if (p.starts_with("::before")) {
206- } else if (p.starts_with("::after")) {}
207-
208+ std::string value = p.substr(5,p.length()-6);
209+ // Just inverts the output of testSelector
210+ matched = !testSelector(node, parseSelectorParts(value));
211+ } else if (p.starts_with(":has(")) {
212+
213+ // We have to do a little work to get :has to work
214+ // once parse the inner parts of the selector,
215+ // we need to find what the selector is targeting
216+ std::string value = p.substr(5,p.length()-6);
217+ auto innerParts = parseSelectorParts(value);
218+ bool subMatch = false;
219+
220+ for (auto ip : innerParts) {
221+ // if the selector was :has(+ p, div, > video)
222+ // ip each comma seperated value like {"+", "p"}
223+ // these differ from how we parse the parts above
224+ // if the first item in a selector is not a +~> then
225+ // it is a decendent otherwise they are the same
226+ }
227+ }
228+ // If there are any pseudo elements we will just skip them
229+ // with the transformers being replaced with pseudo elements
230+ // we won't know all of them. Will need to have a function to strip
231+ // the element names
232 }
233
234 if (!matched) {
235@@ -692,9 +738,9 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
236 }
237
238 // The rest of the logic assumes the other selectors do not match until proven otherwise
239+
240 matched = false;
241-
242- if (node->parent != nullptr) {
243+ if (node->parent == nullptr) {
244 return false;
245 }
246
247@@ -710,37 +756,35 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
248 return false;
249 } else {
250 // In this selector we just need to get the direct sibling and test it
251- matched = testSelector(children[i-1].get(), {trimmed});
252+ matched = testSelector(children[childIndex-1].get(), {trimmed});
253 }
254 }
255 } else if (symbol == "~") {
256 // Subsequent-sibling combinator
257- const auto& children = node->parent->children;
258 if (children.size() > 1) {
259- for (size_t i = 0; i < children.size(); i++) {
260- Node* child_ptr = children[i].get();
261-
262- if (child_ptr == node) {
263+ for (size_t i = 0; i < childIndex; i++) {
264+ // We have to test every selector before the current element,
265+ // if any match then it matches
266+ matched = testSelector(children[i].get(), {trimmed});
267+ if (matched) {
268 break;
269- } else {
270- // We have to test every selector before the current element,
271- // if any match then it matches
272- matched = testSelector(children[i].get(), {trimmed});
273- if (matched) {
274- break;
275- }
276 }
277 }
278 }
279 } else if (symbol == " ") {
280 // For the descendant combinator we have to check every parent until we match or nullptr out
281 Node* current = node->parent;
282- while (current != nullptr) {
283+ bool hasParent = true;
284+ while (hasParent) {
285 if (testSelector(current, {trimmed})) {
286 matched = true;
287 break;
288 }
289- current = current->parent;
290+ if (current->parent != nullptr) {
291+ current = current->parent;
292+ } else {
293+ hasParent = false;
294+ }
295 }
296 }
297