diff --git a/src/config.cpp b/src/config.cpp index 2e5dfeb..4272ecd 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -474,14 +474,22 @@ CParseResult CConfig::parse() { sc->applyDefaults(); } - std::ifstream iffile(impl->path); - if (!iffile.good()) - throw "Config file failed to open"; + CParseResult fileParseResult = parseFile(impl->path); - std::string line = ""; - int linenum = 1; + return fileParseResult; +} - CParseResult fileParseResult; +CParseResult CConfig::parseFile(std::string file) { + CParseResult result; + + std::ifstream iffile(file); + if (!iffile.good()) { + result.setError("File failed to open"); + return result; + } + + std::string line = ""; + int linenum = 1; while (std::getline(iffile, line)) { @@ -489,7 +497,7 @@ CParseResult CConfig::parse() { if (RET.error && impl->parseError.empty()) { impl->parseError = RET.getError(); - fileParseResult.setError(std::format("Config error at line {}: {}", linenum, RET.errorStdString)); + result.setError(std::format("Config error in file {} at line {}: {}", file, linenum, RET.errorStdString)); } ++linenum; @@ -498,12 +506,11 @@ CParseResult CConfig::parse() { iffile.close(); if (!impl->categories.empty()) { - fileParseResult.setError("Unclosed category at EOF"); + result.setError("Unclosed category at EOF"); impl->categories.clear(); - return fileParseResult; } - return fileParseResult; + return result; } CParseResult CConfig::parseDynamic(const char* line) { diff --git a/src/public.hpp b/src/public.hpp index 1620784..06d28b2 100644 --- a/src/public.hpp +++ b/src/public.hpp @@ -132,6 +132,10 @@ namespace Hyprlang { /* Parse the config. Refresh the values. */ CParseResult parse(); + /* Same as parse(), but parse a specific file, without any refreshing. + recommended to use for stuff like source = path.conf */ + CParseResult parseFile(std::string file); + /* Parse a single "line", dynamically. Values set by this are temporary and will be overwritten by default / config on the next parse() */ diff --git a/tests/config/config.conf b/tests/config/config.conf index 77f1316..4f2bd47 100644 --- a/tests/config/config.conf +++ b/tests/config/config.conf @@ -11,6 +11,8 @@ testVar = $MY_VAR$MY_VAR_2 testEnv = $SHELL +source = ./colors.conf + testCategory { testValueInt = 123456 testValueHex = 0xF diff --git a/tests/main.cpp b/tests/main.cpp index 018230f..dbebe2c 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -1,4 +1,5 @@ #include +#include #include @@ -21,8 +22,10 @@ namespace Colors { } // globals for testing -bool barrelRoll = false; -std::string flagsFound = ""; +bool barrelRoll = false; +std::string flagsFound = ""; +Hyprlang::CConfig* pConfig = nullptr; +std::string currentPath = ""; static Hyprlang::CParseResult handleDoABarrelRoll(const char* COMMAND, const char* VALUE) { if (std::string(VALUE) == "woohoo, some, params") @@ -40,6 +43,11 @@ static Hyprlang::CParseResult handleFlagsTest(const char* COMMAND, const char* V return result; } +static Hyprlang::CParseResult handleSource(const char* COMMAND, const char* VALUE) { + std::string PATH = std::filesystem::canonical(currentPath + "/" + VALUE); + return pConfig->parseFile(PATH); +} + int main(int argc, char** argv, char** envp) { int ret = 0; @@ -47,6 +55,8 @@ int main(int argc, char** argv, char** envp) { std::cout << "Starting test\n"; Hyprlang::CConfig config("./config/config.conf"); + pConfig = &config; + currentPath = std::filesystem::canonical("./config/"); // setup config config.addConfigValue("testInt", 0L); @@ -64,9 +74,13 @@ int main(int argc, char** argv, char** envp) { config.addConfigValue("testCategory:testColor1", 0L); config.addConfigValue("testCategory:testColor2", 0L); config.addConfigValue("testCategory:testColor3", 0L); + config.addConfigValue("myColors:pink", 0L); + config.addConfigValue("myColors:green", 0L); + config.addConfigValue("myColors:random", 0L); config.registerHandler(&handleDoABarrelRoll, "doABarrelRoll", {false}); config.registerHandler(&handleFlagsTest, "flags", {true}); + config.registerHandler(&handleSource, "source", {false}); config.addSpecialCategory("special", {"key"}); config.addSpecialConfigValue("special", "value", 0L); @@ -136,6 +150,12 @@ int main(int argc, char** argv, char** envp) { EXPECT(std::any_cast(config.getSpecialConfigValue("specialGeneric:one", "value")), 1); EXPECT(std::any_cast(config.getSpecialConfigValue("specialGeneric:two", "value")), 2); + // test sourcing + std::cout << " → Testing sourcing\n"; + EXPECT(std::any_cast(config.getConfigValue("myColors:pink")), 0xFFc800c8L); + EXPECT(std::any_cast(config.getConfigValue("myColors:green")), 0xFF14f014L); + EXPECT(std::any_cast(config.getConfigValue("myColors:random")), 0xFFFF1337L); + } catch (const char* e) { std::cout << Colors::RED << "Error: " << Colors::RESET << e << "\n"; return 1;