core: add support for handlers

This commit is contained in:
Vaxry 2023-12-28 23:25:43 +01:00
parent 53d955b150
commit 19479c3216
5 changed files with 89 additions and 22 deletions

View file

@ -243,11 +243,28 @@ CParseResult CConfig::parseLine(std::string line) {
} }
if (equalsPos != std::string::npos) { if (equalsPos != std::string::npos) {
// set value // set value or call handler
CParseResult ret = configSetValueSafe(removeBeginEndSpacesTabs(line.substr(0, equalsPos)), removeBeginEndSpacesTabs(line.substr(equalsPos + 1))); CParseResult ret;
if (ret.error) { const auto LHS = removeBeginEndSpacesTabs(line.substr(0, equalsPos));
return ret; const auto RHS = removeBeginEndSpacesTabs(line.substr(equalsPos + 1));
bool found = false;
for (auto& h : impl->handlers) {
if (!h.options.allowFlags && h.name != LHS)
continue;
if (h.options.allowFlags && !LHS.starts_with(h.name))
continue;
ret = h.func(LHS.c_str(), RHS.c_str());
found = true;
} }
if (!found)
ret = configSetValueSafe(LHS, RHS);
if (ret.error)
return ret;
} else if (!line.empty()) { } else if (!line.empty()) {
// has to be a set // has to be a set
if (line.contains("}")) { if (line.contains("}")) {
@ -319,3 +336,7 @@ CConfigValue* CConfig::getConfigValuePtr(const char* name) {
const auto IT = impl->values.find(std::string{name}); const auto IT = impl->values.find(std::string{name});
return IT == impl->values.end() ? nullptr : &IT->second; return IT == impl->values.end() ? nullptr : &IT->second;
} }
void CConfig::registerHandler(PCONFIGHANDLERFUNC func, const char* name, SHandlerOptions options) {
impl->handlers.push_back(SHandler{name, options, func});
}

View file

@ -4,12 +4,19 @@
#include <string> #include <string>
#include <vector> #include <vector>
struct SHandler {
std::string name = "";
Hyprlang::SHandlerOptions options;
Hyprlang::PCONFIGHANDLERFUNC func = nullptr;
};
class CConfigImpl { class CConfigImpl {
public: public:
std::string path = ""; std::string path = "";
std::unordered_map<std::string, Hyprlang::CConfigValue> values; std::unordered_map<std::string, Hyprlang::CConfigValue> values;
std::unordered_map<std::string, Hyprlang::CConfigValue> defaultValues; std::unordered_map<std::string, Hyprlang::CConfigValue> defaultValues;
std::vector<SHandler> handlers;
std::vector<std::string> categories; std::vector<std::string> categories;

View file

@ -22,6 +22,30 @@ namespace Hyprlang {
} }
}; };
class CParseResult {
public:
bool error = false;
const char* getError() const {
return errorString;
}
void setError(const char* err);
private:
void setError(const std::string& err);
std::string errorStdString = "";
const char* errorString = nullptr;
friend class CConfig;
};
struct SHandlerOptions {
bool allowFlags = false;
};
/* typedefs */
typedef CParseResult (*PCONFIGHANDLERFUNC)(const char* COMMAND, const char* VALUE);
struct SConfigValueImpl; struct SConfigValueImpl;
/* Container for a config value */ /* Container for a config value */
class CConfigValue { class CConfigValue {
@ -63,23 +87,6 @@ namespace Hyprlang {
friend class CConfig; friend class CConfig;
}; };
class CParseResult {
public:
bool error = false;
const char* getError() const {
return errorString;
}
void setError(const char* err);
private:
void setError(const std::string& err);
std::string errorStdString = "";
const char* errorString = nullptr;
friend class CConfig;
};
/* Base class for a config file */ /* Base class for a config file */
class CConfig { class CConfig {
public: public:
@ -91,6 +98,10 @@ namespace Hyprlang {
Value provided becomes default */ Value provided becomes default */
void addConfigValue(const char* name, const CConfigValue value); void addConfigValue(const char* name, const CConfigValue value);
/* Register a handler. Can be called anytime, though not recommended
to do this dynamically */
void registerHandler(PCONFIGHANDLERFUNC func, const char* name, SHandlerOptions options);
/* Commence the config state. Config becomes immutable, as in /* Commence the config state. Config becomes immutable, as in
no new values may be added or removed. Required for parsing. */ no new values may be added or removed. Required for parsing. */
void commence(); void commence();

View file

@ -24,7 +24,8 @@ testCategory {
testStringQuotes = "Hello World!" testStringQuotes = "Hello World!"
#testDefault = 123 #testDefault = 123
#doABarrelRoll = woohoo, some, params # Funny! doABarrelRoll = woohoo, some, params # Funny!
flagsabc = test
#doSomethingFunny = 1, 2, 3, 4 # Funnier! #doSomethingFunny = 1, 2, 3, 4 # Funnier!
#testSpaces = abc , def # many spaces, should be trimmed #testSpaces = abc , def # many spaces, should be trimmed

View file

@ -10,6 +10,26 @@
std::cout << "Passed " << #expr << ". Got " << val << "\n"; \ std::cout << "Passed " << #expr << ". Got " << val << "\n"; \
} }
// globals for testing
bool barrelRoll = false;
std::string flagsFound = "";
static Hyprlang::CParseResult handleDoABarrelRoll(const char* COMMAND, const char* VALUE) {
if (std::string(VALUE) == "woohoo, some, params")
barrelRoll = true;
Hyprlang::CParseResult result;
return result;
}
static Hyprlang::CParseResult handleFlagsTest(const char* COMMAND, const char* VALUE) {
std::string cmd = COMMAND;
flagsFound = cmd.substr(5);
Hyprlang::CParseResult result;
return result;
}
int main(int argc, char** argv, char** envp) { int main(int argc, char** argv, char** envp) {
int ret = 0; int ret = 0;
@ -33,6 +53,9 @@ int main(int argc, char** argv, char** envp) {
config.addConfigValue("testCategory:testColor2", 0L); config.addConfigValue("testCategory:testColor2", 0L);
config.addConfigValue("testCategory:testColor3", 0L); config.addConfigValue("testCategory:testColor3", 0L);
config.registerHandler(&handleDoABarrelRoll, "doABarrelRoll", {false});
config.registerHandler(&handleFlagsTest, "flags", {true});
config.commence(); config.commence();
const auto PARSERESULT = config.parse(); const auto PARSERESULT = config.parse();
@ -58,6 +81,10 @@ int main(int argc, char** argv, char** envp) {
EXPECT(std::any_cast<int64_t>(config.getConfigValue("testCategory:testColor1")), 0xFFFFFFFFL); EXPECT(std::any_cast<int64_t>(config.getConfigValue("testCategory:testColor1")), 0xFFFFFFFFL);
EXPECT(std::any_cast<int64_t>(config.getConfigValue("testCategory:testColor2")), 0xFF000000L); EXPECT(std::any_cast<int64_t>(config.getConfigValue("testCategory:testColor2")), 0xFF000000L);
EXPECT(std::any_cast<int64_t>(config.getConfigValue("testCategory:testColor3")), 0x22ffeeffL); EXPECT(std::any_cast<int64_t>(config.getConfigValue("testCategory:testColor3")), 0x22ffeeffL);
// test handlers
EXPECT(barrelRoll, true);
EXPECT(flagsFound, std::string{"abc"});
} catch (const char* e) { } catch (const char* e) {
std::cout << "Error: " << e << "\n"; std::cout << "Error: " << e << "\n";
return 1; return 1;