#include "meta.hpp" #include #include #include #include #include "VarList.hpp" CMeta* currentMeta = nullptr; CMeta::CMeta(const std::string& rawdata_, bool hyprlang_ /* false for toml */, bool dataIsPath) : rawdata(rawdata_), hyprlang(hyprlang_), dataPath(dataIsPath) { if (!dataIsPath) return; rawdata = ""; try { if (std::filesystem::exists(rawdata_ + ".hl")) { rawdata = rawdata_ + ".hl"; hyprlang = true; return; } if (std::filesystem::exists(rawdata_ + ".toml")) { rawdata = rawdata_ + ".toml"; hyprlang = false; return; } } catch (...) {} } std::optional CMeta::parse() { if (rawdata.empty()) return "Invalid meta (missing?)"; std::optional res; currentMeta = this; if (hyprlang) res = parseHL(); else res = parseTOML(); currentMeta = nullptr; return res; } static std::string removeBeginEndSpacesTabs(std::string str) { if (str.empty()) return str; int countBefore = 0; while (str[countBefore] == ' ' || str[countBefore] == '\t') { countBefore++; } int countAfter = 0; while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) { countAfter++; } str = str.substr(countBefore, str.length() - countBefore - countAfter); return str; } static Hyprlang::CParseResult parseDefineSize(const char* C, const char* V) { Hyprlang::CParseResult result; const std::string VALUE = V; CVarList sizes(VALUE, 0, ';'); for (const auto& sizeStr : sizes) { if (!sizeStr.contains(",")) { result.setError("Invalid define_size"); return result; } auto LHS = removeBeginEndSpacesTabs(sizeStr.substr(0, sizeStr.find_first_of(","))); auto RHS = removeBeginEndSpacesTabs(sizeStr.substr(sizeStr.find_first_of(",") + 1)); auto DELAY = 0; CMeta::SDefinedSize size; if (RHS.contains(",")) { const auto LL = removeBeginEndSpacesTabs(RHS.substr(0, RHS.find(","))); const auto RR = removeBeginEndSpacesTabs(RHS.substr(RHS.find(",") + 1)); try { size.delayMs = std::stoull(RR); } catch (std::exception& e) { result.setError(e.what()); return result; } RHS = LL; } if (!std::regex_match(RHS, std::regex("^[A-Za-z0-9_\\-\\.]+$"))) { result.setError("Invalid cursor file name, characters must be within [A-Za-z0-9_\\-\\.] (if this seems like a mistake, check for invisible characters)"); return result; } size.file = RHS; if (!size.file.ends_with(".svg")) { try { size.size = std::stoull(LHS); } catch (std::exception& e) { result.setError(e.what()); return result; } } else size.size = 0; currentMeta->parsedData.definedSizes.push_back(size); } return result; } static Hyprlang::CParseResult parseOverride(const char* C, const char* V) { Hyprlang::CParseResult result; const std::string VALUE = V; CVarList overrides(VALUE, 0, ';'); for (const auto& o : overrides) { currentMeta->parsedData.overrides.push_back(VALUE); } return result; } std::optional CMeta::parseHL() { std::unique_ptr meta; try { meta = std::make_unique(rawdata.c_str(), Hyprlang::SConfigOptions{.pathIsStream = !dataPath}); meta->addConfigValue("hotspot_x", Hyprlang::FLOAT{0.F}); meta->addConfigValue("hotspot_y", Hyprlang::FLOAT{0.F}); meta->addConfigValue("resize_algorithm", Hyprlang::STRING{"nearest"}); meta->registerHandler(::parseDefineSize, "define_size", {.allowFlags = false}); meta->registerHandler(::parseOverride, "define_override", {.allowFlags = false}); meta->commence(); const auto RESULT = meta->parse(); if (RESULT.error) return RESULT.getError(); } catch (const char* err) { return "failed parsing meta: " + std::string{err}; } parsedData.hotspotX = std::any_cast(meta->getConfigValue("hotspot_x")); parsedData.hotspotY = std::any_cast(meta->getConfigValue("hotspot_y")); parsedData.resizeAlgo = std::any_cast(meta->getConfigValue("resize_algorithm")); return {}; } std::optional CMeta::parseTOML() { try { auto MANIFEST = dataPath ? toml::parse_file(rawdata) : toml::parse(rawdata); parsedData.hotspotX = MANIFEST["General"]["hotspot_x"].value_or(0.f); parsedData.hotspotY = MANIFEST["General"]["hotspot_y"].value_or(0.f); const std::string OVERRIDES = MANIFEST["General"]["define_override"].value_or(""); const std::string SIZES = MANIFEST["General"]["define_size"].value_or(""); // CVarList OVERRIDESLIST(OVERRIDES, 0, ';', true); for (auto& o : OVERRIDESLIST) { const auto RESULT = ::parseOverride("define_override", o.c_str()); if (RESULT.error) throw; } CVarList SIZESLIST(SIZES, 0, ';', true); for (auto& s : SIZESLIST) { const auto RESULT = ::parseDefineSize("define_size", s.c_str()); if (RESULT.error) throw; } parsedData.resizeAlgo = MANIFEST["General"]["resize_algorithm"].value_or(""); } catch (std::exception& e) { return std::string{"Failed parsing toml: "} + e.what(); } return {}; }