mirror of
https://github.com/hyprwm/hyprlang.git
synced 2024-12-22 09:59:48 +01:00
core: add options for config parser
This commit is contained in:
parent
c69c286b31
commit
70145fd8da
5 changed files with 46 additions and 8 deletions
|
@ -50,6 +50,15 @@ namespace Hyprlang {
|
||||||
friend class CConfig;
|
friend class CConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Generic struct for options for the config parser */
|
||||||
|
struct SConfigOptions {
|
||||||
|
/* Don't throw errors on missing values. */
|
||||||
|
bool verifyOnly = false;
|
||||||
|
|
||||||
|
/* Return all errors instead of the first */
|
||||||
|
bool throwAllErrors = false;
|
||||||
|
};
|
||||||
|
|
||||||
/* Generic struct for options for handlers */
|
/* Generic struct for options for handlers */
|
||||||
struct SHandlerOptions {
|
struct SHandlerOptions {
|
||||||
bool allowFlags = false;
|
bool allowFlags = false;
|
||||||
|
@ -142,7 +151,7 @@ namespace Hyprlang {
|
||||||
/* Base class for a config file */
|
/* Base class for a config file */
|
||||||
class CConfig {
|
class CConfig {
|
||||||
public:
|
public:
|
||||||
CConfig(const char* configPath);
|
CConfig(const char* configPath, const SConfigOptions& options);
|
||||||
~CConfig();
|
~CConfig();
|
||||||
|
|
||||||
/* Add a config value, for example myCategory:myValue.
|
/* Add a config value, for example myCategory:myValue.
|
||||||
|
|
|
@ -28,7 +28,7 @@ static std::string removeBeginEndSpacesTabs(std::string str) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
CConfig::CConfig(const char* path) {
|
CConfig::CConfig(const char* path, const Hyprlang::SConfigOptions& options) {
|
||||||
impl = new CConfigImpl;
|
impl = new CConfigImpl;
|
||||||
try {
|
try {
|
||||||
impl->path = std::filesystem::canonical(path);
|
impl->path = std::filesystem::canonical(path);
|
||||||
|
@ -46,6 +46,8 @@ CConfig::CConfig(const char* path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(impl->envVariables.begin(), impl->envVariables.end(), [&](const auto& a, const auto& b) { return a.name.length() > b.name.length(); });
|
std::sort(impl->envVariables.begin(), impl->envVariables.end(), [&](const auto& a, const auto& b) { return a.name.length() > b.name.length(); });
|
||||||
|
|
||||||
|
impl->configOptions = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
CConfig::~CConfig() {
|
CConfig::~CConfig() {
|
||||||
|
@ -444,7 +446,7 @@ CParseResult CConfig::parseLine(std::string line, bool dynamic) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found)
|
if (!found && !impl->configOptions.verifyOnly)
|
||||||
ret = configSetValueSafe(LHS, RHS);
|
ret = configSetValueSafe(LHS, RHS);
|
||||||
|
|
||||||
if (ret.error)
|
if (ret.error)
|
||||||
|
@ -515,9 +517,11 @@ CParseResult CConfig::parseFile(std::string file) {
|
||||||
|
|
||||||
const auto RET = parseLine(line);
|
const auto RET = parseLine(line);
|
||||||
|
|
||||||
if (RET.error && impl->parseError.empty()) {
|
if (RET.error && (impl->parseError.empty() || impl->configOptions.throwAllErrors)) {
|
||||||
impl->parseError = RET.getError();
|
if (!impl->parseError.empty())
|
||||||
result.setError(std::format("Config error in file {} at line {}: {}", file, linenum, RET.errorStdString));
|
impl->parseError += "\n";
|
||||||
|
impl->parseError += std::format("Config error in file {} at line {}: {}", file, linenum, RET.errorStdString);
|
||||||
|
result.setError(impl->parseError);
|
||||||
}
|
}
|
||||||
|
|
||||||
++linenum;
|
++linenum;
|
||||||
|
@ -526,7 +530,13 @@ CParseResult CConfig::parseFile(std::string file) {
|
||||||
iffile.close();
|
iffile.close();
|
||||||
|
|
||||||
if (!impl->categories.empty()) {
|
if (!impl->categories.empty()) {
|
||||||
result.setError("Unclosed category at EOF");
|
if (impl->parseError.empty() || impl->configOptions.throwAllErrors) {
|
||||||
|
if (!impl->parseError.empty())
|
||||||
|
impl->parseError += "\n";
|
||||||
|
impl->parseError += std::format("Config error in file {}: Unclosed category at EOF", file);
|
||||||
|
result.setError(impl->parseError);
|
||||||
|
}
|
||||||
|
|
||||||
impl->categories.clear();
|
impl->categories.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,4 +69,6 @@ class CConfigImpl {
|
||||||
std::string currentSpecialKey = "";
|
std::string currentSpecialKey = "";
|
||||||
|
|
||||||
std::string parseError = "";
|
std::string parseError = "";
|
||||||
|
|
||||||
|
Hyprlang::SConfigOptions configOptions;
|
||||||
};
|
};
|
6
tests/config/error.conf
Normal file
6
tests/config/error.conf
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# This config houses two errors
|
||||||
|
|
||||||
|
someValue = 123
|
||||||
|
|
||||||
|
category {
|
||||||
|
invalid_line
|
|
@ -1,5 +1,6 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <hyprlang.hpp>
|
#include <hyprlang.hpp>
|
||||||
|
|
||||||
|
@ -75,7 +76,7 @@ int main(int argc, char** argv, char** envp) {
|
||||||
|
|
||||||
std::cout << "Starting test\n";
|
std::cout << "Starting test\n";
|
||||||
|
|
||||||
Hyprlang::CConfig config("./config/config.conf");
|
Hyprlang::CConfig config("./config/config.conf", {});
|
||||||
pConfig = &config;
|
pConfig = &config;
|
||||||
currentPath = std::filesystem::canonical("./config/");
|
currentPath = std::filesystem::canonical("./config/");
|
||||||
|
|
||||||
|
@ -182,6 +183,16 @@ int main(int argc, char** argv, char** envp) {
|
||||||
std::cout << " → Testing custom types\n";
|
std::cout << " → Testing custom types\n";
|
||||||
EXPECT(*reinterpret_cast<int64_t*>(std::any_cast<void*>(config.getConfigValue("customType"))), 1L);
|
EXPECT(*reinterpret_cast<int64_t*>(std::any_cast<void*>(config.getConfigValue("customType"))), 1L);
|
||||||
|
|
||||||
|
std::cout << " → Testing error.conf\n";
|
||||||
|
Hyprlang::CConfig errorConfig("./config/error.conf", {.verifyOnly = true, .throwAllErrors = true});
|
||||||
|
|
||||||
|
errorConfig.commence();
|
||||||
|
const auto ERRORS = errorConfig.parse();
|
||||||
|
|
||||||
|
EXPECT(ERRORS.error, true);
|
||||||
|
const auto ERRORSTR = std::string{ERRORS.getError()};
|
||||||
|
EXPECT(std::count(ERRORSTR.begin(), ERRORSTR.end(), '\n'), 1);
|
||||||
|
|
||||||
} catch (const char* e) {
|
} catch (const char* e) {
|
||||||
std::cout << Colors::RED << "Error: " << Colors::RESET << e << "\n";
|
std::cout << Colors::RED << "Error: " << Colors::RESET << e << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
|
|
Loading…
Reference in a new issue