Author: Mason Wright
Email:
[email protected]
Date: Sun, 29 Jun 2025 13:33:00 -0600
src/grim.cc.bak
5e4c38ff3c212cdd9881427ef3f8c2706539a190
Reworked parseSelectorParts and tests
Clone
-
.gitignore
M
Makefile
-
include/catch_amalgamated.cpp
-
include/catch_amalgamated.hpp
M
include/grim.h
-
include/parser.h
-
index.html
-
main.cc
-
src/adapter.cc
-
src/events.cc
M
src/grim.cc
A
src/grim.cc.bak
-
src/parser.cc
-
style.css
A
tests/css_selector.cc
-
tests/html_parser.cc
Commits
b966b2a517365074e5c381dbdea05b3221dc0198
e840f1eeb0ae26af69e1ae146ea9938e28e9f1af
e4e05418a640eaed08cd1ec7cd8644eb1dbcca50
4e01ba8ad2c3361fa4be3d896288020948b58b5e
aae562ac1350480e4889aabb35899f776c5b59e9
6c3ae0e31eb0893f20e3872117f92cc6b9a942af
350e7d88bb2feb9db00c6e032cc6623f215b7adf
95e6c70d23e99ffcf70e5bbe12503496e5d8f232
e188783659b9bc3b9993a647e93ed110e7f41db6
5e4c38ff3c212cdd9881427ef3f8c2706539a190
e50ea9e1356a74af18fdd171337ef9dc931e1f4e
8f2e83556d12aaebe8e8597ea6923804b0eb7a43
1627c585128af263181053ab2cf1a4cdcd14ee21
def3513f75b325464ad88a33c741c4ca80572b77
a21501590980a905fa9b902897d700a42a08b7f0
56074a6bfe4498d092f3a227297c8c20e2bb962c
d9cf1485b7ae0614130494f0e73237921323b9a1
80f04b134ae32ad8a9d526007b33dd02f6600f05
23d6c65f9368d3c622a55a3068a6b2f1efa0c8d4
09c195df02536b6a796bd648fce9669397b96109
f2b5c8202fbc904e2ed78260e3fdbd55164799d2
4bfba076120f389994fc46a98e8b7a2622314400
e36ac5417e10ee9b9f94f340e1ccf28afc5705ea
d00dc89a86dd7e2fcfd4618bc3a1c8cfba9e3c3d
d9eef16adaf292f3748db5fb5aa98463de10d712
18ff2ec1bfc1cf9fcd17c1acb05c3b41f8f0ed83
9e7fd2980d723437ea621b78d395fa72ca3f4922
Diff
diff --git a/src/grim.cc.bak b/src/grim.cc.bak deleted file mode 100755 index 36ec981..0000000 --- a/src/grim.cc.bak +++ /dev/null @@ -1,602 +0,0 @@ -#include "grim.h" -#include
-#include
-#include
-#include
-#include
- -std::string ClassList::value() const { - if (classes.empty()) { - return ""; - } - std::string collection = classes[0]; - for (size_t i = 1; i < classes.size(); ++i) { - collection += " " + classes[i]; - } - return collection; -} - -std::vector
ClassList::values() { - return classes; -} - -void ClassList::add(std::string value) { - classes.push_back(value); -} - -void ClassList::remove(std::string value) { - auto it_prev = std::find(classes.begin(), classes.end(), value); - if (it_prev != classes.end()) { - *it_prev = classes.back(); - classes.pop_back(); - } -} - -// Constructor -Node::Node() : parent(nullptr) {} - -std::string Node::getTagName() const { return TagName; } -void Node::setTagName(const std::string& name) { TagName = name; } - -const std::unordered_map
& Node::getAttributes() const { - return Attributes; -} - -// Implement the getter/setter methods declared using the macro -#define IMPLEMENT_ATTRIBUTE_ACCESSORS(_Type, _FuncNameSuffix, _AttrKeyString) \ - _Type Node::get##_FuncNameSuffix() const { \ - return getAttribute<_Type>(_AttrKeyString); \ - } \ - void Node::set##_FuncNameSuffix(_Type value) { \ - setAttribute(_AttrKeyString, value); \ - } - -IMPLEMENT_ATTRIBUTE_ACCESSORS(std::string, Id, "id") -IMPLEMENT_ATTRIBUTE_ACCESSORS(std::string, InnerText, "innerText") -IMPLEMENT_ATTRIBUTE_ACCESSORS(bool, ContentEditable, "contenteditable") -IMPLEMENT_ATTRIBUTE_ACCESSORS(std::string, Href, "href") -IMPLEMENT_ATTRIBUTE_ACCESSORS(std::string, Src, "src") -IMPLEMENT_ATTRIBUTE_ACCESSORS(std::string, Title, "title") -IMPLEMENT_ATTRIBUTE_ACCESSORS(std::string, Value, "value") -IMPLEMENT_ATTRIBUTE_ACCESSORS(int, TabIndex, "tabindex") -IMPLEMENT_ATTRIBUTE_ACCESSORS(bool, Disabled, "disabled") -IMPLEMENT_ATTRIBUTE_ACCESSORS(bool, Required, "required") -IMPLEMENT_ATTRIBUTE_ACCESSORS(bool, Checked, "checked") - -Node* Node::createElement(std::string name) { - std::unique_ptr
newNode = std::make_unique
(); - newNode->setTagName(name); - newNode->parent = this; - children.push_back(std::move(newNode)); - return children.back().get(); -} - -template
-void Node::setAttribute(const std::string& name, const T& value) { - if constexpr (std::is_same_v
) { - if (value) { - Attributes[name] = ""; - } else { - Attributes.erase(name); - } - } else if constexpr (std::is_arithmetic_v
) { - Attributes[name] = std::to_string(value); - } else { - static_assert(std::is_convertible_v
, - "setAttribute: Type cannot be converted to std::string automatically."); - Attributes[name] = static_cast
(value); - } -} - -void Node::setAttribute(const std::string& name, const std::string& value) { - Attributes[name] = value; -} - -template
-T Node::getAttribute(const std::string& name) const { - auto it = Attributes.find(name); - if (it != Attributes.end()) { - const std::string& s = it->second; - - if constexpr (std::is_same_v
) { - try { - return std::stoi(s); - } catch (const std::invalid_argument& e) { - return 0; - } catch (const std::out_of_range& e) { - return 0; - } - } else if constexpr (std::is_same_v
) { - std::string lower_s = s; - std::transform(lower_s.begin(), lower_s.end(), lower_s.begin(), - [](unsigned char c){ return std::tolower(c); }); - return (!lower_s.empty() && lower_s != "false"); - } else if constexpr (std::is_same_v
) { - try { - return std::stod(s); - } catch (const std::invalid_argument& e) { - return 0.0; - } catch (const std::out_of_range& e) { - return 0.0; - } - } else { - static_assert(std::is_convertible_v
, - "getAttribute: Type conversion from std::string not implemented for this type."); - return static_cast
(s); - } - } - return T(); -} - -std::string Node::getAttribute(const std::string& name) const { - auto it = Attributes.find(name); - if (it != Attributes.end()) { - return it->second; - } - return ""; -} - -std::vector
Node::getAttributeKeys() { - std::vector
keys; - - for(auto p : Attributes) { - keys.push_back(p.first); - } - return keys; -} - -std::string Node::print(int indent) { - std::string out = ""; - for (int i = 0; i < indent; ++i) { - out += " "; - } - - out += "<" + getTagName(); - for (const auto& attr_pair : getAttributes()) { - if (attr_pair.first == "innerText" || attr_pair.first == "tagName") { - continue; - } - out += " " + attr_pair.first; - if (!attr_pair.second.empty()) { - out += "=\"" + attr_pair.second + "\""; - } - } - out += ">"; - - if (!getAttribute("innerText").empty()) { - out += "\n" + getAttribute("innerText"); - } - - out += "\n"; - - for (const auto& child : children) { - out += child->print(indent + 1)+"\n"; - } - - for (int i = 0; i < indent; ++i) { - out += " "; - } - out += "" + getTagName() + ">\n"; - - return out; -} - -struct Style { - std::unordered_map
properties; - std::string selector; - // Index of when it was added (for cascading) - size_t index; -}; - -// splitSelector takes a CSS selector and splits it by a key -// it ingores any key that is inside (), [], or {} -// Used in testSelector to take a compound selector and match each one to the -// passed node until a match is found. -std::vector
splitSelector(std::string selector, char key) { - size_t nesting = 0; - - std::vector
selectors; - std::string current = ""; - - for (auto s : selector) { - if (s == '(') { - nesting++; - } else if (s == ')') { - nesting--; - } else if (s == '[') { - nesting++; - } else if (s == ']') { - nesting--; - } else if (s == '{') { - nesting++; - } else if (s == '}') { - nesting--; - } else if (s == key && nesting == 0) { - selectors.push_back(current); - current = ""; - continue; - } - current += s; - } - - selectors.push_back(current); - - // Trim the space - for (size_t i = 0; i < selectors.size(); i++) { - size_t start = 0; - size_t end = selectors[i].length()-1; - for (size_t s = 0; s < selectors[i].length(); s++) { - if (!std::isspace(selectors[i][s])) { - start = s; - break; - } - } - for (size_t e = selectors[i].length()-1; e > start; e--) { - if (!std::isspace(selectors[i][e])) { - end = e; - break; - } - } - selectors[i] = selectors[i].substr(start,end - start +1); - } - - return selectors; -} - -// This function is used to create a "short list" of full selectors -// that may apply to the element we are targeting. -// When we add a selector to the StyleHandler we use this function to -// create the basemap keys for the style we are adding. -// Additionally we will use this in the testSelector function to test each part of an -// of a selector to an element -// Example: given body > h1:required -// We use parseSelectorParts to get: [h1, :required] -// We test the first element given and it is a required h1 -// Next in the testSelector function we see the selector has a > -// so we pass the parent and the second part of the selector: -// body -// Then the process repeats -std::vector
parseSelectorParts(std::string selector) { - // we want to find the right most (right of a " " > ~ + ) selector - // need to account for selectors with parenthesis like: h1:(+ input:required) - // need to convert all single quotes to double quotes - // need to account for commas, will return - // need to claps all spaces to a single space - // need to trim spaces - - std::vector
parts; - size_t nesting = 0; - - std::string current = ""; - - for (auto s : selector) { - if (s == '(') { - nesting++; - } else if (s == ')') { - nesting--; - } else if (s == '[') { - nesting++; - } else if (s == ']') { - nesting--; - } else if (s == '{') { - nesting++; - } else if (s == '}') { - nesting--; - } else if (s == ',' && nesting == 0) { - // Same logic as splitSelector but we want to inline it here because we - // are already returning a vector so why make two? - // - // Here is the selector part parsing logic, we go backwards until we hit a combined - std::string part; - bool prevWasSpace = false; - for (size_t i = current.length()-1; i >= 0; i--) { - char c = current[i]; - if (c == '(') { - nesting++; - continue; - } else if (c == ')') { - nesting--; - continue; - } - - // We will still claps and convert while nested - if (c == ' ') { - // Claps spaces (will not trim) - if (!prevWasSpace) { - part = c + part; - prevWasSpace = true; - } - continue; - } else { - prevWasSpace = false; - - if (c == '\'') { - // convert single quotes to double quotes - part = '\"' + part; - } - continue; - } - if (nesting == 0) { - - } - } - current = ""; - continue; - } - current += s; - } - - return deduplicated; -} - -class StyleHandler { - private: - // basemap: Maps baseparts to a index of the styles vector pointing to a Style object - // because processing a CSS selector isn't trivial we want to make a short list of - // the styles that can possibly be a match so we aren't spending a lot of compute - // on a selector that applies to the wrong element. Todo this we take the right most part - // of a selector (that is the part that targets the current element) and we do a few checks - // like is the tagname the same, does it have that class, and do the id's match. If so that - // is a candidate and we run the full selector on it. That includes checking parents,children, - // or what ever else the selector needs to match. - std::unordered_map
> basemap; - std::vector