home readme diff tree note docs

0commit aa8ce6c35f8208ce6c30d19014935d7e5a91f04b
1Author: Mason Wright <mason@lakefox.net>
2Date:   Sat Oct 18 20:48:36 2025 -0600
3
4    Added all CSS types
5
6diff --git a/.swp b/.swp
7deleted file mode 100644
8index ced872d..0000000
9Binary files a/.swp and /dev/null differ
10diff --git a/docs/content/features/.supported-css-selectors.md.swp b/docs/content/features/.supported-css-selectors.md.swp
11deleted file mode 100644
12index b3fbabf..0000000
13Binary files a/docs/content/features/.supported-css-selectors.md.swp and /dev/null differ
14diff --git a/docs/manpage/grim.3 b/docs/manpage/grim.3
15new file mode 100644
16index 0000000..c942cc3
17--- /dev/null
18+++ b/docs/manpage/grim.3
19@@ -0,0 +1,110 @@
20+'\" t
21+.\" Copyright 2025 Mason Wright (mason@lakefox.net)
22+.\"
23+.\" SPDX-License-Identifier: Linux-man-pages-copyleft
24+.\"
25+.\" Modified Wed Oct 15 16:19 2025, Mason Wright
26+.\"
27+.TH grim 3 2025-10-15 "Linux man-pages 6.03"
28+.SH NAME
29+grim \- render HTML and CSS documents to a output source
30+.SH LIBRARY
31+Grim
32+.SH SYNOPSIS
33+.nf
34+.B #include <grim.h>
35+.PP
36+.BI "int abs(int " j );
37+.BI "long labs(long " j );
38+.BI "long long llabs(long long " j );
39+.PP
40+.B #include <inttypes.h>
41+.PP
42+.BI "intmax_t imaxabs(intmax_t " j );
43+.fi
44+.PP
45+.RS -3
46+Feature Test Macro Requirements for glibc (see
47+.BR feature_test_macros (7)):
48+.RE
49+.PP
50+.BR llabs ():
51+.nf
52+    _ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L
53+.fi
54+.SH DESCRIPTION
55+The
56+.BR grim
57+library takes HTML and CSS as a file, string, or virtual document then computes the styles and position for the page.
58+The output is draw to a canvas, this canvas can share memory with any output. Most commonly this will be to the compositor
59+of the system OS.
60+
61+Grim also includes DOM api's from the programming language "JavaScript". This provides a common interface to interact with the
62+document allowing dynamic updates and user events.
63+
64+.SH TABLE
65+.TS
66+tab(@) ;
67+l l l.
68+Header 1@Header 2@Header 3
69+Row 1 A@Row 1 B@Row 1 C
70+Row 2 A@Row 2 B@Row 2 C
71+.TE
72+
73+.SH RETURN VALUE
74+Returns the absolute value of the integer argument, of the appropriate
75+integer type for the function.
76+.SH ATTRIBUTES
77+For an explanation of the terms used in this section, see
78+.BR attributes (7).
79+.ad l
80+.nh
81+.TS
82+allbox;
83+lbx lb lb
84+l l l.
85+Interface	Attribute	Value
86+T{
87+.BR abs (),
88+.BR labs (),
89+.BR llabs (),
90+.BR imaxabs ()
91+T}	Thread safety	MT-Safe
92+.TE
93+.hy
94+.ad
95+.sp 1
96+.SH STANDARDS
97+POSIX.1-2001, POSIX.1-2008, C99, SVr4, 4.3BSD.
98+.SH NOTES
99+Trying to take the absolute value of the most negative integer
100+is not defined.
101+.PP
102+The
103+.BR llabs ()
104+function is included since glibc 2.0.
105+The
106+.BR imaxabs ()
107+function is included since glibc 2.1.1.
108+.PP
109+For
110+.BR llabs ()
111+to be declared, it may be necessary to define
112+\fB_ISOC99_SOURCE\fP or \fB_ISOC9X_SOURCE\fP (depending on the
113+version of glibc) before including any standard headers.
114+.PP
115+By default,
116+GCC handles
117+.BR abs (),
118+.BR labs (),
119+and (since GCC 3.0)
120+.BR llabs ()
121+and
122+.BR imaxabs ()
123+as built-in functions.
124+.SH SEE ALSO
125+.BR cabs (3),
126+.BR ceil (3),
127+.BR fabs (3),
128+.BR floor (3),
129+.BR rint (3)
130diff --git a/docs/manpage/grim.html b/docs/manpage/grim.html
131new file mode 100644
132index 0000000..e69de29
133diff --git a/include/grim.h b/include/grim.h
134index fe50ffb..64ee1c7 100755
135--- a/include/grim.h
136+++ b/include/grim.h
137@@ -149,12 +149,14 @@ enum class UnitType {
138 	// Operator 
139 		EQ, LT, GT, LE, GE, ADD, SUB, MULT, DIV,
140 	// Color
141-		HEX, RGB, RGBA, HSL, HSLA, HWB, COLOR,
142+		HEX, RGB, RGBA, HSL, HSLA, COLOR,
143 	// Logic
144 		AND, OR, NOT, ONLY, COMMA,
145 	// Length 
146 		PX, EM, PERCENT, CM, CAP, CH, EX, IC, LH, RCAP, RCH, REM, REX, RIC, RLH, VH, 
147 		VW, VMAX, VMIN, VB, VI, CQW, CQH, CQI, CQB, CQMIN, CQMAX, MM, Q, IN, PC, PT,
148+	// Diminsion
149+		KHZ, HZ, SECOND, MS, FRACTION,
150 	// Angle
151 		DEG, RAD, GRAD, TURN,
152 	// Non-unit numbers
153@@ -167,8 +169,48 @@ enum class UnitType {
154 		CONTENT_DISTRIBUTION, BETWEEN, AROUND, EVENLY, STRETCH,
155 	// Content-position
156 		CONTENT_POSITION, CENTER, START, FLEX_START, FLEX_END,
157+	// Display Box
158+		DISPLAY_BOX, CONTENTS, NONE,
159+	// Display Inside
160+		DISPLAY_INSIDE, FLOW, FLOW_ROOT, TABLE, FLEX, GRID, RUBY,
161+	// Display Internal
162+		DISPLAY_INTERNAL, TABLE_ROW_GROUP, TABLE_HEADER_GROUP, TABLE_FOOTER_GROUP, TABLE_COLUMN_GROUP,
163+		TABLE_ROW, TABLE_CELL, TABLE_COLUMN, TABLE_CAPTION, RUBY_BASE, RUBY_TEXT, RUBY_BASE_CONTAINER,
164+		RUBY_TEXT_CONTAINER,
165+	// Display Legacy
166+		DISPLAY_LEGACY, INLINE_BLOCK, INLINE_TABLE, INLINE_GRID, INLINE_FLEX,
167+	// Display List Item
168+		DISPLAY_LISTITEM, LISTITEM,
169+	// Display Outside
170+		DISPLAY_OUTSIDE, BLOCK, INLINE, RUN_IN,
171+	// Easing Functions
172+		EASING_FUNCTION, LINEAR_EASING_FUNCTION, LINEAR, EASE, EASE_IN, EASE_OUT, EASE_IN_OUT, CUBIC_BEZIER_FUNCTION, 
173+		STEP_START, STEP_END, STEPS_FUNCTION, JUMP_START, JUMP_END, JUMP_NONE, JUMP_BOTH, 
174 	// Function
175-		CALC, MIN,
176+		CALC, MIN, BLUR, BRIGHTNESS, CONTRAST, DROP_SHADOW, GRAYSCALE, HUE_ROTATE, INVERT, OPACITY, SEPIA, SATURATE,
177+	// Position
178+		POSITION, TOP, LEFT, BOTTOM, RIGHT, INLINE_START, INLINE_END, BLOCK_START, BLOCK_END, SELF_START, SELF_END, FLEX_START, FLEX_END,
179+	// Shape
180+		SHAPE, RADIAL_SHAPE, CIRCLE, ELLIPSE,
181+	// Generic Family
182+		GENERIC_FAMILY, SERIF, SANS_SERIF, MONOSPACE, CURSIVE, FANTASY, SYSTEM_UI, UI_SERIF, UI_SANS_SERIF, UI_MONOSPACE, 
183+		UI_ROUNDED, MATH, FANGSONG,
184+	// Hue Interpolation
185+		HUE_INTERPOLATION, SHORTER_HUE, LONGER_HUE, INCREASING_HUE, DECREASING_HUE,
186+		HUE,
187+	// Line Style
188+		LINE_STYLE, HIDDEN, DOTTED, DASHED, SOLID, DOUBLE, GROOVE, RIDGE, INSET, OUTSET,
189+	// Image
190+		IMAGE, URL, IMAGE_SET, CROSS_FADE, ELEMENT, GRADIENT,
191+	// Overflow Position
192+		OVERFLOW_POSITION, SAFE, UNSAFE,
193+	// Overflow
194+		OVERFLOW, VISIBLE, CLIP, SCROLL, AUTO, 
195+	// Transform Functions
196+		MATRIX,	MATRIX3D, PERSPECTIVE, ROTATE, ROTATE3D, ROTATEX, ROTATEY, ROTATEZ, SCALE, SCALE3D, SCALEX, SCALEY, SCALEZ, TRANSLATE, TRANSLATE3D, TRANSLATEX, TRANSLATEY, TRANSLATEZ, 
197+		SKEW, SKEWX, SKEWY,
198+	// URL
199+		URL,
200 	// Keyword
201 		PRINT, SCREEN, TOKEN, FUNC, OPERATOR, GROUP, END,
202 	// Property
203diff --git a/src/parser.cc b/src/parser.cc
204index 5a1429b..f29c1c2 100755
205--- a/src/parser.cc
206+++ b/src/parser.cc
207@@ -355,6 +355,174 @@ void typeCheck(std::string key, std::string value, Unit* property, std::vector<U
208 }
209 */
210 
211+static const std::unordered_map<std::string_view, unsigned int> kColors {
212+	{"black", 0x000000},
213+	{"silver", 0xc0c0c0},
214+	{"gray", 0x808080},
215+	{"white", 0xffffff},
216+	{"maroon", 0x800000},
217+	{"red", 0xff0000},
218+	{"purple", 0x800080},
219+	{"fuchsia", 0xff00ff},
220+	{"green", 0x008000},
221+	{"lime", 0x00ff00},
222+	{"olive", 0x808000},
223+	{"yellow", 0xffff00},
224+	{"navy", 0x000080},
225+	{"blue", 0x0000ff},
226+	{"teal", 0x008080},
227+	{"aqua", 0x00ffff},
228+	{"aliceblue", 0xf0f8ff},
229+	{"antiquewhite", 0xfaebd7},
230+	{"aqua", 0x00ffff},
231+	{"aquamarine", 0x7fffd4},
232+	{"azure", 0xf0ffff},
233+	{"beige", 0xf5f5dc},
234+	{"bisque", 0xffe4c4},
235+	{"black", 0x000000},
236+	{"blanchedalmond", 0xffebcd},
237+	{"blue", 0x0000ff},
238+	{"blueviolet", 0x8a2be2},
239+	{"brown", 0xa52a2a},
240+	{"burlywood", 0xdeb887},
241+	{"cadetblue", 0x5f9ea0},
242+	{"chartreuse", 0x7fff00},
243+	{"chocolate", 0xd2691e},
244+	{"coral", 0xff7f50},
245+	{"cornflowerblue", 0x6495ed},
246+	{"cornsilk", 0xfff8dc},
247+	{"crimson", 0xdc143c},
248+	{"cyan", 0x00ffff},
249+	{"darkblue", 0x00008b},
250+	{"darkcyan", 0x008b8b},
251+	{"darkgoldenrod", 0xb8860b},
252+	{"darkgray", 0xa9a9a9},
253+	{"darkgreen", 0x006400},
254+	{"darkgrey", 0xa9a9a9},
255+	{"darkkhaki", 0xbdb76b},
256+	{"darkmagenta", 0x8b008b},
257+	{"darkolivegreen", 0x556b2f},
258+	{"darkorange", 0xff8c00},
259+	{"darkorchid", 0x9932cc},
260+	{"darkred", 0x8b0000},
261+	{"darksalmon", 0xe9967a},
262+	{"darkseagreen", 0x8fbc8f},
263+	{"darkslateblue", 0x483d8b},
264+	{"darkslategray", 0x2f4f4f},
265+	{"darkslategrey", 0x2f4f4f},
266+	{"darkturquoise", 0x00ced1},
267+	{"darkviolet", 0x9400d3},
268+	{"deeppink", 0xff1493},
269+	{"deepskyblue", 0x00bfff},
270+	{"dimgray", 0x696969},
271+	{"dimgrey", 0x696969},
272+	{"dodgerblue", 0x1e90ff},
273+	{"firebrick", 0xb22222},
274+	{"floralwhite", 0xfffaf0},
275+	{"forestgreen", 0x228b22},
276+	{"fuchsia", 0xff00ff},
277+	{"gainsboro", 0xdcdcdc},
278+	{"ghostwhite", 0xf8f8ff},
279+	{"gold", 0xffd700},
280+	{"goldenrod", 0xdaa520},
281+	{"gray", 0x808080},
282+	{"green", 0x008000},
283+	{"greenyellow", 0xadff2f},
284+	{"grey", 0x808080},
285+	{"honeydew", 0xf0fff0},
286+	{"hotpink", 0xff69b4},
287+	{"indianred", 0xcd5c5c},
288+	{"indigo", 0x4b0082},
289+	{"ivory", 0xfffff0},
290+	{"khaki", 0xf0e68c},
291+	{"lavender", 0xe6e6fa},
292+	{"lavenderblush", 0xfff0f5},
293+	{"lawngreen", 0x7cfc00},
294+	{"lemonchiffon", 0xfffacd},
295+	{"lightblue", 0xadd8e6},
296+	{"lightcoral", 0xf08080},
297+	{"lightcyan", 0xe0ffff},
298+	{"lightgoldenrodyellow", 0xfafad2},
299+	{"lightgray", 0xd3d3d3},
300+	{"lightgreen", 0x90ee90},
301+	{"lightgrey", 0xd3d3d3},
302+	{"lightpink", 0xffb6c1},
303+	{"lightsalmon", 0xffa07a},
304+	{"lightseagreen", 0x20b2aa},
305+	{"lightskyblue", 0x87cefa},
306+	{"lightslategray", 0x778899},
307+	{"lightslategrey", 0x778899},
308+	{"lightsteelblue", 0xb0c4de},
309+	{"lightyellow", 0xffffe0},
310+	{"lime", 0x00ff00},
311+	{"limegreen", 0x32cd32},
312+	{"linen", 0xfaf0e6},
313+	{"magenta", 0xff00ff},
314+	{"maroon", 0x800000},
315+	{"mediumaquamarine", 0x66cdaa},
316+	{"mediumblue", 0x0000cd},
317+	{"mediumorchid", 0xba55d3},
318+	{"mediumpurple", 0x9370db},
319+	{"mediumseagreen", 0x3cb371},
320+	{"mediumslateblue", 0x7b68ee},
321+	{"mediumspringgreen", 0x00fa9a},
322+	{"mediumturquoise", 0x48d1cc},
323+	{"mediumvioletred", 0xc71585},
324+	{"midnightblue", 0x191970},
325+	{"mintcream", 0xf5fffa},
326+	{"mistyrose", 0xffe4e1},
327+	{"moccasin", 0xffe4b5},
328+	{"navajowhite", 0xffdead},
329+	{"navy", 0x000080},
330+	{"oldlace", 0xfdf5e6},
331+	{"olive", 0x808000},
332+	{"olivedrab", 0x6b8e23},
333+	{"orange", 0xffa500},
334+	{"orangered", 0xff4500},
335+	{"orchid", 0xda70d6},
336+	{"palegoldenrod", 0xeee8aa},
337+	{"palegreen", 0x98fb98},
338+	{"paleturquoise", 0xafeeee},
339+	{"palevioletred", 0xdb7093},
340+	{"papayawhip", 0xffefd5},
341+	{"peachpuff", 0xffdab9},
342+	{"peru", 0xcd853f},
343+	{"pink", 0xffc0cb},
344+	{"plum", 0xdda0dd},
345+	{"powderblue", 0xb0e0e6},
346+	{"purple", 0x800080},
347+	{"rebeccapurple", 0x663399},
348+	{"red", 0xff0000},
349+	{"rosybrown", 0xbc8f8f},
350+	{"royalblue", 0x4169e1},
351+	{"saddlebrown", 0x8b4513},
352+	{"salmon", 0xfa8072},
353+	{"sandybrown", 0xf4a460},
354+	{"seagreen", 0x2e8b57},
355+	{"seashell", 0xfff5ee},
356+	{"sienna", 0xa0522d},
357+	{"silver", 0xc0c0c0},
358+	{"skyblue", 0x87ceeb},
359+	{"slateblue", 0x6a5acd},
360+	{"slategray", 0x708090},
361+	{"slategrey", 0x708090},
362+	{"snow", 0xfffafa},
363+	{"springgreen", 0x00ff7f},
364+	{"steelblue", 0x4682b4},
365+	{"tan", 0xd2b48c},
366+	{"teal", 0x008080},
367+	{"thistle", 0xd8bfd8},
368+	{"tomato", 0xff6347},
369+	{"transparent", 0x00000000.},
370+	{"turquoise", 0x40e0d0},
371+	{"violet", 0xee82ee},
372+	{"wheat", 0xf5deb3},
373+	{"white", 0xffffff},
374+	{"whitesmoke", 0xf5f5f5},
375+	{"yellow", 0xffff00},
376+	{"yellowgreen", 0x9acd32},
377+};
378+
379 struct SuffixParse {
380 	std::string_view suffix;
381 	UnitType type;
382@@ -381,7 +549,17 @@ static constexpr SuffixParse table[] = {
383 	{"cqb",   UnitType::CQB,   3},
384 	{"deg",   UnitType::DEG,   3},
385 	{"rad",   UnitType::RAD,   3},
386+	{"khz",   UnitType::KHZ,   3},
387+	{"kHz",   UnitType::KHZ,   3},
388+	{"Khz",   UnitType::KHZ,   3},
389+	{"KHz",   UnitType::KHZ,   3},
390+	{"KHZ",   UnitType::KHZ,   3},
391 	{"px",    UnitType::PX,    2},
392+	{"hz",    UnitType::HZ,    2},
393+	{"Hz",    UnitType::HZ,    2},
394+	{"HZ",    UnitType::HZ,    2},
395+	{"hZ",    UnitType::HZ,    2},
396+	{"ms",    UnitType::MS,    2},
397 	{"em",    UnitType::EM,    2},
398 	{"cm",    UnitType::CM,    2},
399 	{"ch",    UnitType::CH,    2},
400@@ -396,8 +574,10 @@ static constexpr SuffixParse table[] = {
401 	{"in",    UnitType::IN,    2},
402 	{"pc",    UnitType::PC,    2},
403 	{"pt",    UnitType::PT,    2},
404+	{"fr",    UnitType::FRACTION,2},
405 	{"%",     UnitType::PERCENT,1},
406 	{"q",     UnitType::Q,     1},
407+	{"s",     UnitType::SECOND,1},
408 };
409 
410 static const std::unordered_map<std::string_view, std::pair<UnitType, UnitType>> kMatch{
411@@ -431,6 +611,154 @@ static const std::unordered_map<std::string_view, std::pair<UnitType, UnitType>>
412 	{"end",{UnitType::CONTENT_POSITION, UnitType::END}},
413 	{"flex-start",{UnitType::CONTENT_POSITION, UnitType::FLEX_START}},
414 	{"flex-end",{UnitType::CONTENT_POSITION, UnitType::FLEX_END}},
415+	{"contents",{UnitType::DISPLAY_BOX, UnitType::CONTENTS}},
416+	{"none",{UnitType::DISPLAY_BOX, UnitType::NONE}},
417+	{"flow",{UnitType::DISPLAY_INSIDE, UnitType::FLOW}},
418+	{"flow-root",{UnitType::DISPLAY_INSIDE, UnitType::FLOW_ROOT}},
419+	{"table",{UnitType::DISPLAY_INSIDE, UnitType::TABLE}},
420+	{"flex",{UnitType::DISPLAY_INSIDE, UnitType::FLEX}},
421+	{"grid",{UnitType::DISPLAY_INSIDE, UnitType::GRID}},
422+	{"ruby",{UnitType::DISPLAY_INSIDE, UnitType::RUBY}},
423+	{"table-row-group",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_ROW_GROUP}},
424+	{"table-header-group",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_HEADER_GROUP}},
425+	{"table-footer-group",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_FOOTER_GROUP}},
426+	{"table-column-group",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_COLUMN_GROUP}},
427+	{"table-row",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_ROW}},
428+	{"table-cell",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_CELL}},
429+	{"table-column",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_COLUMN}},
430+	{"table-caption",{UnitType::DISPLAY_INTERNAL, UnitType::TABLE_CAPTION}},
431+	{"ruby-base",{UnitType::DISPLAY_INTERNAL, UnitType::RUBY_BASE}},
432+	{"ruby-text",{UnitType::DISPLAY_INTERNAL, UnitType::RUBY_TEXT}},
433+	{"ruby-base-container",{UnitType::DISPLAY_INTERNAL, UnitType::RUBY_BASE_CONTAINER}},
434+	{"ruby-text-container",{UnitType::DISPLAY_INTERNAL, UnitType::RUBY_TEXT_CONTAINER}},
435+	{"inline-block",{UnitType::DISPLAY_LEGACY, UnitType::INLINE_BLOCK}},
436+	{"inline-table",{UnitType::DISPLAY_LEGACY, UnitType::INLINE_TABLE}},
437+	{"inline-flex",{UnitType::DISPLAY_LEGACY, UnitType::INLINE_FLEX}},
438+	{"inline-grid",{UnitType::DISPLAY_LEGACY, UnitType::INLINE_GRID}},
439+	{"list-item",{UnitType::DISPLAY_LISTITEM, UnitType::LISTITEM}},
440+	{"block",{UnitType::DISPLAY_OUTSIDE, UnitType::BLOCK}},
441+	{"inline",{UnitType::DISPLAY_OUTSIDE, UnitType::INLINE}},
442+	{"run-in",{UnitType::DISPLAY_OUTSIDE, UnitType::RUN_IN}},
443+	{"linear",{UnitType::EASING_FUNCTION, UnitType::LINEAR}},
444+	{"ease",{UnitType::EASING_FUNCTION, UnitType::EASE}},
445+	{"ease-in",{UnitType::EASING_FUNCTION, UnitType::EASE_IN}},
446+	{"ease-out",{UnitType::EASING_FUNCTION, UnitType::EASE_OUT}},
447+	{"ease-in-out",{UnitType::EASING_FUNCTION, UnitType::EASE_IN_OUT}},
448+	{"step-start",{UnitType::EASING_FUNCTION, UnitType::STEP_START}},
449+	{"step-end",{UnitType::EASING_FUNCTION, UnitType::STEP_END}},
450+	{"jump-start",{UnitType::EASING_FUNCTION, UnitType::JUMP_START}},
451+	{"jump-end",{UnitType::EASING_FUNCTION, UnitType::JUMP_END}},
452+	{"jump-none",{UnitType::EASING_FUNCTION, UnitType::JUMP_NONE}},
453+	{"jump-both",{UnitType::EASING_FUNCTION, UnitType::JUMP_BOTH}},
454+	{"serif",{UnitType::GENERIC_FAMILY, UnitType::SERIF}},
455+	{"sans-serif",{UnitType::GENERIC_FAMILY, UnitType::SANS_SERIF}},
456+	{"monospace",{UnitType::GENERIC_FAMILY, UnitType::MONOSPACE}},
457+	{"cursive",{UnitType::GENERIC_FAMILY, UnitType::CURSIVE}},
458+	{"fantasy",{UnitType::GENERIC_FAMILY, UnitType::FANTASY}},
459+	{"system-ui",{UnitType::GENERIC_FAMILY, UnitType::SYSTEM_UI}},
460+	{"ui-serif",{UnitType::GENERIC_FAMILY, UnitType::UI_SERIF}},
461+	{"ui-sans-serif",{UnitType::GENERIC_FAMILY, UnitType::UI_SANS_SERIF}},
462+	{"ui-monospace",{UnitType::GENERIC_FAMILY, UnitType::UI_MONOSPACE}},
463+	{"ui-rounded",{UnitType::GENERIC_FAMILY, UnitType::UI_ROUNDED}},
464+	{"math",{UnitType::GENERIC_FAMILY, UnitType::MATH}},
465+	{"fangsong",{UnitType::GENERIC_FAMILY, UnitType::FANGSONG}},
466+	{"top",{UnitType::POSITION, UnitType::TOP}},
467+	{"left",{UnitType::POSITION, UnitType::LEFT}},
468+	{"bottom",{UnitType::POSITION, UnitType::BOTTOM}},
469+	{"right",{UnitType::POSITION, UnitType::RIGHT}},
470+	{"center",{UnitType::POSITION, UnitType::CENTER}},
471+	{"inline-start",{UnitType::POSITION, UnitType::INLINE_START}},
472+	{"inline-end",{UnitType::POSITION, UnitType::INLINE_END}},
473+	{"block-start",{UnitType::POSITION, UnitType::BLOCK_START}},
474+	{"block-end",{UnitType::POSITION, UnitType::BLOCK_END}},
475+	{"self-start",{UnitType::POSITION, UnitType::SELF_START}},
476+	{"self-end",{UnitType::POSITION, UnitType::SELF_END}},
477+	{"flex-start",{UnitType::POSITION, UnitType::FLEX_START}},
478+	{"flex-end",{UnitType::POSITION, UnitType::FLEX_END}},
479+	{"circle",{UnitType::SHAPE, UnitType::CIRCLE}},
480+	{"ellipse",{UnitType::SHAPE, UnitType::ELLIPSE}},
481+	{"shorter hue",{UnitType::HUE_INTERPOLATION, UnitType::SHORTER_HUE}},
482+	{"longer hue",{UnitType::HUE_INTERPOLATION, UnitType::LONGER_HUE}},
483+	{"increasing hue",{UnitType::HUE_INTERPOLATION, UnitType::INCREASING_HUE}},
484+	{"decreasing hue",{UnitType::HUE_INTERPOLATION, UnitType::DECREASING_HUE}},
485+	{"hidden",{UnitType::LINE_STYLE, UnitType::HIDDEN}},
486+	{"dotted",{UnitType::LINE_STYLE, UnitType::DOTTED}},
487+	{"dashed",{UnitType::LINE_STYLE, UnitType::DASHED}},
488+	{"solid",{UnitType::LINE_STYLE, UnitType::SOLID}},
489+	{"double",{UnitType::LINE_STYLE, UnitType::DOUBLE}},
490+	{"groove",{UnitType::LINE_STYLE, UnitType::GROOVE}},
491+	{"ridge",{UnitType::LINE_STYLE, UnitType::RIDGE}},
492+	{"inset",{UnitType::LINE_STYLE, UnitType::INSET}},
493+	{"outset",{UnitType::LINE_STYLE, UnitType::OUTSET}},
494+	{"baseline",{UnitType::BASELINE, UnitType::FIRST}},
495+	{"first baseline",{UnitType::BASELINE, UnitType::FIRST}},
496+	{"last baseline",{UnitType::BASELINE, UnitType::LAST}},
497+	{"safe",{UnitType::OVERFLOW_POSITION, UnitType::SAFE}},
498+	{"unsafe",{UnitType::OVERFLOW_POSITION, UnitType::UNSAFE}},
499+	{"visible",{UnitType::OVERFLOW, UnitType::VISIBLE}},
500+	{"clip",{UnitType::OVERFLOW, UnitType::CLIP}},
501+	{"scroll",{UnitType::OVERFLOW, UnitType::SCROLL}},
502+	{"auto",{UnitType::OVERFLOW, UnitType::AUTO}},
503+};
504+
505+/*
506+	Note to self:
507+		make a kMap object that will map values that have conflicts like none
508+		In another function use the key to find the type
509+
510+		overflow: hidden
511+
512+		what to do about strings
513+*/
514+
515+static const std::unordered_map<std::string_view, UnitType> kFunc{
516+	{"calc", UnitType::CALC},
517+	{"min", UnitType::MIN},
518+	{"rgb", UnitType::RGB},
519+	{"rgba", UnitType::RGBA},
520+	{"hsl", UnitType::HSL},
521+	{"linear", UnitType::LINEAR_EASING_FUNCTION},
522+	{"cubic-bezier", UnitType::CUBIC_BEZIER_FUNCTION},
523+	{"steps", UnitType::STEPS_FUNCTION},
524+	{"blur", UnitType::BLUR},
525+	{"brightness", UnitType::BRIGHTNESS},
526+	{"contrast", UnitType::CONTRAST},
527+	{"drop-shadow", UnitType::DROP_SHADOW},
528+	{"grayscale", UnitType::GRAYSCALE},
529+	{"hue-rotate", UnitType::HUE_ROTATE},
530+	{"invert", UnitType::INVERT},
531+	{"opacity", UnitType::OPACITY},
532+	{"sepia", UnitType::SEPIA},
533+	{"saturate", UnitType::SATURATE},
534+	{"image", UnitType::IMAGE},
535+	{"image-set", UnitType::IMAGE_SET},
536+	{"cross-fade", UnitType::CROSS_FADE},
537+	{"element", UnitType::ELEMENT},
538+	{"gradient", UnitType::GRADIENT},
539+	{"matrix", UnitType::MATRIX},
540+	{"matrix3d", UnitType::MATRIX3D},
541+	{"perspective", UnitType::PERSPECTIVE},
542+	{"rotate", UnitType::ROTATE},
543+	{"rotate3d", UnitType::ROTATE3D},
544+	{"rotateX", UnitType::ROTATEX},
545+	{"rotateY", UnitType::ROTATEY},
546+	{"rotateZ", UnitType::ROTATEZ},
547+	{"scale", UnitType::SCALE},
548+	{"scale3d", UnitType::SCALE3D},
549+	{"scaleX", UnitType::SCALEX},
550+	{"scaleY", UnitType::SCALEY},
551+	{"scaleZ", UnitType::SCALEZ},
552+	{"translate", UnitType::TRANSLATE},
553+	{"translate3d", UnitType::TRANSLATE3D},
554+	{"translateX", UnitType::TRANSLATEX},
555+	{"translateY", UnitType::TRANSLATEY},
556+	{"translateZ", UnitType::TRANSLATEZ},
557+	{"skew", UnitType::SKEW},
558+	{"skewX", UnitType::SKEWX},
559+	{"skewY", UnitType::SKEWY},
560+	{"url", UnitType::URL},
561+
562+	{"", UnitType::GROUP}
563 };
564 
565 static const std::unordered_map<std::string_view, float> kAbsSize{
566@@ -470,6 +798,9 @@ std::vector<Unit> getUnit(std::string value) {
567 			buffer.push_back(v);
568 			continue;
569 		} else if (v == ')') {
570+			/*
571+				Function handling
572+			*/
573 			// We are at the end of the parentheseses and we need to pass it for more parsing
574 			std::string name;
575 			bool nameset = false;
576@@ -488,22 +819,11 @@ std::vector<Unit> getUnit(std::string value) {
577 			
578 			Unit unit;
579 
580-			if (name == "calc") {
581-				unit.type = UnitType::CALC;
582-			} else if (name == "min") {
583-				unit.type = UnitType::MIN;
584-			} else if (name == "rgb") {
585-				unit.type = UnitType::RGB;
586-			} else if (name == "rgba") {
587-				unit.type = UnitType::RGBA;
588-			} else if (name == "hsl") {
589-				unit.type = UnitType::HSL;
590-			} else if (name == "hwb") {
591-				unit.type = UnitType::HWB;
592-			} else if (name == "") {
593-				unit.type = UnitType::GROUP;
594+			if (auto it = kFunc.find(name); it != kFunc.end()) { 
595+				unit.type = it->second;
596 			}
597 
598+			// The value of the function is the child count
599 			unit.value.INT = children.size();
600 
601 			units.push_back(unit);
602@@ -520,9 +840,19 @@ std::vector<Unit> getUnit(std::string value) {
603 
604 			bool found = false;
605 			if (auto it = kMatch.find(buffer); it != kMatch.end()) { 
606+				/*
607+					Keyword Matching
608+				*/
609 				unit.type = it->second.first;
610 				unit.value.ENUM = it->second.second;
611 				found = true;
612+			} else if (auto it = kColor.find(buffer); it != kColor.end()) { 
613+				/*
614+					Color Matching
615+				*/
616+				unit.type = UnitType::HEX;
617+				unit.value.ENUM = it->second;
618+				found = true;
619 			} else {
620 				for (const auto& [suffix, type, trim] : table) {
621 					if (buffer.ends_with(suffix)) {
622@@ -536,19 +866,19 @@ std::vector<Unit> getUnit(std::string value) {
623 
624 			if (!found) {
625 				if (buffer.starts_with("#")) {
626+					/*
627+						# Prefix for HEX codes
628+					*/
629 					unit.type = UnitType::HEX;
630 					unit.value.UINT = std::stoul(buffer.substr(1), nullptr, 16);
631 					found = true;
632 				} else if (auto it = kAbsSize.find(buffer); it != kAbsSize.end()) { 
633+					/*
634+						Absolute size matching
635+					*/
636 					unit.type = UnitType::EM;
637 					unit.value.FLOAT = it->second;
638 					found = true;
639-				} else if (buffer.ends_with("baseline")) {
640-					unit.type = UnitType::BASELINE;
641-					if (buffer.starts_with("first")) unit.value.ENUM = UnitType::FIRST;
642-					else if (buffer.starts_with("last")) unit.value.ENUM = UnitType::LAST;
643-					else unit.value.ENUM = UnitType::FIRST;
644-					found = true;
645 				} else {
646 					// Maybe its a number?
647 					try {
648diff --git a/src/parser.cc.bak b/src/parser.cc.bak
649deleted file mode 100755
650index 2578022..0000000
651--- a/src/parser.cc.bak
652+++ /dev/null
653@@ -1,804 +0,0 @@
654-#include "grim.h" 
655-#include <iostream>
656-#include <fstream>
657-#include <sstream>
658-#include <unordered_map>
659-#include <cctype>
660-#include <algorithm>
661-#include <cmath>
662-#include <string_view>
663-
664-std::unordered_map<std::string, std::string> parseAttributes(std::string_view token) {
665-	std::unordered_map<std::string, std::string> attrs;
666-	
667-	bool inQuote = false;
668-	bool escaped = false;
669-	char quoteType = '"';
670-
671-	std::string word;
672-	for (unsigned short i = 0; i < token.length(); i++) {
673-		char current = token[i];
674-		if ((current == '"' || current == '\'') && !escaped) {
675-			if (inQuote && current == quoteType) {
676-				inQuote = false;
677-			} else if (!inQuote) {
678-				inQuote = true;
679-				quoteType = current;
680-			}
681-		}
682-
683-		if (current == '\\') { //'
684-			escaped = true;
685-			continue;
686-		}
687-
688-		if ((!std::isspace(current) || inQuote) && i != token.length()-1) {
689-			word += current;
690-		} else {
691-			if (i == token.length()-1) {
692-				word += current;
693-			}
694-
695-			std::string name = "";
696-			std::string value = "";
697-			bool setValue = false;
698-			
699-			for (auto c : word) {
700-				if (c == '=') {
701-					setValue = true;
702-					continue;
703-				}
704-
705-				if (setValue) {
706-					value += c;
707-				} else {
708-					name += c;
709-				}
710-			}
711-
712-			word = "";
713-
714-			std::string trimmedName = "";
715-			for (auto c : name) {
716-				if (!std::isspace(c)) {
717-					trimmedName += c;
718-				}
719-			}
720-
721-			if (attrs.size() == 0) {
722-				value = '"'+trimmedName+'"';
723-				trimmedName = "tagName";
724-			}
725-
726-			std::string trimmedValue = "";
727-			int sliceStart = 0;
728-			int sliceEnd = value.length();
729-
730-			if (value.length() >= 2) {
731-				for (unsigned short t = 0; t < value.length(); t++) {
732-					if (!std::isspace(value[t])) {
733-						sliceStart = t;
734-						break;
735-					}
736-				}
737-
738-				for (int t = value.length()-1; t >= 0; t--) {
739-					// Trim the trailing / on self closing elements if there isn't a space inbetween
740-					if (!std::isspace(value[t]) && value[t] != '/') {
741-						sliceEnd = t;
742-						break;
743-					}
744-				}
745-
746-				// Add and subtract 1 from each side to remove quotes
747-				for (unsigned short t = sliceStart+1; t < sliceEnd; t++) {
748-					trimmedValue += value[t];
749-				}
750-			}
751-
752-			attrs[trimmedName] = trimmedValue;
753-		}
754-	}
755-
756-	return attrs;
757-}
758-
759-std::unique_ptr<Node> parseHTML(std::istream& inputStream) {
760-	std::unique_ptr<Node> root = std::make_unique<Node>();
761-	root->setTagName("root");
762-
763-	Node* currentNode = root.get();
764-
765-	bool inTag = false;
766-	bool escaped = false;
767-	bool inQuote = false;
768-	bool inComment = false;
769-	bool waitToClose = false;
770-	char quoteType = '"';
771-
772-	std::string token;
773-
774-	char current;
775-	while (inputStream.get(current)) {
776-		// Finds the --> and removes it then resets inComment
777-		if (inComment) {
778-			// added the peek to prevent hitting on every -
779-			if (current == '-' && inputStream.peek() == '-') {
780-				char a,b;
781-				// load the next two
782-				if (inputStream.get(a) && inputStream.get(b)) {
783-					// We know a == -
784-					if (b == '>') {
785-						// Close the comment
786-						inComment = false;
787-					}
788-				}
789-
790-				if (!inComment) {
791-					// we don't put anything back and that puts us where we need to be
792-					continue;
793-				} else {
794-					// Not the end 
795-					inputStream.putback(b);
796-					inputStream.putback(a);
797-				}
798-			}
799-			continue;
800-		}
801-
802-		std::string tagName = currentNode->getTagName();
803-		if (!waitToClose && (
804-					tagName == "style" || 
805-					tagName == "script" ||
806-					tagName == "textarea" 
807-					) && current == '<' && inputStream.peek() == '/' ) {
808-			// If its the starting of a closing tag and we are inside of a special tag
809-			// we need to see if the upcoming closing tag is the correct closing tag
810-			// if it is then we put the read ahead back and waitToClose. This will let normal parsing
811-			// continue
812-			const size_t readTo = tagName.length()+2;
813-			std::string buffer(readTo, '\0');
814-
815-			inputStream.read(&buffer[0], readTo);
816-
817-			if (buffer == "/"+tagName+">") {
818-				waitToClose = true;
819-			} else {
820-				token += current;
821-			}
822-
823-			for (int i = readTo-1; i>= 0; i--) {
824-				inputStream.putback(buffer[i]);
825-			}
826-			if (!waitToClose) {
827-				continue;
828-			}
829-		} else if (!waitToClose && (
830-					tagName == "style" || 
831-					tagName == "script" ||
832-					tagName == "textarea" 
833-					)) {
834-			token += current;
835-			continue;
836-		}
837-
838-		if (inTag) {
839-			 if ((current == '"' || current == '\'') && !escaped) {
840-				if (inQuote && current == quoteType) {
841-					inQuote = false;
842-				} else if (!inQuote) {
843-					inQuote = true;
844-					quoteType = current;
845-				}
846-			}
847-
848-			if (current == '>' && !inQuote && !escaped) {
849-				inTag = false;
850-				waitToClose = false;
851-				// Even if the next tag is next still add a text tag as we can just check if its empty and remove it
852-				// this check would still have to be done either way so we aren't wasting anything
853-				if (token.length() > 0) {
854-					bool empty = true;
855-					bool closingTag = false;
856-					for (size_t i = 0; i < token.length(); i++) {
857-						auto c = token[i];
858-						if (std::isspace(c)) {
859-							continue;
860-						} else if (c == '/') {
861-							closingTag = true;
862-						} else {
863-							empty = false;
864-							break;
865-						}
866-					}
867-
868-					bool selfClosing = false;
869-					int selfClosingPosition = token.length()-1;
870-					if (!closingTag) {
871-						for (int i = token.length()-1; i >= 0; i--) {
872-							auto c = token[i];
873-							if (std::isspace(c)) {
874-								continue;
875-							} else if (c == '/') {
876-								selfClosingPosition = i;
877-								selfClosing = true;
878-								break;
879-							} else {
880-								break;
881-							}
882-						}
883-					}
884-
885-					if (!empty) {
886-						if (selfClosing) {
887-							//Create element and don't jump inside
888-							// Use node instead of currentNode because we do not need to jump into the created element
889-							auto attrs = parseAttributes(token.substr(0, selfClosingPosition));
890-							auto node = currentNode->createElement(attrs["tagName"]);
891-							for (auto const& pair : attrs) {
892-								// All attributes are stored as strings so we can just throw them in
893-								node->setAttribute(pair.first, pair.second);
894-							}
895-						} else if (closingTag) {
896-							// Checksum and tree move
897-							std::string tagName = "";
898-							for (auto t : token) {
899-								if (!std::isspace(t) && t != '/') {
900-									tagName += t;
901-								} else if (t == '/') {
902-									// For closing tags we just want the name
903-									continue;
904-								} else if (tagName.length() > 0) {
905-									break;
906-								}
907-							}
908-							if (currentNode->getTagName() == tagName) {
909-								currentNode = currentNode->parent;
910-							} else {
911-								std::cerr << "malformed html: closing tag (</" << tagName << ">) found for <" << currentNode->getTagName() << ">" << std::endl;
912-							}
913-						} else {
914-							// Create a element and jump inside
915-							auto attrs = parseAttributes(token);
916-							// Don't add elements like <!DOCTYPE>
917-							if (attrs["tagName"][0] != '!') {
918-								currentNode = currentNode->createElement(attrs["tagName"]);
919-								for (auto const& pair : attrs) {
920-									// All attributes are stored as strings so we can just throw them in
921-									currentNode->setAttribute(pair.first, pair.second);
922-								}
923-							}
924-						}
925-					}
926-				}
927-
928-				token = "";	
929-				continue;
930-			}
931-		} else if (!escaped && current == '<') {
932-			// if the next charector is a !
933-			if (inputStream.peek() == '!') {
934-				char a,b,c;
935-				// load the next three charecters (includes !)
936-				if (inputStream.get(a) && inputStream.get(b) && inputStream.get(c)) {
937-					// We know a == !
938-					if (b == '-' && c == '-') {
939-						inComment = true;
940-					}
941-				}
942-
943-				if (inComment) {
944-					continue;
945-				} else {
946-					// Not a comment add all back
947-					inputStream.putback(c);
948-					inputStream.putback(b);
949-					inputStream.putback(a);
950-				}
951-			}
952-			inTag = true;
953-			
954-			// Heres where you actually make the text node and above the real nodes
955-			// can also prob make the vector of tokens a single variable
956-			// it really just needs to be a data string bc we know the type based on inTag
957-
958-
959-			bool hasText = false;
960-			for (auto t : token) {
961-				if (!std::isspace(t)) {
962-					hasText = true;
963-					break;
964-				}
965-			}
966-
967-			// TODO: Add a vector that stores inner text and when elements start to close out pop them but add all to their innerText
968-			// | Will need something simular for innerHTML
969-			if (hasText) {
970-				auto node = currentNode->createElement("text");
971-				node->setAttribute("innerText", token);
972-			}
973-
974-
975-			token = "";
976-			continue;
977-		}
978-		
979-		escaped = false;
980-
981-		if (current == '\\') { //'
982-			escaped = true;
983-			continue;
984-		}
985-
986-		token += current;
987-	}
988-
989-	return root;
990-}
991-
992-
993-void typeCheck(std::string key, std::string value, Unit* property, std::vector<UnitType> allowedTypes) {
994-	for (size_t i = 0; i < property->children.size(); i++) {
995-		bool allowed = false;
996-		for (size_t j = 0; j < allowedTypes.size(); j++) {
997-			if (property->children[i].type == allowedTypes[j]) {
998-				allowed = true;
999-				break;
1000-			}
1001-		}
1002-
1003-		if (!allowed) {
1004-			std::cerr << "Invalid value of property: " << key << " Value: " << value << std::endl;
1005-			std::exit(10);
1006-		}
1007-	}	
1008-}
1009-
1010-struct SuffixParse {
1011-    std::string_view suffix;
1012-    UnitType type;
1013-    int trim;   // chars to strip from the right
1014-};
1015-
1016-static constexpr SuffixParse table[] = {
1017-    {"cqmin", UnitType::CQMIN, 5},
1018-    {"cqmax", UnitType::CQMAX, 5},
1019-    {"rcap",  UnitType::RCAP,  4},
1020-    {"vmax",  UnitType::VMAX,  4},
1021-    {"vmin",  UnitType::VMIN,  4},
1022-    {"cap",   UnitType::CAP,   3},
1023-    {"rch",   UnitType::RCH,   3},
1024-    {"rem",   UnitType::REM,   3},
1025-    {"rex",   UnitType::REX,   3},
1026-    {"ric",   UnitType::RIC,   3},
1027-    {"rlh",   UnitType::RLH,   3},
1028-    {"cqw",   UnitType::CQW,   3},
1029-    {"cqh",   UnitType::CQH,   3},
1030-    {"cqi",   UnitType::CQI,   3},
1031-    {"cqb",   UnitType::CQB,   3},
1032-    {"px",    UnitType::PX,    2},
1033-    {"em",    UnitType::EM,    2},
1034-    {"cm",    UnitType::CM,    2},
1035-    {"ch",    UnitType::CH,    2},
1036-    {"ex",    UnitType::EX,    2},
1037-    {"ic",    UnitType::IC,    2},
1038-    {"lh",    UnitType::LH,    2},
1039-    {"vh",    UnitType::VH,    2},
1040-    {"vw",    UnitType::VW,    2},
1041-    {"vb",    UnitType::VB,    2},
1042-    {"vi",    UnitType::VI,    2},
1043-    {"mm",    UnitType::MM,    2},
1044-    {"in",    UnitType::IN,    2},
1045-    {"pc",    UnitType::PC,    2},
1046-    {"pt",    UnitType::PT,    2},
1047-    {"%",     UnitType::PERCENT,1},
1048-    {"q",     UnitType::Q,     1},
1049-};
1050-
1051-std::vector<Unit> getUnit(std::string value) {
1052-	std::vector<Unit> units;
1053-	std::vector<Unit> children;
1054-
1055-	
1056-	std::string buffer = "";
1057-	std::string parenthesesesBuffer = "";
1058-	bool inParentheses = false;
1059-	bool inQuotes = false;
1060-	// Needs to not be empty but can't be a quote
1061-	char quoteType = 'a';
1062-	bool escaped = false;
1063-
1064-	for (size_t i = 0; i < value.length(); i++) {
1065-		char v = value[i];
1066-		if (v == '\\' && !escaped) escaped = true;
1067-
1068-		if (inParentheses) {
1069-			parenthesesesBuffer.push_back(v);
1070-		}
1071-
1072-		// The way this is setup to parse func() calls is like so
1073-		// | calc(1px, 2px);
1074-		// | -> value of 1px, 2px get's put into getUnit()
1075-		// | once those are pulled into children
1076-		// | the buffer only contains calc
1077-		// | add the children to the parsed keyword
1078-
1079-		
1080-		if (v == '(' && !inParentheses && !inQuotes) inParentheses = true;
1081-		else if (v == ')' && inParentheses && !inQuotes) {
1082-			children = getUnit(parenthesesesBuffer);
1083-			inParentheses = false;
1084-			parenthesesesBuffer.clear();
1085-		} else if ((v == '"' || v == '\'') && !inParentheses) {
1086-			if (inQuotes && v == quoteType) {
1087-				inQuotes = false;
1088-			} else if (!inQuotes) {
1089-				quoteType = v;
1090-				inQuotes = true;
1091-			}
1092-
1093-		} else if ((!inQuotes && !inParentheses && (v == ',' ||  std::isspace(v))) || i >= value.length()-1) {
1094-			if (buffer.length() == 0) continue;
1095-			if (v != ',' && !std::isspace(v)) buffer.push_back(v);
1096-
1097-			Unit unit;
1098-
1099-			// Split by spaces into parts
1100-
1101-			bool found = false;
1102-
1103-			for (const auto& [suffix, type, trim] : table) {
1104-				if (buffer.ends_with(suffix)) {
1105-					unit.value.FLOAT = std::stof(std::string(buffer.substr(0, buffer.size() - trim)));
1106-					unit.type = type;
1107-					found = true;
1108-					break;
1109-				}
1110-			}
1111-
1112-			if (!found) {
1113-				if (buffer.starts_with("#")) {
1114-					unit.type = UnitType::HEX;
1115-					unit.value.UINT = std::stoul(buffer.substr(1), nullptr, 16);
1116-					found = true;
1117-				} else if (buffer == "xx-small" || buffer == "x-small" || buffer == "small" || buffer == "medium" || 
1118-						buffer == "large" || buffer == "x-large" || buffer == "xx-large" || buffer == "xxx-large" ) {
1119-					// <absolute-size> read as a EM
1120-					unit.type = UnitType::EM;
1121-
1122-					if (buffer == "xx-small") unit.value.FLOAT = 0.6;
1123-					else if (buffer == "x-small") unit.value.FLOAT = 0.75;
1124-					else if (buffer == "small") unit.value.FLOAT = 0.89;
1125-					else if (buffer == "medium") unit.value.FLOAT = 1;
1126-					else if (buffer == "large") unit.value.FLOAT = 1.2;
1127-					else if (buffer == "x-large") unit.value.FLOAT = 1.5;
1128-					else if (buffer == "xx-large") unit.value.FLOAT = 2;
1129-					else if (buffer == "xxx-large") unit.value.FLOAT = 3;
1130-					found = true;
1131-				} else if (buffer.ends_with("baseline")) {
1132-					unit.type = UnitType::BASELINE;
1133-					std::cout << buffer << std::endl;
1134-					if (buffer.starts_with("first")) unit.value.ENUM = UnitType::FIRST;
1135-					else if (buffer.starts_with("last")) unit.value.ENUM = UnitType::LAST;
1136-					else unit.value.ENUM = UnitType::FIRST;
1137-					found = true;
1138-				} else if (buffer.ends_with("-box")) {
1139-					unit.type = UnitType::BOX_EDGE;
1140-
1141-					if (buffer.starts_with("content")) unit.value.ENUM = UnitType::CONTENT;
1142-					else if (buffer.starts_with("padding")) unit.value.ENUM = UnitType::PADDING;
1143-					else if (buffer.starts_with("border")) unit.value.ENUM = UnitType::BORDER;
1144-					else if (buffer.starts_with("margin")) unit.value.ENUM = UnitType::MARGIN;
1145-					else if (buffer.starts_with("fill")) unit.value.ENUM = UnitType::FILL;
1146-					else if (buffer.starts_with("stroke")) unit.value.ENUM = UnitType::STROKE;
1147-					else if (buffer.starts_with("view")) unit.value.ENUM = UnitType::VIEW;
1148-					found = true;
1149-				}
1150-			}
1151-
1152-			if (found) {
1153-				// Only process if its found
1154-
1155-				if (children.size() > 0) {
1156-					unit.children = children;
1157-					children.clear();
1158-				}
1159-
1160-				units.push_back(unit);
1161-
1162-				buffer.clear();
1163-			}
1164-		} else {
1165-			buffer.push_back(v);
1166-		}
1167-		
1168-		escaped = false;
1169-		if (v == '\\') escaped = true;
1170-		
1171-	}
1172-
1173-	return units;
1174-}
1175-
1176-void StyleHandler::parseStream(std::istream& inputStream) {
1177-	// nowhitespace: value(can have whitespace); = property
1178-	// a selector name is anything before a { up to a ; or a }
1179-	Sheet* root = &window->CSS.root;
1180-	
1181-	Sheet* current = root;
1182-	// how to handle @import
1183-
1184-	std::string buffer;
1185-
1186-	bool incomment = false;
1187-
1188-	char ch;
1189-	while (inputStream.get(ch)) {
1190-		if (ch == '*' && inputStream.peek() == '/') {
1191-			incomment = false;
1192-			// Skip ahead to the next letter so we don't caputure the trailing /
1193-			inputStream.get(ch);
1194-			continue;
1195-		}
1196-		if (ch == '/' && inputStream.peek() == '*') {
1197-			incomment = true;
1198-		}
1199-		
1200-		if (incomment) {
1201-			continue;
1202-		}
1203-
1204-		if (ch == '{') {
1205-			for (size_t i = buffer.length()-1; i >= 0; i--) {
1206-				if (std::isspace(buffer[i])) {
1207-					buffer.pop_back();
1208-				} else {
1209-					break;
1210-				}
1211-			}
1212-
1213-			// Parse the selector into its parts
1214-			std::vector<std::vector<std::string>> parts = parseSelectorParts(buffer);
1215-
1216-			if (current->selector.size() > 0) {
1217-				// To be able to handle a subsutution with a parent that has h1, h2
1218-				// we need to rebuild the selector so we can add new copies
1219-				std::vector<std::vector<std::string>> subd;
1220-
1221-				// Look for any & if its a style and replace it with the parsed parent selector
1222-				for (size_t i = 0; i < parts.size(); i++) {
1223-					bool hasAmp = false;
1224-					for (size_t e = 0; e < parts[i].size(); e++) {
1225-						if (parts[i][e] == "&") {
1226-							hasAmp = true;
1227-							break;
1228-						}
1229-					}
1230-
1231-					if (hasAmp) {
1232-						// If it contains a amp then we need replace the amp with each parent selector
1233-						// Inject each part of the parent
1234-						// Parent [[h1],[h2]]
1235-						// Child: [[& .class, &, &]]
1236-						// Result: [[h1 .class, h1, h1]]
1237-						// 	   [[h2 .class, h2, h2]]
1238-						for (size_t e = 0; e < current->selector.size(); e++) {
1239-							std::vector<std::string> temp;
1240-							for (size_t f = 0; f < parts[i].size(); f++) {
1241-								if (parts[i][f] == "&") {
1242-									for (auto p : current->selector[e]) {
1243-										temp.push_back(p);
1244-									}
1245-								} else {
1246-									temp.push_back(parts[i][f]);
1247-								}
1248-							}
1249-							subd.push_back(temp);
1250-						}
1251-					} else {
1252-						// If theres nothing to replace just add to back
1253-						subd.push_back(parts[i]);
1254-					}
1255-				}
1256-
1257-				parts = subd;
1258-			}
1259-
1260-			// Find who the parent is
1261-			Sheet newSheet;
1262-			newSheet.parent = current;
1263-			newSheet.selector = parts;
1264-			current->children.push_back(newSheet);
1265-
1266-			current = &current->children.back();
1267-
1268-			// here we need to take the selector (buffer)
1269-			// and find out what type it is. Also need to manage the nesting
1270-			if (parts[0][0][0] == '@') {
1271-				if (parts[0][0] == "@container") {
1272-					current->type = SheetType::CONTAINER;
1273-					bool hasName = false;
1274-					if (parts[0].size() >= 3) {
1275-						// @container not (width < 400px)
1276-						if (parts[0][2] != "not") {
1277-							// @container (width > 400px) or|and (height > 400px)
1278-							if (parts[0].size() >= 5) {
1279-								if (parts[0][5] != "and" || parts[0][5] != "or") {
1280-									current->name = parts[0][2];
1281-									hasName = true;
1282-								}
1283-							}
1284-						}
1285-					}
1286-					// If a name is present then remove the name and tag from the selector
1287-					// else just remove the @container
1288-					if (hasName) {
1289-						current->selector[0] = std::vector<std::string>(current->selector[0].begin() + 3, current->selector[0].end());
1290-					} else {
1291-						current->selector[0] = std::vector<std::string>(current->selector[0].begin() + 1, current->selector[0].end());
1292-					}
1293-				} else if (parts[0][0] == "@counter-style") {
1294-					current->name = parts[0][2];
1295-					current->type = SheetType::COUNTER;
1296-				} else if (parts[0][0] == "@font-face") {
1297-					current->type = SheetType::FONTFACE;
1298-				} else if (parts[0][0] == "@font-feature") {
1299-					current->type = SheetType::FONTFEATURE;
1300-				} else if (parts[0][0] == "@swash") {
1301-					current->type = SheetType::SWASH;
1302-				} else if (parts[0][0] == "@annotation") {
1303-					current->type = SheetType::ANNOTATION;
1304-				} else if (parts[0][0] == "@ornaments") {
1305-					current->type = SheetType::ORNAMENTS;
1306-				} else if (parts[0][0] == "@stylistic") {
1307-					current->type = SheetType::STYLISTIC;
1308-				} else if (parts[0][0] == "@styleset") {
1309-					current->type = SheetType::STYLESET;
1310-				} else if (parts[0][0] == "@character-varient") {
1311-					current->type = SheetType::CHARACTERVARIANT;
1312-				} else if (parts[0][0] == "@font-palette-values") {
1313-					current->type = SheetType::FONTPALETTEVALUES;
1314-					current->name = parts[0][2];
1315-				} else if (parts[0][0] == "@keyframes") {
1316-					current->type = SheetType::KEYFRAMES;
1317-					current->name = parts[0][2];
1318-				} else if (parts[0][0] == "@layer") {
1319-					current->type = SheetType::LAYER;
1320-				} else if (parts[0][0] == "@media") {
1321-					current->type = SheetType::MEDIA;
1322-				} else if (parts[0][0] == "@property") {
1323-					current->type = SheetType::PROPERTY;
1324-					current->name = parts[0][2];
1325-				} else if (parts[0][0] == "@starting-style") {
1326-					current->type = SheetType::STARTINGSTYLE;
1327-				}
1328-			} else {
1329-				current->type = SheetType::STYLE;
1330-			}
1331-			
1332-
1333-			buffer.clear();
1334-		} else if (ch == '}') {
1335-			// Calculate the basemap (more info in grim.h)
1336-			std::vector<std::string> targetParts = current->selector[current->selector.size()-1];
1337-			for (auto p : targetParts) {
1338-				if (current->parent->basemap.find(p) != current->parent->basemap.end()) {
1339-					current->parent->basemap[p].push_back(window->CSS.index);
1340-				} else {
1341-					std::vector<size_t> bm = {window->CSS.index};
1342-					current->parent->basemap[p] = bm;
1343-				}
1344-			}
1345-
1346-			window->CSS.index++;
1347-
1348-			if (current->parent != nullptr) {
1349-				current = current->parent;
1350-			}
1351-
1352-                        buffer.clear();
1353-		} else if (ch == ';') {
1354-			if (buffer[0] == '@') {
1355-				// Single line at-rule
1356-				Sheet inlineRule;
1357-				std::vector<std::vector<std::string>> parts = parseSelectorParts(buffer);
1358-				inlineRule.selector = parts;
1359-				
1360-				if (parts[0][0] == "@import") {
1361-					inlineRule.path = parts[0][2];
1362-
1363-					if (parts[0].size() > 3) {
1364-						// See if the last word ends in )
1365-						// if not then its the name of the layer
1366-						if (parts[0].back().back() != ')') {
1367-							inlineRule.name = parts[0].back();
1368-						}
1369-					}
1370-
1371-				} else if (parts[0][0] == "@layer") {
1372-					// ISSUE: need to add speficity
1373-
1374-				}
1375-
1376-				current->children.push_back(inlineRule);
1377-
1378-			} else {
1379-				// end of a style property
1380-				std::string key;
1381-				std::string value;
1382-				bool keyFound = false;
1383-				bool firstValue = false;
1384-				for (size_t i = 0; i < buffer.length(); i++) {
1385-					char c = buffer[i];
1386-					if (!keyFound && c == ':') {
1387-						keyFound = true;
1388-					} else if (!std::isspace(c) && !keyFound) {
1389-						key += c;
1390-					} else if (!firstValue && keyFound && !std::isspace(c)) {
1391-						firstValue = true;
1392-						value += c;
1393-					} else if (keyFound && firstValue && !(std::isspace(c) && i < buffer.length()-1 && std::isspace(buffer[i+1]))) {
1394-						// if the key is found and the charactor isn't a ':'
1395-						// 	also (if c is a space and the next c will be a space)
1396-						// 	this is to auto trim duplicate spaces from the value
1397-						value += c;
1398-					}
1399-				}
1400-
1401-				if (key.length() > 2 && key[0] == '-' && key[1] == '-') {
1402-					current->variables[key] = value;
1403-				} else {
1404-					current->properties[key] = value;
1405-				}
1406-			}
1407-			buffer.clear();
1408-		} else {
1409-			buffer.push_back(ch);
1410-		}
1411-	}
1412-}
1413-
1414-std::unordered_map<std::string, std::string> parseCSSInline(std::string inlineStyles) {
1415-	std::unordered_map<std::string, std::string> props;
1416-
1417-	std::string buffer;
1418-
1419-	for (size_t i = 0; i < inlineStyles.length(); i++) {
1420-		char ch = inlineStyles[i];
1421-
1422-		if (ch == ';' || i >= inlineStyles.length()-1) {
1423-			// If this is a ';' then it will be removed in the last else if statement
1424-			buffer.push_back(ch);
1425-			std::string key;
1426-			std::string value;
1427-			bool keyFound = false;
1428-			for (size_t i = 0; i < buffer.length(); i++) {
1429-				char c = buffer[i];
1430-				if (!keyFound && c == ':') {
1431-					keyFound = true;
1432-				} else if (!std::isspace(c) && !keyFound) {
1433-					key += c;
1434-				} else if (keyFound &&
1435-						!(std::isspace(c) && i < buffer.length()-1 && std::isspace(buffer[i+1])) &&
1436-						c != ';'
1437-					  ) {
1438-					// if the key is found and the charactor isn't a ':'
1439-					// 	also (if c is a space and the next c will be a space)
1440-					// 	this is to auto trim duplicate spaces from the value
1441-					value += c;
1442-					
1443-				}
1444-			}
1445-
1446-			props[key] = value;
1447-
1448-			buffer.clear();
1449-		} else {
1450-			buffer.push_back(ch);
1451-		}
1452-	}
1453-
1454-	return props;
1455-}
1456-
1457-
1458diff --git a/tests/.css_unit.cc.swp b/tests/.css_unit.cc.swp
1459deleted file mode 100644
1460index 9fda70f..0000000
1461Binary files a/tests/.css_unit.cc.swp and /dev/null differ
1462diff --git a/tests/css_unit.cc b/tests/css_unit.cc
1463index ca96159..9457dc9 100644
1464--- a/tests/css_unit.cc
1465+++ b/tests/css_unit.cc
1466@@ -718,7 +718,171 @@ TEST_CASE("getUnit can parse color values") {
1467 		REQUIRE(t[0].type == UnitType::CONTENT_DISTRIBUTION);
1468 		REQUIRE(t[0].value.ENUM == UnitType::STRETCH);
1469 	}
1470-
1471+	SECTION("content-position center") {
1472+		std::vector<Unit> t = getUnit("center");
1473+		REQUIRE(t[0].type == UnitType::CONTENT_POSITION);
1474+		REQUIRE(t[0].value.ENUM == UnitType::CENTER);
1475+	}
1476+	SECTION("content-position start") {
1477+		std::vector<Unit> t = getUnit("start");
1478+		REQUIRE(t[0].type == UnitType::CONTENT_POSITION);
1479+		REQUIRE(t[0].value.ENUM == UnitType::START);
1480+	}
1481+	SECTION("content-position end") {
1482+		std::vector<Unit> t = getUnit("end");
1483+		REQUIRE(t[0].type == UnitType::CONTENT_POSITION);
1484+		REQUIRE(t[0].value.ENUM == UnitType::END);
1485+	}
1486+	SECTION("content-position flex-start") {
1487+		std::vector<Unit> t = getUnit("flex-start");
1488+		REQUIRE(t[0].type == UnitType::CONTENT_POSITION);
1489+		REQUIRE(t[0].value.ENUM == UnitType::FLEX_START);
1490+	}
1491+	SECTION("content-position flex-end") {
1492+		std::vector<Unit> t = getUnit("flex-end");
1493+		REQUIRE(t[0].type == UnitType::CONTENT_POSITION);
1494+		REQUIRE(t[0].value.ENUM == UnitType::FLEX_END);
1495+	}
1496+	SECTION("display-box contents") {
1497+		std::vector<Unit> t = getUnit("contents");
1498+		REQUIRE(t[0].type == UnitType::DISPLAY_BOX);
1499+		REQUIRE(t[0].value.ENUM == UnitType::CONTENTS);
1500+	}
1501+	SECTION("display-box none") {
1502+		std::vector<Unit> t = getUnit("none");
1503+		REQUIRE(t[0].type == UnitType::DISPLAY_BOX);
1504+		REQUIRE(t[0].value.ENUM == UnitType::NONE);
1505+	}
1506+	SECTION("display-inside flow") {
1507+		std::vector<Unit> t = getUnit("flow");
1508+		REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1509+		REQUIRE(t[0].value.ENUM == UnitType::FLOW);
1510+	}
1511+	SECTION("display-inside flow-root") {
1512+		std::vector<Unit> t = getUnit("flow-root");
1513+		REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1514+		REQUIRE(t[0].value.ENUM == UnitType::FLOW_ROOT);
1515+	}
1516+	SECTION("display-inside table") {
1517+		std::vector<Unit> t = getUnit("table");
1518+		REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1519+		REQUIRE(t[0].value.ENUM == UnitType::TABLE);
1520+	}
1521+	SECTION("display-inside flex") {
1522+		std::vector<Unit> t = getUnit("flex");
1523+		REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1524+		REQUIRE(t[0].value.ENUM == UnitType::FLEX);
1525+	}
1526+	SECTION("display-inside grid") {
1527+		std::vector<Unit> t = getUnit("grid");
1528+		REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1529+		REQUIRE(t[0].value.ENUM == UnitType::GRID);
1530+	}
1531+	SECTION("display-inside ruby") {
1532+		std::vector<Unit> t = getUnit("ruby");
1533+		REQUIRE(t[0].type == UnitType::DISPLAY_INSIDE);
1534+		REQUIRE(t[0].value.ENUM == UnitType::RUBY);
1535+	}
1536+	SECTION("display-internal table-row-group") {
1537+		std::vector<Unit> t = getUnit("table-row-group");
1538+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1539+		REQUIRE(t[0].value.ENUM == UnitType::TABLE_ROW_GROUP);
1540+	}
1541+	SECTION("display-internal table-header-group") {
1542+		std::vector<Unit> t = getUnit("table-header-group");
1543+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1544+		REQUIRE(t[0].value.ENUM == UnitType::TABLE_HEADER_GROUP);
1545+	}
1546+	SECTION("display-internal table-footer-group") {
1547+		std::vector<Unit> t = getUnit("table-footer-group");
1548+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1549+		REQUIRE(t[0].value.ENUM == UnitType::TABLE_FOOTER_GROUP);
1550+	}
1551+	SECTION("display-internal table-column-group") {
1552+		std::vector<Unit> t = getUnit("table-column-group");
1553+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1554+		REQUIRE(t[0].value.ENUM == UnitType::TABLE_COLUMN_GROUP);
1555+	}
1556+	SECTION("display-internal table-row") {
1557+		std::vector<Unit> t = getUnit("table-row");
1558+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1559+		REQUIRE(t[0].value.ENUM == UnitType::TABLE_ROW);
1560+	}
1561+	SECTION("display-internal table-cell") {
1562+		std::vector<Unit> t = getUnit("table-cell");
1563+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1564+		REQUIRE(t[0].value.ENUM == UnitType::TABLE_CELL);
1565+	}
1566+	SECTION("display-internal table-column") {
1567+		std::vector<Unit> t = getUnit("table-column");
1568+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1569+		REQUIRE(t[0].value.ENUM == UnitType::TABLE_COLUMN);
1570+	}
1571+	SECTION("display-internal table-caption") {
1572+		std::vector<Unit> t = getUnit("table-caption");
1573+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1574+		REQUIRE(t[0].value.ENUM == UnitType::TABLE_CAPTION);
1575+	}
1576+	SECTION("display-internal ruby-base") {
1577+		std::vector<Unit> t = getUnit("ruby-base");
1578+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1579+		REQUIRE(t[0].value.ENUM == UnitType::RUBY_BASE);
1580+	}
1581+	SECTION("display-internal ruby-text") {
1582+		std::vector<Unit> t = getUnit("ruby-text");
1583+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1584+		REQUIRE(t[0].value.ENUM == UnitType::RUBY_TEXT);
1585+	}
1586+	SECTION("display-internal ruby-base-container") {
1587+		std::vector<Unit> t = getUnit("ruby-base-container");
1588+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1589+		REQUIRE(t[0].value.ENUM == UnitType::RUBY_BASE_CONTAINER);
1590+	}
1591+	SECTION("display-internal ruby-text-container") {
1592+		std::vector<Unit> t = getUnit("ruby-text-container");
1593+		REQUIRE(t[0].type == UnitType::DISPLAY_INTERNAL);
1594+		REQUIRE(t[0].value.ENUM == UnitType::RUBY_TEXT_CONTAINER);
1595+	}
1596+	SECTION("display-legacy inline-block") {
1597+		std::vector<Unit> t = getUnit("inline-block");
1598+		REQUIRE(t[0].type == UnitType::DISPLAY_LEGACY);
1599+		REQUIRE(t[0].value.ENUM == UnitType::INLINE_BLOCK);
1600+	}
1601+	SECTION("display-legacy inline-table") {
1602+		std::vector<Unit> t = getUnit("inline-table");
1603+		REQUIRE(t[0].type == UnitType::DISPLAY_LEGACY);
1604+		REQUIRE(t[0].value.ENUM == UnitType::INLINE_TABLE);
1605+	}
1606+	SECTION("display-legacy inline-flex") {
1607+		std::vector<Unit> t = getUnit("inline-flex");
1608+		REQUIRE(t[0].type == UnitType::DISPLAY_LEGACY);
1609+		REQUIRE(t[0].value.ENUM == UnitType::INLINE_FLEX);
1610+	}
1611+	SECTION("display-legacy inline-grid") {
1612+		std::vector<Unit> t = getUnit("inline-grid");
1613+		REQUIRE(t[0].type == UnitType::DISPLAY_LEGACY);
1614+		REQUIRE(t[0].value.ENUM == UnitType::INLINE_GRID);
1615+	}
1616+	SECTION("display-listitem list-item") {
1617+		std::vector<Unit> t = getUnit("list-item");
1618+		REQUIRE(t[0].type == UnitType::DISPLAY_LISTITEM);
1619+		REQUIRE(t[0].value.ENUM == UnitType::LISTITEM);
1620+	}
1621+	SECTION("display-outside block") {
1622+		std::vector<Unit> t = getUnit("block");
1623+		REQUIRE(t[0].type == UnitType::DISPLAY_OUTSIDE);
1624+		REQUIRE(t[0].value.ENUM == UnitType::BLOCK);
1625+	}
1626+	SECTION("display-outside inline") {
1627+		std::vector<Unit> t = getUnit("inline");
1628+		REQUIRE(t[0].type == UnitType::DISPLAY_OUTSIDE);
1629+		REQUIRE(t[0].value.ENUM == UnitType::INLINE);
1630+	}
1631+	SECTION("display-outside run-in") {
1632+		std::vector<Unit> t = getUnit("run-in");
1633+		REQUIRE(t[0].type == UnitType::DISPLAY_OUTSIDE);
1634+		REQUIRE(t[0].value.ENUM == UnitType::RUN_IN);
1635+	}
1636 }
1637 
1638 /*