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;";