home readme diff tree note docs

0commit 4bf8aafceb0253987e505d015ad967383f72c51e
1Author: Mason Wright <mason@lakefox.net>
2Date:   Sat Jul 19 15:52:19 2025 -0600
3
4    Save
5
6diff --git a/Makefile b/Makefile
7index 99678fc..8433da7 100644
8--- a/Makefile
9+++ b/Makefile
10@@ -1,5 +1,5 @@
11 # --- Variables ---
12-CCFLAGS = -Wall -Wextra -std=c++23
13+CCFLAGS = -Wall -Wextra -std=c++23 -g
14 CC = clang++
15 
16 .PHONY: all clean run docs run_tests serve
17@@ -51,7 +51,7 @@ run:
18 	clear && ./main
19 
20 docs:
21-	cd docs/ && evoke build && cd ../../build && ./git.sh && ./tracker.sh
22+	cd docs/ && evoke build && cd ../../build  && ./tracker.sh
23 
24 serve:
25 	cd docs/dist && python3 -m http.server 8000
26diff --git a/docs/content/index.md b/docs/content/index.md
27index bad5562..cab4a27 100644
28--- a/docs/content/index.md
29+++ b/docs/content/index.md
30@@ -1 +1,31 @@
31 # Getting Started
32+
33+## Cloning
34+
35+```sh
36+git clone https://remote.grimui.com/grim.git
37+```
38+
39+
40+## Installing
41+
42+### Adding to a project
43+```sh
44+cd my_project/
45+git submodule add https://remote.grimui.com/grim.git
46+```
47+
48+### Including
49+```c++
50+#include "grim.h";
51+```
52+
53+```sh
54+clang++ -Igrim/include grim/build/grim.o
55+```
56+
57+### Make
58+```sh
59+cd grim
60+make all
61+```
62diff --git a/docs/partials/navbar.html b/docs/partials/navbar.html
63index 6d0fa47..666d5d0 100644
64--- a/docs/partials/navbar.html
65+++ b/docs/partials/navbar.html
66@@ -8,7 +8,7 @@
67 	<details open>
68 		<summary>Links</summary>
69 		<ul>
70-			<li><a href="https://git.grimui.com">Git</a></li>
71+			<li><a href="https://src.grimui.com">Source</a></li>
72 			<li><a href="https://tracker.grimui.com">Trackers</a></li>
73 		</ul>
74 	</details>
75diff --git a/include/grim.h b/include/grim.h
76index 744ffa5..09a4fcf 100644
77--- a/include/grim.h
78+++ b/include/grim.h
79@@ -12,6 +12,10 @@
80 #include <optional>
81 #include <stdexcept>
82 
83+// !TODO: At rules
84+// + Document object
85+// + templates
86+
87 class Attribute {
88 	private:
89 		std::string VALUE;
90@@ -131,6 +135,12 @@ class Node {
91 		std::string print(int indent = 0);
92 };
93 
94+class Document {
95+	public:
96+		Node* body;
97+		//location;
98+};
99+
100 std::vector<std::vector<std::string>> parseSelectorParts(std::string_view);
101 
102 bool testSelector(Node*, std::vector<std::vector<std::string>>);
103@@ -155,6 +165,22 @@ class StyleHandler {
104 		std::vector<Style> styles;
105 		
106 		std::vector<std::string> parseNodeParts(Node* node);
107+		/*
108+		// At rules: should be querable, these will apply over the getStyles if they apply
109+		// also overwrite the variables
110+		std::unordered_map<std::string, Style> rules;
111+
112+		// Map of all of the CSS varibles and system generated variables like (width, height)
113+		// to compute the @ rules. 
114+		std::unordered_map<std::string, std::string> variables;
115+
116+		Document* document;
117+
118+
119+		struct WindowState {
120+			// pull from the Document object
121+			double aspectRatio;
122+		};*/
123 
124 	public:
125 		void add(std::string selector, std::unordered_map<std::string, std::string> properties);
126diff --git a/src/parser.cc b/src/parser.cc
127index dfc5a68..3b5671c 100644
128--- a/src/parser.cc
129+++ b/src/parser.cc
130@@ -384,26 +384,54 @@ std::unique_ptr<StyleHandler> parseCSS(std::istream& inputStream) {
131 			std::string selector;
132 			for (size_t i = 0; i < stack.size(); i++) {
133 				bool firstChar = false;
134-				for (size_t j = 0; j < stack[i].selector.length(); j++) {
135-					char c = stack[i].selector[j];
136-					if (!std::isspace(c) && !firstChar) {
137-						if (c != '&') {
138-							selector.push_back(' ');
139-							selector.push_back(c);
140-						}
141-						
142-						firstChar = true;
143-					} else if (firstChar) {
144-						if (std::isspace(c)) { 
145-							if (j < stack[i].selector.length()-1 && !std::isspace(stack[i].selector[j+1])) {
146+
147+				// Here split the stack[i] by commas and run each one
148+
149+				std::string selectorBuffer;
150+				int depth = 0;
151+				for (size_t h = 0; h < stack[i].selector.length(); h++) {
152+					char ss = stack[i].selector[h];
153+
154+					// Handle comma's in () they need to be added to the selectorBuffer
155+					// but don't split the selector by them
156+					if (ss == '(') {
157+						depth++;
158+					} else if (ss == ')') {
159+						depth--;
160+					}
161+
162+					// Split the selector by comma's or at the end
163+					if ((ss == ',' || h == stack[i].selector.length()-1) && depth == 0) {
164+						for (size_t j = 0; j < selectorBuffer.length(); j++) {
165+						char c = selectorBuffer[j];
166+						if (!std::isspace(c) && !firstChar) {
167+							if (c != '&') {
168+								selector.push_back(' ');
169+								selector.push_back(c);
170+							}
171+
172+							firstChar = true;
173+						} else if (firstChar) {
174+							if (std::isspace(c)) { 
175+								if (j < selectorBuffer.length()-1 && !std::isspace(selectorBuffer[j+1])) {
176+									selector.push_back(c);
177+								}
178+							} else {
179 								selector.push_back(c);
180 							}
181-						} else {
182-							selector.push_back(c);
183 						}
184 					}
185+						selectorBuffer.clear();
186+					} else {
187+						selectorBuffer.push_back(ss);
188+					}
189+
190+					
191 				}
192+
193+
194 			}
195+
196 			handler->add(selector, current.props);
197 
198 			if (!stack.empty()) {
199diff --git a/tests/css_parser.cc b/tests/css_parser.cc
200index 9c4f37a..0a27e38 100644
201--- a/tests/css_parser.cc
202+++ b/tests/css_parser.cc
203@@ -237,6 +237,38 @@ html#nested {
204 	printSelector(handler->item(13).selector);
205 }
206 
207+TEST_CASE("parseCSS can parse multiple selectors nested") {
208+	 std::string cssContent = R"~~~(
209+div, .class1 {
210+	.class2 {
211+		background: red;
212+	}
213+	& .class3 {
214+		background: orange;
215+	}
216+}
217+)~~~";
218+
219+	std::istringstream inputFile(cssContent);	
220+
221+	std::unique_ptr<StyleHandler> handler = parseCSS(inputFile);
222+	SECTION("multi selector test") {
223+		compareStyle(".div .class2", {
224+				{"background", "red"}
225+				  }, 0, handler->item(0));
226+		compareStyle(".div.class3", {
227+				{"background", "orange"}
228+				  }, 1, handler->item(1));
229+		compareStyle(".class1 .class2", {
230+				{"background", "red"}
231+				  }, 2, handler->item(2));
232+		compareStyle(".class1.class3", {
233+				{"background", "orange"}
234+				  }, 3, handler->item(3));
235+	}
236+
237+}
238+
239 TEST_CASE("parseCSSInline can parse inline styles") {
240 	SECTION("parseCSSInline can parse a single property with a ending ;") {
241 		std::string inlineStyles = "background: yellow;";