home readme diff tree note docs

0commit 5c7ab985d8fc32ca0a47252da49377f12377d3e0
1Author: Mason Wright <mason@lakefox.net>
2Date:   Fri Aug 8 17:36:16 2025 -0600
3
4    Adding support of parsing of at-rules
5    
6    At rule & sheet type update
7
8diff --git a/.gitignore b/.gitignore
9old mode 100644
10new mode 100755
11diff --git a/Makefile b/Makefile
12old mode 100644
13new mode 100755
14index 0406c7f..29d253e
15--- a/Makefile
16+++ b/Makefile
17@@ -1,5 +1,5 @@
18 # --- Variables ---
19-CCFLAGS = -Wall -Wextra -std=c++23 -g
20+CCFLAGS = -Wall -Wextra -std=c++2b -g
21 CC = clang++
22 
23 .PHONY: all clean run docs serve
24@@ -54,7 +54,6 @@ MD_FILES := $(shell find docs/content -name "*.md")
25 HTML_FILES := $(MD_FILES:docs/content/%.md=docs/dist/%.html)
26 
27 docs: $(HTML_FILES)
28-	cd ../build  && ./tracker.sh
29 
30 # See 080f729 note for the template command
31 docs/dist/%.html: docs/content/%.md docs/components/navbar.html
32diff --git a/docs/components/navbar.html b/docs/components/navbar.html
33old mode 100644
34new mode 100755
35index 666d5d0..e9e6756
36--- a/docs/components/navbar.html
37+++ b/docs/components/navbar.html
38@@ -8,8 +8,7 @@
39 	<details open>
40 		<summary>Links</summary>
41 		<ul>
42-			<li><a href="https://src.grimui.com">Source</a></li>
43-			<li><a href="https://tracker.grimui.com">Trackers</a></li>
44+			<li><a href="sftp://share@grimui.com">Source</a></li>
45 		</ul>
46 	</details>
47 	<details open>
48diff --git a/docs/content/features/supported-css-selectors.md b/docs/content/features/supported-css-selectors.md
49old mode 100644
50new mode 100755
51index cda043a..4dc2a6b
52--- a/docs/content/features/supported-css-selectors.md
53+++ b/docs/content/features/supported-css-selectors.md
54@@ -108,10 +108,16 @@
55 | @counter-style ||||||
56 | @font-face ||||||
57 | @font-feature-values ||||||
58+| @swash | / |||| Subset of @font-feature-values |
59+| @annotation | / |||| Subset of @font-feature-values |
60+| @ornaments | / |||| Subset of @font-feature-values |
61+| @stylistic | / |||| Subset of @font-feature-values |
62+| @styleset | / |||| Subset of @font-feature-values |
63+| @character-varient | / |||| Subset of @font-feature-values |
64 | @font-palette-values ||||||
65-| @import ||||| <string> and <url> support only |
66+| @import ||||| Parsed where the first argument after @import is the url and the last non parenthesized value if present is the layer name. Inbetween the url and the layer is the media queries. |
67 | @keyframes ||||||
68-| @layer ||||||
69+| @layer ||||| Currently setting the layer order via @layer l1, l2; is not supported |
70 | @media ||||||
71 | @namespace ||||||
72 | @page | / |||| Will not be supported, currently there are no plans to support printing |
73diff --git a/docs/content/index.md b/docs/content/index.md
74old mode 100644
75new mode 100755
76diff --git a/docs/template.html b/docs/template.html
77old mode 100644
78new mode 100755
79index ad2b1b2..a9db999
80--- a/docs/template.html
81+++ b/docs/template.html
82@@ -9,7 +9,7 @@ body {
83 	margin-bottom: 100px;
84 }
85 table {
86-      width: 100%;
87+      width: 100%%;
88       border-collapse: collapse;
89 }
90 th,
91@@ -27,7 +27,7 @@ th {
92 		<main style="margin: 0 4rem 0 4rem">
93 			<div style="display: flex; gap: 1rem">
94 				%s
95-				<div style="width: 100%">
96+				<div style="width: 100%%">
97 					<section>%s</section>
98 				</div>
99 			</div>
100diff --git a/include/.grim.h.swp b/include/.grim.h.swp
101new file mode 100644
102index 0000000..6bd7da8
103Binary files /dev/null and b/include/.grim.h.swp differ
104diff --git a/include/catch_amalgamated.cpp b/include/catch_amalgamated.cpp
105old mode 100644
106new mode 100755
107diff --git a/include/catch_amalgamated.hpp b/include/catch_amalgamated.hpp
108old mode 100644
109new mode 100755
110diff --git a/include/grim.h b/include/grim.h
111old mode 100644
112new mode 100755
113index 93364ff..205ef5c
114--- a/include/grim.h
115+++ b/include/grim.h
116@@ -145,31 +145,40 @@ std::vector<std::vector<std::string>> parseSelectorParts(std::string_view);
117 
118 bool testSelector(Node*, std::vector<std::vector<std::string>>);
119 
120-struct Environment {
121-	int width;
122-	int height;
123-};
124-
125-struct Style {
126-	std::unordered_map<std::string, std::string> properties;
127-	std::vector<std::vector<std::string>> selector;
128-	size_t index;
129-};
130-
131-enum SheetType {
132-	LAYER,
133+enum class SheetType {
134 	CONTAINER,
135 	COUNTER,
136-	FONT,
137+	FONTFACE,
138+	FONTFEATURE,
139+	SWASH,
140+	ANNOTATION,
141+	ORNAMENTS,
142+	STYLISTIC,
143+	STYLESET,
144+	CHARACTERVARIANT,
145+	FONTPALETTEVALUES,
146 	IMPORT,
147+	KEYFRAMES,
148+	LAYER,
149 	NAMESPACE,
150 	PAGE,
151 	PROPERTY,
152-	STARTINGSTYLE
153+	ROOT,
154+	SHEET,
155+	MEDIA,
156+	STARTINGSTYLE,
157+	STYLE
158 };
159 
160-class StyleSheet {
161-	private:
162+// A sheet is a group of styles, layers can be nested for specifity and the order can be set via
163+// @layer order...;
164+// all style sheets are parsed into ROOT layers
165+// the non-layer styles will be placed inside of "styles" and they take priority over the layers
166+// all at rules are placed inside of "children"
167+// defining the order of the layers only effects the children with the type layer
168+// the rest are defined in the order they are parsed
169+class Sheet {
170+	public:
171 		// basemap: Maps baseparts to a index of the styles vector pointing to a Style object
172 		// because processing a CSS selector isn't trivial we want to make a short list of 
173 		// the styles that can possibly be a match so we aren't spending a lot of compute 
174@@ -179,175 +188,165 @@ class StyleSheet {
175 		// is a candidate and we run the full selector on it. That includes checking parents,children, 
176 		// or what ever else the selector needs to match.
177 		std::unordered_map<std::string, std::vector<size_t>> basemap;
178-		std::vector<Style> styles;
179 
180-	public:
181 		std::string name;
182 		std::string path;
183-		query query;
184-		SheetType type;
185+		std::vector<std::vector<std::string>> selector;
186+		std::unordered_map<std::string, std::string> properties;
187 
188+		SheetType type;
189+		std::unordered_map<std::string, std::string> variables;
190 
191-		void add(std::string selector, std::unordered_map<std::string, std::string> properties);
192+		Sheet* parent;
193+		std::vector<Sheet> children;
194 };
195 
196-struct AtRule {
197-	std::string identifier;
198-	std::string rule;
199-	// How to capture the data inside a block?
200-	// it could be anything that can be in a style sheet
201-	// basically need to parse a @rule like a seperate stylesheet
202-	// then merge when a condition is meant if its applicable
203-	//
204-	// if linked a shared document pointer then each should be able to 
205-	// report if applies. the main one should be the same as the rest
206-	
207-	// this will be a circular reference kinda
208-	StyleSheet styleSheet;
209-};
210+class Window;
211 
212 class StyleHandler {
213 	private:
214-				
215+
216 		std::vector<std::string> parseNodeParts(Node* node);
217-		/*
218-		// At rules: should be querable, these will apply over the getStyles if they apply
219-		// also overwrite the variables
220-		std::unordered_map<std::string, Style> rules;
221 
222-		// Map of all of the CSS varibles and system generated variables like (width, height)
223 		// to compute the @ rules. 
224 		std::unordered_map<std::string, std::string> variables;
225 
226-		Document* document;
227-
228-
229-		struct WindowState {
230-			// pull from the Document object
231-			double aspectRatio;
232-		};*/
233+		Window* window;
234 
235 	public:
236-		
237-		
238-		std::unordered_map<std::string, std::string> getStyles(Node* node);
239+		StyleHandler(Window* w): window(w) {}
240+		// Rules from the master.css file are direct styles of this object
241+		// all sheets are parsed as children of the ROOT
242+		Sheet root;
243 
244-		Style item(int index);
245+		std::unordered_map<std::string, std::string> getStyles(Node* node);
246 
247+		void parseStream(std::istream&); 
248 		// make a function that will return a list of attributes the will cause style changes if set
249 };
250 
251 enum class AnyHover {
252-    None,
253-    Hover
254+	None,
255+	Hover
256 };
257 
258 enum class AnyPointer {
259-    None,
260-    Fine,
261-    Coarse
262+	None,
263+	Fine,
264+	Coarse
265 };
266 
267 enum class Orientation {
268-    Landscape,
269-    Portrait
270+	Landscape,
271+	Portrait
272 };
273 
274 enum class ColorScheme {
275-    Light,
276-    Dark
277+	Light,
278+	Dark
279 };
280 
281 enum class Contrast {
282-    NoPreference,
283-    More,
284-    Less
285+	NoPreference,
286+	More,
287+	Less
288 };
289 
290 enum class ReducedMotion {
291-    NoPreference,
292-    Reduce
293+	NoPreference,
294+	Reduce
295 };
296 
297 enum class ReducedTransparency {
298-    NoPreference,
299-    Reduce
300+	NoPreference,
301+	Reduce
302 };
303 
304 enum class Update {
305-    Fast,
306-    Slow
307+	Fast,
308+	Slow
309 };
310 
311 class Window {
312-private:
313-    int width = 0;
314-    int height = 0;
315-    int resolution = 0;
316-    AnyHover anyHover = AnyHover::Hover;
317-    AnyPointer anyPointer = AnyPointer::Fine;
318-    Orientation orientation = Orientation::Landscape;
319-    ColorScheme colorScheme = ColorScheme::Light;
320-    Contrast contrast = Contrast::NoPreference;
321-    ReducedMotion reducedMotion = ReducedMotion::NoPreference;
322-    ReducedTransparency reducedTransparency = ReducedTransparency::NoPreference;
323-    Update update = Update::Fast;
324-
325-public:
326-    void setWidth(int value) {
327-        width = value;
328-    }
329-    void setHeight(int value) {
330-        height = value;
331-    }
332-    void setResolution(int value) {
333-        resolution = value;
334-    }
335-
336-    void setMouse(AnyPointer pointer) {
337-        if (pointer == AnyPointer::None) {
338-            anyHover = AnyHover::None;
339-        } else {
340-            anyHover = AnyHover::Hover;
341-        }
342-        anyPointer = pointer;
343-    }
344-
345-    void setOrientation(Orientation value) {
346-        orientation = value;
347-    }
348-
349-    void setColorScheme(ColorScheme value) {
350-        colorScheme = value;
351-    }
352-
353-    void setContrast(Contrast value) {
354-        contrast = value;
355-    }
356-
357-    void setReducedMotion(ReducedMotion value) {
358-        reducedMotion = value;
359-    }
360-
361-    void setReducedTransparency(ReducedTransparency value) {
362-        reducedTransparency = value;
363-    }
364-
365-    void setUpdate(Update value) {
366-        update = value;
367-    }
368-
369-    // Getters
370-    int getWidth() const {
371-        return width;
372-    }
373-    int getHeight() const {
374-        return height;
375-    }
376-    double getAspectRatio() const {
377-        if (height == 0) return 0.0;
378-        return static_cast<double>(width) / height;
379-    }
380+	private:
381+		int width = 0;
382+		int height = 0;
383+		int resolution = 0;
384+		AnyHover anyHover = AnyHover::Hover;
385+		AnyPointer anyPointer = AnyPointer::Fine;
386+		Orientation orientation = Orientation::Landscape;
387+		ColorScheme colorScheme = ColorScheme::Light;
388+		Contrast contrast = Contrast::NoPreference;
389+		ReducedMotion reducedMotion = ReducedMotion::NoPreference;
390+		ReducedTransparency reducedTransparency = ReducedTransparency::NoPreference;
391+		Update update = Update::Fast;
392+
393+	public:
394+
395+		StyleHandler CSS;
396+
397+		Window(): CSS(this) {}
398+		// +---------------------------------------------------+
399+		// | (hldfk) Window Properties                         |
400+		// +---------------------------------------------------+
401+
402+		void setWidth(int value) {
403+			width = value;
404+		}
405+		void setHeight(int value) {
406+			height = value;
407+		}
408+		void setResolution(int value) {
409+			resolution = value;
410+		}
411+
412+		void setMouse(AnyPointer pointer) {
413+			if (pointer == AnyPointer::None) {
414+				anyHover = AnyHover::None;
415+			} else {
416+				anyHover = AnyHover::Hover;
417+			}
418+			anyPointer = pointer;
419+		}
420+
421+		void setOrientation(Orientation value) {
422+			orientation = value;
423+		}
424+
425+		void setColorScheme(ColorScheme value) {
426+			colorScheme = value;
427+		}
428+
429+		void setContrast(Contrast value) {
430+			contrast = value;
431+		}
432+
433+		void setReducedMotion(ReducedMotion value) {
434+			reducedMotion = value;
435+		}
436+
437+		void setReducedTransparency(ReducedTransparency value) {
438+			reducedTransparency = value;
439+		}
440+
441+		void setUpdate(Update value) {
442+			update = value;
443+		}
444+
445+		// Getters
446+		int getWidth() const {
447+			return width;
448+		}
449+		int getHeight() const {
450+			return height;
451+		}
452+		double getAspectRatio() const {
453+			if (height == 0) return 0.0;
454+			return static_cast<double>(width) / height;
455+		}
456+
457+		
458+
459 };
460 
461 #endif // NODE_H
462diff --git a/include/parser.h b/include/parser.h
463old mode 100644
464new mode 100755
465diff --git a/src/adapter.cc b/src/adapter.cc
466old mode 100644
467new mode 100755
468diff --git a/src/events.cc b/src/events.cc
469old mode 100644
470new mode 100755
471diff --git a/src/grim.cc b/src/grim.cc
472index 2988bcf..75aa4d3 100755
473--- a/src/grim.cc
474+++ b/src/grim.cc
475@@ -15,6 +15,7 @@
476 // |(TOC) Table of contents                               |
477 // +------------------------------------------------------+
478 // |(p98ym) Utils                                         |
479+// | (hldfk) Document Parsing                             |
480 // |(tigfn) Attribute Handling                            |
481 // |(f98y0) ClassList                                     |
482 // |(lhujn) StyleList                                     |
483@@ -62,6 +63,16 @@ void trimSpace(std::string& str) {
484         str.erase(0, first_non_space);
485     }
486 }
487+// +---------------------------------------------------+
488+// | (hldfk) Document Parsing                          |
489+// +---------------------------------------------------+
490+
491+// Node* CreateDocument(std::string path) {
492+	// Parse document
493+	// Pull links from head and get stylesheets
494+	// parse css (pass window to precalculate all of the values)
495+// }
496+
497 
498 // +---------------------------------------------------+
499 // | (tigfn) Attribute Handling                        |
500@@ -222,8 +233,8 @@ void Node::ClassList::remove(std::string value) {
501 		if (newLen == pair.second) {
502 			if (classes.substr(pair.first, pair.second) == value) {
503 				// Splice out the value to be removed 
504-				// !ISSUE: This will keep the surounding spaces and cause the size to grow when 
505-				// + classes are added and removed
506+				// ISSUE: This will keep the surounding spaces and cause the size to grow when 
507+				// classes are added and removed
508 				self->attributes["class"] = classes.substr(0, pair.first)+classes.substr(pair.first+pair.second);
509 			}
510 		}
511@@ -509,7 +520,7 @@ std::string Node::print(int indent) {
512 // parseSelectorParts deconstructs a selector into its indiviual parts
513 // so they can be store and used in things like finding styles for basemap
514 // and comparing a node to a selector in testSelector. This is a higher level function
515-// that should be ran once perselector and the results saved somewhere due to
516+// that should be ran once parselector and the results saved somewhere due to
517 // the high cost to run the function
518 
519 std::vector<std::vector<std::string>> parseSelectorParts(std::string_view selector) {
520@@ -672,13 +683,21 @@ std::vector<std::string> StyleHandler::parseNodeParts(Node* node) {
521 	return parts;
522 }
523 
524-void StyleHandler::add(std::string selector, std::unordered_map<std::string, std::string> properties) {
525+/*
526+void Sheet::add(std::string selector, std::unordered_map<std::string, std::string> properties) {
527 	// Type is 2d vector of selector parts
528 
529 	auto parts = parseSelectorParts(selector);
530+
531+	for (auto pr : parts) {
532+		for (auto p : pr) {
533+			std::cout << p << std::endl;
534+		}
535+	}
536+
537 	size_t index = styles.size();
538 
539-	styles.push_back({properties,parts,index});
540+	styles.push_back({parts,properties});
541 
542 	// Get the last selector group from the parsed selector parts
543 	// because that is the selector that applies to an element
544@@ -693,7 +712,9 @@ void StyleHandler::add(std::string selector, std::unordered_map<std::string, std
545 		}
546 	}
547 }
548-		
549+*/
550+
551+/*
552 std::unordered_map<std::string, std::string> StyleHandler::getStyles(Node* node) {
553 	// TODO: Will need to change getStyles to first consider if the style sheet applies
554 	// then to check the selectors
555@@ -757,6 +778,7 @@ std::unordered_map<std::string, std::string> StyleHandler::getStyles(Node* node)
556 Style StyleHandler::item(int index) {
557 	return styles[index];
558 }
559+*/
560 
561 // Used for root node without a parent
562 const std::vector<std::unique_ptr<Node>> EMPTY_NODE_CHILDREN_VECTOR;
563diff --git a/src/parser.cc b/src/parser.cc
564old mode 100644
565new mode 100755
566index c85915a..f819dcb
567--- a/src/parser.cc
568+++ b/src/parser.cc
569@@ -310,7 +310,7 @@ std::unique_ptr<Node> parseHTML(std::istream& inputStream) {
570 				}
571 			}
572 
573-			// !TODO: Add a vector that stores inner text and when elements start to close out pop them but add all to their innerText
574+			// TODO: Add a vector that stores inner text and when elements start to close out pop them but add all to their innerText
575 			// + Will need something simular for innerHTML
576 			if (hasText) {
577 				auto node = currentNode->createElement("text");
578@@ -335,88 +335,14 @@ std::unique_ptr<Node> parseHTML(std::istream& inputStream) {
579 	return root;
580 }
581 
582-struct SelectorAndProps {
583-	std::string selector;
584-	std::unordered_map<std::string, std::string> props;
585-};
586-
587-std::vector<std::string> genSelectorStrings(std::string prefix, const std::vector<SelectorAndProps>& stack) {
588-	std::vector<std::string> selectors;
589-
590-	std::string buffer;
591-	bool inParens = false;
592-	size_t len = stack[0].selector.length();
593-	for (size_t i = 0; i < len; i++) {
594-		char c = stack[0].selector[i];
595-		if (c == '(') {
596-			inParens = true;
597-		}
598-		if (c == ')') {
599-			inParens = false;
600-		}
601-		if ((c == ',' && !inParens) || i == len-1) {
602-			if (i == len-1 && c != ',') {
603-				buffer.push_back(c);
604-			}
605-			std::vector<std::string> s;
606-
607-			if (stack.size() > 1) {
608-				std::vector<SelectorAndProps> temp(stack.begin()+1, stack.end());
609-				size_t lastChar = buffer.length()-1;
610-				for (size_t k = buffer.length()-1; k >= 0; k--) {
611-					if (!std::isspace(buffer[k])) {
612-						lastChar = k+1;
613-						break;
614-					}
615-				}
616-				s = genSelectorStrings(buffer.substr(0, lastChar), temp);
617-			} else {
618-				s.push_back(buffer);
619-			}
620-
621-			for (size_t j = 0; j < s.size(); j++) {
622-				std::string temp;
623-				bool hasAmp = false;
624-				for (size_t k = 0; k < s[j].length(); k++) {
625-					char c = s[j][k];
626-					if (c == '&') {
627-						hasAmp = true;
628-						for (auto p : prefix) {
629-							temp.push_back(p);
630-						}
631-					} else {
632-						temp.push_back(c);
633-					}
634-				}
635-				// Remove trailing space
636-				size_t lastChar = temp.length() - 1;
637-				for (size_t k = temp.length()-1; k >= 0; k--) {
638-					if (!std::isspace(temp[k])) {
639-						lastChar = k+1;
640-						break;
641-					}
642-				}
643-				if (!hasAmp) {
644-					selectors.push_back(prefix+" "+temp.substr(0,lastChar));
645-				} else {
646-					selectors.push_back(temp.substr(0,lastChar));
647-				}
648-			}
649-			buffer.clear();
650-
651-		} else {
652-			buffer.push_back(c);
653-		}
654-	}
655-	return selectors;
656-}
657-
658-std::unique_ptr<StyleHandler> parseCSS(std::istream& inputStream) {
659+void StyleHandler::parseStream(std::istream& inputStream) {
660 	// nowhitespace: value(can have whitespace); = property
661 	// a selector name is anything before a { up to a ; or a }
662-	std::unique_ptr<StyleHandler> handler = std::make_unique<StyleHandler>();
663-	std::vector<SelectorAndProps> stack;
664-	SelectorAndProps current;
665+	Sheet* root = &window->CSS.root;
666+	
667+	Sheet* current = root;
668+	// how to handle @import
669+
670 	std::string buffer;
671 
672 	bool incomment = false;
673@@ -439,58 +365,143 @@ std::unique_ptr<StyleHandler> parseCSS(std::istream& inputStream) {
674 
675 
676 		if (ch == '{') {
677-			// start of a group of properties
678-			// need to parse the selector and add it to the stack
679-			current.selector = buffer;
680-			stack.push_back(current);
681-			current = SelectorAndProps();
682+			// Parse the selector into its parts
683+			std::vector<std::vector<std::string>> parts = parseSelectorParts(buffer);
684+
685+			// Find who the parent is
686+			Sheet newSheet;
687+			newSheet.parent = current;
688+			newSheet.selector = parts;
689+			current->children.push_back(newSheet);
690+
691+			current = &current->children.back();
692+
693+			// here we need to take the selector (buffer)
694+			// and find out what type it is. Also need to manage the nesting
695+			if (parts[0][0][0] == '@') {
696+				if (parts[0][0] == "@container") {
697+					current->type = SheetType::CONTAINER;
698+					bool hasName = false;
699+					if (parts[0].size() >= 3) {
700+						// @container not (width < 400px)
701+						if (parts[0][2] != "not") {
702+							// @container (width > 400px) or|and (height > 400px)
703+							if (parts[0].size() >= 5) {
704+								if (parts[0][5] != "and" || parts[0][5] != "or") {
705+									current->name = parts[0][2];
706+									hasName = true;
707+								}
708+							}
709+						}
710+					}
711+					// If a name is present then remove the name and tag from the selector
712+					// else just remove the @container
713+					if (hasName) {
714+						current->selector[0] = std::vector<std::string>(current->selector[0].begin() + 2, current->selector[0].end());
715+					} else {
716+
717+						current->selector[0] = std::vector<std::string>(current->selector[0].begin() + 1, current->selector[0].end());
718+					}
719+				} else if (parts[0][0] == "@counter-style") {
720+					current->name = parts[0][2];
721+					current->type = SheetType::COUNTER;
722+				} else if (parts[0][0] == "@font-face") {
723+					current->type = SheetType::FONTFACE;
724+				} else if (parts[0][0] == "@font-feature") {
725+					current->type = SheetType::FONTFEATURE;
726+				} else if (parts[0][0] == "@swash") {
727+					current->type = SheetType::SWASH;
728+				} else if (parts[0][0] == "@annotation") {
729+					current->type = SheetType::ANNOTATION;
730+				} else if (parts[0][0] == "@ornaments") {
731+					current->type = SheetType::ORNAMENTS;
732+				} else if (parts[0][0] == "@stylistic") {
733+					current->type = SheetType::STYLISTIC;
734+				} else if (parts[0][0] == "@styleset") {
735+					current->type = SheetType::STYLESET;
736+				} else if (parts[0][0] == "@character-varient") {
737+					current->type = SheetType::CHARACTERVARIANT;
738+				} else if (parts[0][0] == "@font-palette-values") {
739+					current->type = SheetType::FONTPALETTEVALUES;
740+					current->name = parts[0][2];
741+				} else if (parts[0][0] == "@keyframes") {
742+					current->type = SheetType::KEYFRAMES;
743+					current->name = parts[0][2];
744+				} else if (parts[0][0] == "@layer") {
745+					current->type = SheetType::LAYER;
746+				} else if (parts[0][0] == "@media") {
747+					current->type = SheetType::MEDIA;
748+				} else if (parts[0][0] == "@property") {
749+					current->type = SheetType::PROPERTY;
750+					current->name = parts[0][2];
751+				} else if (parts[0][0] == "@starting-style") {
752+					current->type = SheetType::STARTINGSTYLE;
753+				}
754+				// ISSUE: need to remove the leading at-rule and other data
755+			} else {
756+				// Rework this, should make a Style not a Sheet  
757+				current->type = SheetType::STYLE;
758+			}
759 			
760+
761 			buffer.clear();
762 		} else if (ch == '}') {
763-			// compile the selector and add to the handler
764-                        // This handles the nested selectors
765-			std::vector<std::string> selectors = genSelectorStrings("", stack);
766-
767-			for (auto s : selectors) {
768-				handler->add(s, current.props);
769+			if (current->parent != nullptr) {
770+				current = current->parent;
771 			}
772 
773-                        if (!stack.empty()) {
774-                                current = stack.back();
775-                                stack.pop_back();
776-                        } else {
777-                                current = SelectorAndProps();
778-                        }
779                         buffer.clear();
780 		} else if (ch == ';') {
781-			// end of a style property
782-			std::string key;
783-			std::string value;
784-			bool keyFound = false;
785-			for (size_t i = 0; i < buffer.length(); i++) {
786-				char c = buffer[i];
787-				if (!keyFound && c == ':') {
788-					keyFound = true;
789-				} else if (!std::isspace(c) && !keyFound) {
790-					key += c;
791-				} else if (keyFound  &&
792-						!(std::isspace(c) && i < buffer.length()-1 && std::isspace(buffer[i+1]))) {
793-					// if the key is found and the charactor isn't a ':'
794-					// 	also (if c is a space and the next c will be a space)
795-					// 	this is to auto trim duplicate spaces from the value
796-					value += c;
797-					
798+			if (buffer[0] == '@') {
799+				// Single line at-rule
800+				Sheet inlineRule;
801+				std::vector<std::vector<std::string>> parts = parseSelectorParts(buffer);
802+				inlineRule.selector = parts;
803+				
804+				if (parts[0][0] == "@import") {
805+					inlineRule.path = parts[0][2];
806+
807+					if (parts[0].size() > 3) {
808+						// See if the last word ends in )
809+						// if not then its the name of the layer
810+						if (parts[0].back().back() != ')') {
811+							inlineRule.name = parts[0].back();
812+						}
813+					}
814+
815+				} else if (parts[0][0] == "@layer") {
816+					// need to add speficity
817+
818+				}
819+
820+				current->children.push_back(inlineRule);
821+
822+			} else {
823+				// end of a style property
824+				std::string key;
825+				std::string value;
826+				bool keyFound = false;
827+				for (size_t i = 0; i < buffer.length(); i++) {
828+					char c = buffer[i];
829+					if (!keyFound && c == ':') {
830+						keyFound = true;
831+					} else if (!std::isspace(c) && !keyFound) {
832+						key += c;
833+					} else if (keyFound  && !(std::isspace(c) && i < buffer.length()-1 && std::isspace(buffer[i+1]))) {
834+						// if the key is found and the charactor isn't a ':'
835+						// 	also (if c is a space and the next c will be a space)
836+						// 	this is to auto trim duplicate spaces from the value
837+						value += c;
838+					}
839 				}
840-			}
841 
842-			current.props[key] = value;
843+				current->properties[key] = value;
844+			}
845 			buffer.clear();
846 		} else {
847 			buffer.push_back(ch);
848 		}
849 	}
850-
851-	return handler;
852 }
853 
854 std::unordered_map<std::string, std::string> parseCSSInline(std::string inlineStyles) {
855diff --git a/tests/css_parser.cc b/tests/css_parser.cc
856old mode 100644
857new mode 100755
858index 8470cc1..66bea3c
859--- a/tests/css_parser.cc
860+++ b/tests/css_parser.cc
861@@ -47,9 +47,8 @@ void trimSpace2(std::string& str) {
862         str.erase(0, first_non_space);
863     }
864 }
865-
866-void compareStyle(std::string selector, std::unordered_map<std::string, std::string> props, size_t index, Style style) {
867-	REQUIRE(style.index == index);
868+/*
869+void compareStyle(std::string selector, std::unordered_map<std::string, std::string> props, Style style) {
870 	std::vector<std::vector<std::string>> parts = parseSelectorParts(selector);
871 	INFO(selector); 
872 	INFO(printSelector( style.selector));
873@@ -73,7 +72,7 @@ void compareStyle(std::string selector, std::unordered_map<std::string, std::str
874 		REQUIRE(f == s);
875 	}
876 }
877-
878+*/
879 void compareInlineStyles(std::string style, std::unordered_map<std::string, std::string> targetProps) {
880 	std::unordered_map<std::string, std::string> props = parseCSSInline(style);
881 	
882@@ -147,30 +146,32 @@ html#nested {
883     transition-duration: 0.5s;
884   }
885 }
886-
887-@media not all and (hover: hover) {
888-  abbr::after {
889-    content: " (" attr(title) ")";
890-  }
891-}
892 )~~~";
893 
894 	std::istringstream inputFile(cssContent);	
895 
896-	std::unique_ptr<StyleHandler> handler = parseCSS(inputFile);
897-	SECTION("StyleHandler Benchmark") {
898+	Window window;
899+	window.CSS.parseStream(inputFile);
900+
901+	StyleHandler handler = window.CSS;
902+
903+	std::cout << handler.root.children.size() << std::endl;
904+
905+	/*SECTION("StyleHandler Benchmark") {
906 		BENCHMARK("master.css") {
907 			std::ifstream tempFile("./tests/master.css");
908 			return parseCSS(tempFile);
909 		};
910-	}
911+	}*/
912 
913+/*
914 	SECTION("parseCSS can parse simple CSS rules") {
915 		compareStyle("h1", {
916 				{"color", "red"}
917-				}, 0, handler->item(0));
918+				}, handler.root.styles[0]);
919 	}
920-
921+*/
922+/*
923 	SECTION("parseCSS can parse a CSS rule with a child combinator") {
924 		compareStyle("h1 > #id", {
925 				{"background", "purple"}
926@@ -234,8 +235,10 @@ html#nested {
927 				{"font-size", "10px"}
928 				  }, 9, handler->item(9));
929 	}
930+*/
931 }
932 
933+/*
934 TEST_CASE("parseCSS can parse multiple selectors nested") {
935 	 std::string cssContent = R"~~~(
936 div, .class1 {
937@@ -267,6 +270,8 @@ div, .class1 {
938 	}
939 
940 }
941+*/
942+
943 
944 TEST_CASE("parseCSSInline can parse inline styles") {
945 	SECTION("parseCSSInline can parse a single property with a ending ;") {
946@@ -300,4 +305,29 @@ TEST_CASE("parseCSSInline can parse inline styles") {
947 				});
948 	}
949 }
950-// !TODO: Figure out how to handle @ rules
951+
952+/*
953+TEST_CASE("parseCSS-at-rules") {
954+	std::string cssContent = R"~~~(
955+@container (width > 400px) {
956+  h2 {
957+    font-size: 1.5em;
958+  }
959+}
960+
961+// With an optional <container-name>
962+@container tall (height > 30rem) {
963+  p {
964+    line-height: 1.6;
965+  }
966+}
967+)~~~";
968+
969+	std::istringstream inputFile(cssContent);	
970+
971+	std::unique_ptr<StyleHandler> handler = parseCSS(inputFile);
972+	SECTION("parseCSS can parse @container") {
973+			REQUIRE(handler->item(1).name == "tall");
974+	}
975+}
976+*/
977diff --git a/tests/css_selector.cc b/tests/css_selector.cc
978old mode 100644
979new mode 100755
980diff --git a/tests/html_node.cc b/tests/html_node.cc
981old mode 100644
982new mode 100755
983diff --git a/tests/html_parser.cc b/tests/html_parser.cc
984old mode 100644
985new mode 100755
986diff --git a/tests/index.html b/tests/index.html
987old mode 100644
988new mode 100755
989diff --git a/tests/style.css b/tests/style.css
990old mode 100644
991new mode 100755