diff --git a/include/hyprlang.hpp b/include/hyprlang.hpp index fcebdce..96bca49 100644 --- a/include/hyprlang.hpp +++ b/include/hyprlang.hpp @@ -131,6 +131,17 @@ namespace Hyprlang { don't pop up an error if the config value is missing */ bool ignoreMissing = false; + + /*! + Make this category an anonymous special one. + key has to be nullptr. + + Anonymous special categories behave like key-based ones, but the keys + will be automatically assigned without user input. + + \since 0.4.0 + */ + bool anonymousKeyBased = false; }; /*! diff --git a/src/config.cpp b/src/config.cpp index de61ae5..7ee367f 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -8,7 +8,11 @@ #include using namespace Hyprlang; -extern "C" char** environ; +extern "C" char** environ; + +// defines +inline constexpr const char* ANONYMOUS_KEY = "__hyprlang_internal_anonymous_key"; +// static std::string removeBeginEndSpacesTabs(std::string str) { if (str.empty()) @@ -107,14 +111,17 @@ void CConfig::addSpecialCategory(const char* name, SSpecialCategoryOptions optio PDESC->key = options.key ? options.key : ""; PDESC->dontErrorOnMissing = options.ignoreMissing; - if (!options.key) { + if (!options.key && !options.anonymousKeyBased) { const auto PCAT = impl->specialCategories.emplace_back(std::make_unique()).get(); PCAT->descriptor = PDESC; PCAT->name = name; - PCAT->key = options.key ? options.key : ""; + PCAT->key = ""; PCAT->isStatic = true; - if (!PCAT->key.empty()) - addSpecialConfigValue(name, options.key, CConfigValue("0")); + } + + if (options.anonymousKeyBased) { + PDESC->key = ANONYMOUS_KEY; + PDESC->anonymous = true; } // sort longest to shortest @@ -310,12 +317,26 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std:: if (VALUEIT != PCAT->values.end()) found = true; - if (VALUEIT == PCAT->values.end() || VALUEIT->first != sc->key) { - result.setError(std::format("special category's first value must be the key. Key for <{}> is <{}>", PCAT->name, PCAT->key)); - return result; - } + if (sc->anonymous) { + // find suitable key + size_t biggest = 0; + for (auto& catt : impl->specialCategories) { + if (catt->anonymousID > biggest) + biggest = catt->anonymousID; + } - impl->currentSpecialKey = value; + biggest++; + + PCAT->values[ANONYMOUS_KEY].setFrom(std::to_string(biggest)); + impl->currentSpecialKey = std::to_string(biggest); + PCAT->anonymousID = biggest; + } else { + if (VALUEIT == PCAT->values.end() || VALUEIT->first != sc->key) { + result.setError(std::format("special category's first value must be the key. Key for <{}> is <{}>", PCAT->name, PCAT->key)); + return result; + } + impl->currentSpecialKey = value; + } break; } diff --git a/src/config.hpp b/src/config.hpp index 81d9375..3e72791 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -41,6 +41,7 @@ struct SSpecialCategoryDescriptor { std::string key = ""; std::unordered_map defaultValues; bool dontErrorOnMissing = false; + bool anonymous = false; }; struct SSpecialCategory { @@ -51,6 +52,9 @@ struct SSpecialCategory { bool isStatic = false; void applyDefaults(); + + // for easy anonymous ID'ing + size_t anonymousID = 0; }; class CConfigImpl { diff --git a/tests/config/config.conf b/tests/config/config.conf index 0144da3..e68c46e 100644 --- a/tests/config/config.conf +++ b/tests/config/config.conf @@ -53,6 +53,14 @@ specialGeneric { } } +specialAnonymous { + value = 2 +} + +specialAnonymous { + value = 3 +} + testCategory:testValueHex = 0xFFfFaAbB testStringQuotes = "Hello World!" diff --git a/tests/parse/main.cpp b/tests/parse/main.cpp index 696ef9a..c11c4ae 100644 --- a/tests/parse/main.cpp +++ b/tests/parse/main.cpp @@ -108,6 +108,9 @@ int main(int argc, char** argv, char** envp) { config.addSpecialCategory("special", {"key"}); config.addSpecialConfigValue("special", "value", (Hyprlang::INT)0); + config.addSpecialCategory("specialAnonymous", {nullptr, false, true}); + config.addSpecialConfigValue("specialAnonymous", "value", (Hyprlang::INT)0); + config.commence(); config.addSpecialCategory("specialGeneric:one", {nullptr, true}); @@ -194,6 +197,11 @@ int main(int argc, char** argv, char** envp) { // test listing keys EXPECT(config.listKeysForSpecialCategory("special")[1], "b"); + // test anonymous + EXPECT(config.listKeysForSpecialCategory("specialAnonymous").size(), 2); + const auto KEYS = config.listKeysForSpecialCategory("specialAnonymous"); + EXPECT(std::any_cast(config.getSpecialConfigValue("specialAnonymous", "value", KEYS[1].c_str())), 3); + // test sourcing std::cout << " → Testing sourcing\n"; EXPECT(std::any_cast(config.getConfigValue("myColors:pink")), (Hyprlang::INT)0xFFc800c8);