home readme diff tree note docs

0commit 23d6c65f9368d3c622a55a3068a6b2f1efa0c8d4
1Author: Mason Wright <mason@lakefox.net>
2Date:   Thu Jun 19 20:40:16 2025 -0600
3
4    Base parts added
5
6diff --git a/index.html b/index.html
7index e4e370d..3284123 100644
8--- a/index.html
9+++ b/index.html
10@@ -1,16 +1,20 @@
11+<!DOCTYPE html>
12 <html>
13+	<head>
14+<style>
15+	h1 {
16+		color: red;
17+	}
18+</style>
19+	</head>
20+	<body>
21 	<h1 id="<">
22-
23-<!-- asdjkasdhjklsahdjklsa -->
24-<!-- 	 
25-	<b></b>
26--->
27-<!-- -->
28-<!---->
29+		Hello world
30 	</h1>
31 	<br />
32 	<input type="text"/>
33 	<p id="test">
34 		this is a test
35 	</p>
36+	</body>
37 </html>
38diff --git a/main b/main
39index 06056be..6f01d7a 100755
40Binary files a/main and b/main differ
41diff --git a/main.cc b/main.cc
42index 135fb3a..f51d773 100755
43--- a/main.cc
44+++ b/main.cc
45@@ -5,27 +5,34 @@
46 #include "parser.h" 
47 
48 int main() {
49-    // Option 1: Parse from a file
50-    std::ifstream inputFile("./index.html");
51-    if (!inputFile.is_open()) {
52-        std::cerr << "Error: Could not open index.html" << std::endl;
53-        return 1;
54-    }
55+    // // Option 1: Parse from a file
56+    // std::ifstream inputFile("./index.html");
57+    // if (!inputFile.is_open()) {
58+    //     std::cerr << "Error: Could not open index.html" << std::endl;
59+    //     return 1;
60+    // }
61+    //
62+    // std::unique_ptr<Node> document = parseStream(inputFile);
63+    // inputFile.close(); // Close the file after parsing
64+    //
65+    // // Option 2: Parse from a string (for testing)
66+    // // std::string html_content = "<div>Hello <b>world</b>!</div><p>Another paragraph.</p>";
67+    // // std::stringstream ss(html_content);
68+    // // std::unique_ptr<Node> document = parseStream(ss);
69+    //
70+    // // Print the parsed document tree
71+    // if (document) {
72+    //     document->print();
73+    // } else {
74+    //     std::cout << "Document parsing failed or resulted in an empty document." << std::endl;
75+    // }
76 
77-    std::unique_ptr<Node> document = parseStream(inputFile);
78-    inputFile.close(); // Close the file after parsing
79+	
80+	std::ifstream inputFile("./style.css");
81 
82-    // Option 2: Parse from a string (for testing)
83-    // std::string html_content = "<div>Hello <b>world</b>!</div><p>Another paragraph.</p>";
84-    // std::stringstream ss(html_content);
85-    // std::unique_ptr<Node> document = parseStream(ss);
86+	parseCSS(inputFile);
87 
88-    // Print the parsed document tree
89-    if (document) {
90-        document->print();
91-    } else {
92-        std::cout << "Document parsing failed or resulted in an empty document." << std::endl;
93-    }
94+	inputFile.close();
95 
96-    return 0;
97+	return 0;
98 }
99diff --git a/src/element.cc b/src/element.cc
100index 157533f..5c7f76a 100755
101--- a/src/element.cc
102+++ b/src/element.cc
103@@ -164,3 +164,127 @@ void Node::print(int indent) const {
104     }
105     std::cout << "</" << getTagName() << ">" << std::endl;
106 }
107+
108+struct Style {
109+	std::unordered_map<std::string, std::string> properties;
110+	std::string selector;
111+	// Index of when it was added (for cascading)
112+	int index;
113+}
114+
115+// struct BaseParts {
116+// 	std::string tagName;
117+// 	std::string id;
118+// 	std::vector<std::string> classes;
119+// 	std::unordered_map<std::string, std::string> attributes;
120+// }
121+
122+class StyleHandler {
123+	private:
124+		// basemap: Maps baseparts to a index of the styles vector pointing to a Style object
125+		// because processing a CSS selector isn't trivial we want to make a short list of 
126+		// the styles that can possibly be a match so we aren't spending a lot of compute 
127+		// on a selector that applys to the wrong element. Todo this we take the right most part
128+		// of a selector (that is the part that targets the current element) and we do a few checks
129+		// like is the tagname the same, does it have that class, and do the id's match. If so that 
130+		// is a canidate and we run the full selector on it. That includes checking parents,children, 
131+		// or what ever else the selector needs to match.
132+		std::unordered_map<std::string, std::vector<size_t>> basemap;
133+		std::vector<Style> styles;
134+		int currentIndex = 0;
135+
136+
137+		std::vector<std::string> parseSelectorParts(std::string selector) {
138+			// we want to find the right most (right of a " " > ~ + ) selector
139+			// account for * for commas split the selector then for each parse right
140+			
141+			std::vector<std::string> parts;
142+			std::string word;
143+
144+			for (int s = 0; s < selector.length(); s++) {
145+				// Start parsing if we see a comma or the end of the selector
146+				if (selector[s] == ',' || s == selector.length()-1) {
147+					// Break the tag and add the right most parts to parts
148+					for (int i = word.length()-1; i > -1; i--) {
149+						if (
150+								word[i] == ' ' ||
151+								word[i] == '>' ||
152+								word[i] == '~' ||
153+								word[i] == '+' 
154+								) {
155+							word = word.substr(i+1);
156+							break;
157+						}
158+					}
159+
160+					// Now word contains the right most selection
161+					// we will extract the quick to verify parts from it
162+					// so we can build the basemap
163+					std::string part;
164+					for (auto w : word) {
165+						// if the current letter is a : that is either a psuedo element
166+						// or selector. We don't care about that part for this part
167+						if (w != ':') {
168+							// We don't care if the thing we are splitting is a id or class we just 
169+							// need them split up so we can use them as map keys
170+
171+							if (w == '#') {
172+								if (part != "") {
173+									parts.push_back(part);
174+									part = "";
175+								}
176+
177+							} else if (w == '.') {
178+								if (part != "") {
179+									parts.push_back(part);
180+									part = "";
181+								}
182+							} else if (w == '[' || w == ']') {
183+								if (part != "") {
184+									parts.push_back(part);
185+									part = "";
186+								}
187+								continue;
188+							}
189+
190+							part += w;
191+						} else {
192+							break;
193+						}
194+					}
195+
196+					if (part != "") {
197+						parts.push_back(part);
198+					}
199+				} else {
200+					word += selector[s];
201+				}
202+			}
203+
204+			std::vector<std::string> deduplicated;
205+
206+			for (int p1 = 0; p1 < parts.size(); p1++) {
207+				bool matches = false;
208+
209+				for (int p2 = p1+1; p2 < parts.size(); p2++) {
210+					if (parts[p1] == parts[p2]) {
211+						matches = true;
212+					}
213+				}
214+
215+				if (!matches) {
216+					deduplicated.push_back(parts[p1]);
217+				}
218+			}
219+
220+			return deduplicated;
221+		}
222+	public:
223+		void add(Style style) {
224+			styles.push_back(std::move(style));
225+			basemap[styles.back().selector] = styles.size() - 1; // Store the index
226+			// Give the properties a cascade index
227+			styles.back().index = currentIndex++;
228+		}
229+
230+}
231diff --git a/src/parser.cc b/src/parser.cc
232index 784fbdd..9017b6c 100644
233--- a/src/parser.cc
234+++ b/src/parser.cc
235@@ -222,12 +222,14 @@ std::unique_ptr<Node> parseStream(std::istream& inputStream) {
236 						} else {
237 							// Create a element and jump inside
238 							auto attrs = parseAttributes(token);
239-							currentNode = currentNode->createElement(attrs["tagName"]);
240-							for (auto const& pair : attrs) {
241-								// All attributes are stored as strings so we can just throw them in
242-								currentNode->setAttribute(pair.first, pair.second);
243+							// Don't add elements like <!DOCTYPE>
244+							if (attrs["tagName"][0] != '!') {
245+								currentNode = currentNode->createElement(attrs["tagName"]);
246+								for (auto const& pair : attrs) {
247+									// All attributes are stored as strings so we can just throw them in
248+									currentNode->setAttribute(pair.first, pair.second);
249+								}
250 							}
251-
252 						}
253 					}
254 				}
255diff --git a/style.css b/style.css
256new file mode 100644
257index 0000000..2e59320
258--- /dev/null
259+++ b/style.css
260@@ -0,0 +1,7 @@
261+h1 {
262+	color: red;
263+}
264+
265+h1 > #id {
266+	background: purple;
267+}