configvalue: add an extended config value getter (#93)

This commit is contained in:
Damien Trala 2026-04-27 22:02:07 +02:00 committed by GitHub
parent 7833ff33b2
commit 090117506d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 106 additions and 37 deletions

View file

@ -389,6 +389,18 @@ namespace Hyprlang {
*/
CConfigValue* getSpecialConfigValuePtr(const char* category, const char* name, const char* key = nullptr);
/*!
Get a basic or special category's config value ptr.
Syntax:
- `name` -> `general:gaps_out`
- `category[key]:name` -> `windowrule[name]:enable`
\note Prefer `getConfigValuePtr` or `getSpecialConfigValuePtr` to avoid unnecessary lookup and parsing.
\warning The pointer is temporary and only valid for a brief moment
*/
CConfigValue* getAnyConfigValuePtr(const char* name);
/*!
Get a config value's stored value. Empty on fail
*/
@ -409,6 +421,22 @@ namespace Hyprlang {
return val->getValue();
}
/*!
Get a basic or special config value's stored value. Empty on fail.
Syntax:
- `name` -> `general:gaps_out`
- `category[key]:name` -> `windowrule[name]:enable`
\note Prefer `getConfigValue` or `getSpecialConfigValue` to avoid unnecessary lookup and parsing.
*/
std::any getAnyConfigValue(const char* name) {
CConfigValue* val = getAnyConfigValuePtr(name);
if (!val)
return {};
return val->getValue();
}
/*!
Check whether a special category with the provided key value exists

View file

@ -41,6 +41,20 @@ static size_t seekABIStructSize(const void* begin, size_t startOffset, size_t ma
return 0;
}
static SParsedConfigName parseConfigName(const char* name) {
const std::string NAME = name;
const auto L = NAME.find('[');
const auto R = NAME.find("]:", L);
if (L != std::string::npos && R != std::string::npos)
return SParsedConfigName{
.category = NAME.substr(0, L),
.key = NAME.substr(L + 1, R - L - 1),
.name = NAME.substr(R + 2),
};
return SParsedConfigName{.name = name};
}
static std::expected<std::string, eGetNextLineFailure> getNextLine(std::istream& str, int& rawLineNum, int& lineNum) {
std::string line = "";
std::string nextLine = "";
@ -293,50 +307,44 @@ std::pair<bool, CParseResult> CConfig::configSetValueSafe(const std::string& com
// TODO: all this sucks xD
SSpecialCategory* overrideSpecialCat = nullptr;
const auto parsedName = parseConfigName(valueName.c_str());
if (valueName.contains('[') && valueName.contains(']')) {
const auto L = valueName.find_first_of('[');
const auto R = valueName.find_last_of(']');
if (!parsedName.category.empty()) {
impl->currentSpecialKey = parsedName.key;
valueName = parsedName.category + ":" + parsedName.name;
if (L < R) {
const auto CATKEY = valueName.substr(L + 1, R - L - 1);
impl->currentSpecialKey = CATKEY;
for (auto& sc : impl->specialCategoryDescriptors) {
if (sc->key.empty() || !valueName.starts_with(sc->name + ":"))
continue;
valueName = valueName.substr(0, L) + valueName.substr(R + 1);
for (auto& sc : impl->specialCategoryDescriptors) {
if (sc->key.empty() || !valueName.starts_with(sc->name + ":"))
bool keyExists = false;
for (const auto& specialCat : impl->specialCategories) {
if (specialCat->key != sc->key || specialCat->name != sc->name)
continue;
bool keyExists = false;
for (const auto& specialCat : impl->specialCategories) {
if (specialCat->key != sc->key || specialCat->name != sc->name)
continue;
if (parsedName.key != std::string_view{std::any_cast<const char*>(specialCat->values[sc->key].getValue())})
continue;
if (CATKEY != std::string_view{std::any_cast<const char*>(specialCat->values[sc->key].getValue())})
continue;
// existing special
keyExists = true;
overrideSpecialCat = specialCat.get();
}
if (keyExists)
break;
// if it doesn't exist, make it
const auto PCAT = impl->specialCategories.emplace_back(std::make_unique<SSpecialCategory>()).get();
PCAT->descriptor = sc.get();
PCAT->name = sc->name;
PCAT->key = sc->key;
addSpecialConfigValue(sc->name.c_str(), sc->key.c_str(), CConfigValue(CATKEY.c_str()));
applyDefaultsToCat(*PCAT);
PCAT->values[sc->key].setFrom(CATKEY);
overrideSpecialCat = PCAT;
break;
// existing special
keyExists = true;
overrideSpecialCat = specialCat.get();
}
if (keyExists)
break;
// if it doesn't exist, make it
const auto PCAT = impl->specialCategories.emplace_back(std::make_unique<SSpecialCategory>()).get();
PCAT->descriptor = sc.get();
PCAT->name = sc->name;
PCAT->key = sc->key;
addSpecialConfigValue(sc->name.c_str(), sc->key.c_str(), CConfigValue(parsedName.key.c_str()));
applyDefaultsToCat(*PCAT);
PCAT->values[sc->key].setFrom(parsedName.key);
overrideSpecialCat = PCAT;
break;
}
}
@ -1109,6 +1117,13 @@ CConfigValue* CConfig::getSpecialConfigValuePtr(const char* category, const char
return nullptr;
}
CConfigValue* CConfig::getAnyConfigValuePtr(const char* name) {
const auto parsedName = parseConfigName(name);
if (!parsedName.category.empty())
return getSpecialConfigValuePtr(parsedName.category.c_str(), parsedName.name.c_str(), parsedName.key.c_str());
return getConfigValuePtr(name);
}
void CConfig::registerHandler(PCONFIGHANDLERFUNC func, const char* name, SHandlerOptions options_) {
SHandlerOptions options;
std::memcpy(&options, &options_, seekABIStructSize(&options_, 0, sizeof(SHandlerOptions)));

View file

@ -70,6 +70,12 @@ struct SSpecialCategory {
size_t anonymousID = 0;
};
struct SParsedConfigName {
std::string category = "";
std::string key = "";
std::string name = "";
};
enum eGetNextLineFailure : uint8_t {
GETNEXTLINEFAILURE_EOF = 0,
GETNEXTLINEFAILURE_BACKSLASH,

View file

@ -385,6 +385,26 @@ int main(int argc, char** argv, char** envp) {
EXPECT(std::any_cast<int64_t>(config.getSpecialConfigValue("specialAnonymousNested", "nested1:nested2:value1", KEYS2[1].c_str())), 12);
EXPECT(std::any_cast<int64_t>(config.getSpecialConfigValue("specialAnonymousNested", "nested1:nested2:value2", KEYS2[1].c_str())), 13);
std::cout << " → Testing the unified config value getter\n";
// check against expected counterpart
EXPECT(std::any_cast<int64_t>(config.getAnyConfigValue("testInt")), std::any_cast<int64_t>(config.getConfigValue("testInt")));
EXPECT(std::any_cast<float>(config.getAnyConfigValue("testFloat")), std::any_cast<float>(config.getConfigValue("testFloat")));
EXPECT(std::any_cast<const char*>(config.getAnyConfigValue("testString")), std::any_cast<const char*>(config.getConfigValue("testString")));
EXPECT(std::any_cast<int64_t>(config.getAnyConfigValue("special[a]:value")), std::any_cast<int64_t>(config.getSpecialConfigValue("special", "value", "a")));
EXPECT(std::any_cast<int64_t>(config.getAnyConfigValue("special[b]:value")), std::any_cast<int64_t>(config.getSpecialConfigValue("special", "value", "b")));
EXPECT(std::any_cast<int64_t>(config.getAnyConfigValue("special[]:value")), std::any_cast<int64_t>(config.getSpecialConfigValue("special", "value", "")));
EXPECT(std::any_cast<int64_t>(config.getAnyConfigValue("specialAnonymousNested[c]:nested:value1")),
std::any_cast<int64_t>(config.getSpecialConfigValue("specialAnonymousNested", "nested:value1", "c")));
// check against malformed
EXPECT(config.getAnyConfigValuePtr("[a]:value"), nullptr);
EXPECT(config.getAnyConfigValuePtr("special[[a]:value"), nullptr);
EXPECT(config.getAnyConfigValuePtr("special[[a]]:value"), nullptr);
EXPECT(config.getAnyConfigValuePtr("special[a]]:value"), nullptr);
EXPECT(config.getAnyConfigValuePtr("special[a]value"), nullptr);
EXPECT(config.getAnyConfigValuePtr("special[avalue"), nullptr);
EXPECT(config.getAnyConfigValuePtr("special]:a[value"), nullptr);
EXPECT(config.getAnyConfigValuePtr("speciala]:value"), nullptr);
// test sourcing
std::cout << " → Testing sourcing\n";
EXPECT(std::any_cast<int64_t>(config.getConfigValue("myColors:pink")), (Hyprlang::INT)0xFFc800c8);