core: add support for conditional statements

Adds support for simple if / endif statements operating on variables

Fixes #52
This commit is contained in:
Vaxry 2025-07-25 21:20:25 +02:00
parent cee01452bc
commit 235ce61cba
Signed by: vaxry
GPG key ID: 665806380871D640
3 changed files with 85 additions and 8 deletions

View file

@ -501,16 +501,71 @@ CParseResult CConfig::parseVariable(const std::string& lhs, const std::string& r
return result;
}
void CConfigImpl::parseComment(const std::string& comment) {
SVariable* CConfigImpl::getVariable(const std::string& name) {
for (auto& v : envVariables) {
if (v.name == name)
return &v;
}
for (auto& v : variables) {
if (v.name == name)
return &v;
}
return nullptr;
}
std::optional<std::string> CConfigImpl::parseComment(const std::string& comment) {
const auto COMMENT = trim(comment);
if (!COMMENT.starts_with("hyprlang"))
return;
return std::nullopt;
CVarList args(COMMENT, 0, 's', true);
CConstVarList args(COMMENT, 0, 's', true);
if (args[1] == "noerror")
currentFlags.noError = args[2] == "true" || args[2] == "yes" || args[2] == "enable" || args[2] == "enabled" || args[2] == "set";
bool negated = false;
std::string ifBlockVariable = "";
for (size_t i = 1; i < args.size(); ++i) {
if (args[i] == "noerror") {
if (negated)
currentFlags.noError = false;
else
currentFlags.noError = args[2] == "true" || args[2] == "yes" || args[2] == "enable" || args[2] == "enabled" || args[2] == "set" || args[2].empty();
break;
}
if (args[i] == "!") {
negated = true;
continue;
}
if (args[i] == "endif") {
if (!currentFlags.inAnIfBlock)
return "stray endif";
currentFlags.inAnIfBlock = false;
break;
}
if (args[i] == "if") {
ifBlockVariable = args[++i];
break;
}
}
if (!ifBlockVariable.empty()) {
if (currentFlags.inAnIfBlock)
return "nested if statements are not allowed";
currentFlags.inAnIfBlock = true;
if (const auto VAR = getVariable(ifBlockVariable); VAR)
currentFlags.ifBlockFailed = !VAR->truthy();
else
currentFlags.ifBlockFailed = true;
}
return std::nullopt;
}
std::expected<float, std::string> CConfigImpl::parseExpression(const std::string& s) {
@ -571,10 +626,15 @@ CParseResult CConfig::parseLine(std::string line, bool dynamic) {
auto commentPos = line.find('#');
if (commentPos == 0) {
impl->parseComment(line.substr(1));
const auto COMMENT_RESULT = impl->parseComment(line.substr(1));
if (COMMENT_RESULT.has_value())
result.setError(*COMMENT_RESULT);
return result;
}
if (impl->currentFlags.inAnIfBlock && impl->currentFlags.ifBlockFailed)
return result;
size_t lastHashPos = 0;
while (commentPos != std::string::npos) {

View file

@ -23,6 +23,10 @@ struct SVariable {
};
std::vector<SVarLine> linesContainingVar; // for dynamic updates
bool truthy() {
return value.length() > 0;
}
};
// remember to also edit CConfigValue if editing
@ -95,10 +99,13 @@ class CConfigImpl {
Hyprlang::SConfigOptions configOptions;
void parseComment(const std::string& comment);
std::optional<std::string> parseComment(const std::string& comment);
std::expected<float, std::string> parseExpression(const std::string& s);
SVariable* getVariable(const std::string& name);
struct {
bool noError = false;
bool noError = false;
bool inAnIfBlock = false;
bool ifBlockFailed = false;
} currentFlags;
};

View file

@ -45,9 +45,19 @@ errorVariable = true
# hyprlang noerror false
# hyprlang if NONEXISTENT_VAR
customType = bcd
# hyprlang endif
# hyprlang if MY_VAR
categoryKeyword = oops, this one shouldn't call the handler, not fun
testUseKeyword = yes
# hyprlang endif
testCategory {
testValueInt = 123456
testValueHex = 0xF