Add support for multi-line configs

This commit is contained in:
Joshua Baker 2024-12-15 22:56:33 -06:00
parent f054f2e44d
commit 2c5093321f
4 changed files with 82 additions and 12 deletions

View file

@ -695,22 +695,52 @@ CParseResult CConfig::parse() {
CParseResult CConfig::parseRawStream(const std::string& stream) {
CParseResult result;
std::string line = "";
int linenum = 1;
std::string rawLine = "";
int rawLineNum = 0;
std::string line = "";
int lineNum = 0;
std::stringstream str(stream);
while (std::getline(str, line)) {
while (std::getline(str, rawLine)) {
line = rawLine;
lineNum = ++rawLineNum;
bool mergeWithNextLine = rawLine.length() > 0 && rawLine.at(rawLine.length() - 1) == '\\';
bool gotWholeLine = true;
while (mergeWithNextLine) {
const auto lastNonSpace = line.length() < 2 ? -1 : line.find_last_not_of(MULTILINE_SPACE_CHARSET, line.length() - 2);
line = line.substr(0, lastNonSpace + 1);
if (!std::getline(str, rawLine)) {
if (!impl->parseError.empty())
impl->parseError += "\n";
impl->parseError += "Config error: Last line ends with backslash";
result.setError(impl->parseError);
gotWholeLine = false;
break;
}
++rawLineNum;
line += rawLine;
mergeWithNextLine = line.length() > 0 && line.at(line.length() - 1) == '\\';
}
if (!gotWholeLine)
break;
const auto RET = parseLine(line);
if (RET.error && (impl->parseError.empty() || impl->configOptions.throwAllErrors)) {
if (!impl->parseError.empty())
impl->parseError += "\n";
impl->parseError += std::format("Config error at line {}: {}", linenum, RET.errorStdString);
impl->parseError += std::format("Config error at line {}: {}", lineNum, RET.errorStdString);
result.setError(impl->parseError);
}
++linenum;
lineNum = rawLineNum + 1;
line = "";
}
if (!impl->categories.empty()) {
@ -736,21 +766,50 @@ CParseResult CConfig::parseFile(const char* file) {
return result;
}
std::string line = "";
int linenum = 1;
std::string rawLine = "";
int rawLineNum = 0;
std::string line = "";
int lineNum = 0;
while (std::getline(iffile, line)) {
while (std::getline(iffile, rawLine)) {
line = rawLine;
lineNum = ++rawLineNum;
bool mergeWithNextLine = rawLine.length() > 0 && rawLine.at(rawLine.length() - 1) == '\\';
bool gotWholeLine = true;
while (mergeWithNextLine) {
const auto lastNonSpace = line.length() < 2 ? -1 : line.find_last_not_of(MULTILINE_SPACE_CHARSET, line.length() - 2);
line = line.substr(0, lastNonSpace + 1);
if (!std::getline(iffile, rawLine)) {
if (!impl->parseError.empty())
impl->parseError += "\n";
impl->parseError += std::format("Config error in file {}: Last line ends with backslash", file);
result.setError(impl->parseError);
gotWholeLine = false;
break;
}
++rawLineNum;
line += rawLine;
mergeWithNextLine = line.length() > 0 && line.at(line.length() - 1) == '\\';
}
if (!gotWholeLine)
break;
const auto RET = parseLine(line);
if (!impl->currentFlags.noError && RET.error && (impl->parseError.empty() || impl->configOptions.throwAllErrors)) {
if (!impl->parseError.empty())
impl->parseError += "\n";
impl->parseError += std::format("Config error in file {} at line {}: {}", file, linenum, RET.errorStdString);
impl->parseError += std::format("Config error in file {} at line {}: {}", file, lineNum, RET.errorStdString);
result.setError(impl->parseError);
}
++linenum;
lineNum = rawLineNum + 1;
line = "";
}
iffile.close();

View file

@ -4,6 +4,8 @@
#include <string>
#include <vector>
static const char* MULTILINE_SPACE_CHARSET = " \t";
struct SHandler {
std::string name = "";
Hyprlang::SHandlerOptions options;
@ -93,4 +95,4 @@ class CConfigImpl {
struct {
bool noError = false;
} currentFlags;
};
};

View file

@ -90,6 +90,11 @@ flagsStuff {
value = 2
}
multiline = \
very \
long \
command
testCategory:testValueHex = 0xFFfFaAbB
$RECURSIVE1 = a
@ -103,4 +108,3 @@ doABarrelRoll = woohoo, some, params # Funny!
flagsabc = test
#doSomethingFunny = 1, 2, 3, 4 # Funnier!
#testSpaces = abc , def # many spaces, should be trimmed

View file

@ -145,6 +145,8 @@ int main(int argc, char** argv, char** envp) {
config.addSpecialCategory("specialAnonymous", {nullptr, false, true});
config.addSpecialConfigValue("specialAnonymous", "value", (Hyprlang::INT)0);
config.addConfigValue("multiline", "");
config.commence();
config.addSpecialCategory("specialGeneric:one", {nullptr, true});
@ -269,6 +271,9 @@ int main(int argc, char** argv, char** envp) {
std::cout << " → Testing custom types\n";
EXPECT(*reinterpret_cast<int64_t*>(std::any_cast<void*>(config.getConfigValue("customType"))), (Hyprlang::INT)1);
// test multiline config
EXPECT(std::any_cast<const char*>(config.getConfigValue("multiline")), std::string{"very long command"});
std::cout << " → Testing error.conf\n";
Hyprlang::CConfig errorConfig("./config/error.conf", {.verifyOnly = true, .throwAllErrors = true});