home readme diff tree note docs

0commit 35fdc3dd912205c066700c3731d390b63ce31ba4
1Author: lakefox <mason@lakefox.net>
2Date:   Fri Jan 16 15:26:06 2026 -0700
3
4    var()
5
6diff --git a/include/grim.h b/include/grim.h
7index 7b1c532..19b86a2 100755
8--- a/include/grim.h
9+++ b/include/grim.h
10@@ -193,6 +193,7 @@ class Node {
11 		void setAttribute(const std::string& name, const std::string& value);
12 		void deleteAttribute(const std::string& name);
13 		std::string getAttribute(const std::string& name) const;
14+		bool hasAttribute(const std::string& name) const;
15 
16 		const std::unordered_map<std::string, std::string>& getAttributes() const;
17 		std::vector<std::string> getAttributeKeys();
18@@ -289,6 +290,15 @@ class IndexedMap {
19 			}
20 		}
21 
22+		bool contains(std::string key) {
23+			for (size_t i = 0; i < map.size(); i++) {
24+				if (map[i].first == key) {
25+					return true;
26+				}
27+			}
28+			return false;
29+		}
30+
31 		size_t index(std::string key) {
32 			for (size_t i = 0; i < map.size(); i++) {
33 				if (map[i].first == key) {
34@@ -320,7 +330,7 @@ class Style {
35 	public:
36 		std::unordered_map<std::string, std::vector<size_t>> basemap{};
37 
38-		std::string name;
39+		std::string name; // remove
40 		std::vector<std::vector<std::string>> selector{};
41 		
42 		std::unordered_map<KeyType, std::vector<Unit>> properties{};
43diff --git a/playground/window.cc b/playground/window.cc
44index e8ec151..5d54e8c 100644
45--- a/playground/window.cc
46+++ b/playground/window.cc
47@@ -10,8 +10,8 @@ int main() {
48 			"<html width=\"\">"
49 				"<head>"
50 					"<title>This is a simple test</title>"
51-					"<link rel=\"stylesheet\" href=\'tests/style.css\'/>"
52-					"<style>h1 {background: red;}</style>"
53+					"<!--<link rel=\"stylesheet\" href=\'tests/style.css\'/>-->"
54+					"<style>:root {--test: 10px;} h1 {--test2: 10px; background: red;}</style>"
55 				"</head>"
56 				"<body>"
57 					"<h1 id=\"h1Tag\">Header</h1>"
58@@ -50,7 +50,7 @@ int main() {
59 
60 	document.children[0].cacheWidth(1000);
61 
62-	std::vector<Unit> units = getUnit(&window.CSS, "attr(width px, 10px)");
63+	std::vector<Unit> units = getUnit(&window.CSS, "var(--test)");
64 
65-	std::cout << UnitLengthValue(&document.children[0], &window.CSS, units, 0, units.size()) << std::endl;
66+	std::cout << UnitLengthValue(&document.children[0], &window.CSS.children[0], units, 0, units.size()) << std::endl;
67 }
68diff --git a/src/grim.cc b/src/grim.cc
69index e18d42c..bbd3df0 100755
70--- a/src/grim.cc
71+++ b/src/grim.cc
72@@ -13,6 +13,7 @@
73 #include <stdexcept>
74 #include <limits>
75 #include <cmath>
76+#include <string>
77 
78 // +------------------------------------------------------+
79 // |(TOC) Table of contents                               |
80@@ -135,6 +136,10 @@ std::string Node::getAttribute(const std::string& name) const {
81 	}
82 }
83 
84+bool Node::hasAttribute(const std::string& name) const {
85+    return attributes.contains(name) || DEFAULT_ATTRIBUTE_VALUES.contains(name);
86+}
87+
88 std::vector<std::string> Node::getAttributeKeys() {
89 	std::vector<std::string> keys;
90 
91@@ -725,6 +730,7 @@ std::vector<std::string> parseNodeParts(Node* node) {
92 	}
93 
94 	parts.push_back("*");
95+	parts.push_back(":root");
96 
97 	return parts;
98 }
99@@ -947,8 +953,6 @@ float UnitLengthValue(Node* n, Style* style, const std::vector<Unit>& units, siz
100 	float sum = 0;
101 	UnitType op = UnitType::ADD;
102 
103-	std::cout << "CALL START: " << start << " END: " << end << std::endl;
104-
105 	for (size_t i = start; i < end; i++) {
106 		Unit unit = units[i];
107 		UnitType type = unit.type;
108@@ -962,6 +966,7 @@ float UnitLengthValue(Node* n, Style* style, const std::vector<Unit>& units, siz
109 		std::vector<Range> extracted;
110 		UnitType ut;
111 		std::string s = "";
112+		bool b = false;
113 
114 		switch (type) {
115 			case UnitType::ADD:
116@@ -1297,9 +1302,10 @@ float UnitLengthValue(Node* n, Style* style, const std::vector<Unit>& units, siz
117 				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
118 
119 				if (units[extracted[0].start].type == UnitType::VAR) {
120+					b = n->hasAttribute(style->variables.key(units[extracted[0].start].value.INT));
121 					s = n->getAttribute(style->variables.key(units[extracted[0].start].value.INT));
122 
123-					if (!s.empty()) {
124+					if (!s.empty() && b) {
125 						// attr(size px, 10)
126 						// s = n->getAttribute(size) size="20"
127 						std::vector<Unit> us = getUnit(style, s);
128@@ -1317,11 +1323,44 @@ float UnitLengthValue(Node* n, Style* style, const std::vector<Unit>& units, siz
129 						value = UnitLengthValue(n, style, us, 0, us.size());
130 					} else if (extracted.size() == 3) {
131 						// Default value
132-						value = UnitLengthValue(n, style, units, extracted[2].start, extracted[2].end);
133+						value = UnitLengthValue(n, style, units, extracted[6].start, extracted[2].end);
134+					}
135+				}
136+
137+				i += unit.value.INT;
138+				break;
139+			case UnitType::VAR:
140+				extracted = extractUnits(units, i+1, i+1+unit.value.INT);
141+
142+				if (units[extracted[0].start].type == UnitType::VAR) {
143+					// Variables flow down during processing so theres no need to check above
144+					std::vector<Unit> us = style->variables.at(units[extracted[0].start].value.INT);
145+
146+					if (us.size() > 0) {
147+						value = UnitLengthValue(n, style, us, 0, us.size());
148+					} else if (extracted.size() == 2) {
149+						// Default value
150+						value = UnitLengthValue(n, style, units, extracted[1].start, extracted[1].end);
151 					}
152 				}
153 
154 				i += unit.value.INT;
155+				break;
156+
157+
158+
159+
160+
161+
162+
163+
164+												// Why not make this just get unit value and return a unit?
165+
166+
167+
168+
169+
170+
171 
172 			// Need to add variable injection and group handling
173 		}
174@@ -1344,7 +1383,6 @@ float UnitLengthValue(Node* n, Style* style, const std::vector<Unit>& units, siz
175 		}
176 	}
177 	
178-	std::cout << "SUM: " << sum << std::endl;
179 	return sum;
180 }
181 
182@@ -1524,11 +1562,9 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
183 		}
184 	}
185 
186-
187-
188 	size_t i = 0;
189-	for (auto p : parts) {
190-		if (p[0] == '*') {
191+	for (std::string p : parts) {
192+		if (p[0] == '*' || p == ":root") {
193 			matched = true;
194 		} else if (i == 0 && p[0] != '#' && p[0] != '.' &&  p[0] != '[' && p[0] != ':') {
195 			matched = tagName == p;
196@@ -1572,7 +1608,7 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
197 				matched = testSelector(node, next);
198 			} else if (p.starts_with(":where")) {
199 				// Per specification where and is differ in specificity only
200-				// however, grim does not support specificity
201+				// however, grim does not support specificity at this time
202 				// https://developer.mozilla.org/en-US/docs/Web/CSS/:is#difference_between_is_and_where
203 				matched = testSelector(node, next);
204 			} else if (p.starts_with(":not")) {
205diff --git a/src/parser.cc b/src/parser.cc
206index 8b51153..e5f027a 100755
207--- a/src/parser.cc
208+++ b/src/parser.cc
209@@ -97,7 +97,7 @@ std::unordered_map<std::string, std::string> parseAttributes(std::string_view to
210 			}
211 
212 			if (trimmedValue.length() == 0) {
213-				trimmedValue = "true";
214+				trimmedValue = "";
215 			}
216 
217 			attrs[trimmedName] = trimmedValue;