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