New upstream version 0.5.1
This commit is contained in:
parent
bb479d7f9c
commit
c602a9207e
|
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
set(HYPRLANG_VERSION "0.5.0")
|
||||
set(HYPRLANG_VERSION "0.5.1")
|
||||
|
||||
project(hyprlang
|
||||
VERSION ${HYPRLANG_VERSION}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
#include "VarList.hpp"
|
||||
#include <ranges>
|
||||
#include <algorithm>
|
||||
|
||||
static std::string removeBeginEndSpacesTabs(std::string str) {
|
||||
if (str.empty())
|
||||
return str;
|
||||
|
||||
int countBefore = 0;
|
||||
while (str[countBefore] == ' ' || str[countBefore] == '\t') {
|
||||
countBefore++;
|
||||
}
|
||||
|
||||
int countAfter = 0;
|
||||
while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) {
|
||||
countAfter++;
|
||||
}
|
||||
|
||||
str = str.substr(countBefore, str.length() - countBefore - countAfter);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
CVarList::CVarList(const std::string& in, const size_t lastArgNo, const char delim, const bool removeEmpty) {
|
||||
if (in.empty())
|
||||
m_vArgs.emplace_back("");
|
||||
|
||||
std::string args{in};
|
||||
size_t idx = 0;
|
||||
size_t pos = 0;
|
||||
std::ranges::replace_if(
|
||||
args, [&](const char& c) { return delim == 's' ? std::isspace(c) : c == delim; }, 0);
|
||||
|
||||
for (const auto& s : args | std::views::split(0)) {
|
||||
if (removeEmpty && s.empty())
|
||||
continue;
|
||||
if (++idx == lastArgNo) {
|
||||
m_vArgs.emplace_back(removeBeginEndSpacesTabs(in.substr(pos)));
|
||||
break;
|
||||
}
|
||||
pos += s.size() + 1;
|
||||
m_vArgs.emplace_back(removeBeginEndSpacesTabs(std::string_view{s}.data()));
|
||||
}
|
||||
}
|
||||
|
||||
std::string CVarList::join(const std::string& joiner, size_t from, size_t to) const {
|
||||
size_t last = to == 0 ? size() : to;
|
||||
|
||||
std::string rolling;
|
||||
for (size_t i = from; i < last; ++i) {
|
||||
rolling += m_vArgs[i] + (i + 1 < last ? joiner : "");
|
||||
}
|
||||
|
||||
return rolling;
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class CVarList {
|
||||
public:
|
||||
/** Split string into arg list
|
||||
@param lastArgNo stop splitting after argv reaches maximum size, last arg will contain rest of unsplit args
|
||||
@param delim if delimiter is 's', use std::isspace
|
||||
@param removeEmpty remove empty args from argv
|
||||
*/
|
||||
CVarList(const std::string& in, const size_t maxSize = 0, const char delim = ',', const bool removeEmpty = false);
|
||||
|
||||
~CVarList() = default;
|
||||
|
||||
size_t size() const {
|
||||
return m_vArgs.size();
|
||||
}
|
||||
|
||||
std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const;
|
||||
|
||||
void map(std::function<void(std::string&)> func) {
|
||||
for (auto& s : m_vArgs)
|
||||
func(s);
|
||||
}
|
||||
|
||||
void append(const std::string arg) {
|
||||
m_vArgs.emplace_back(arg);
|
||||
}
|
||||
|
||||
std::string operator[](const size_t& idx) const {
|
||||
if (idx >= m_vArgs.size())
|
||||
return "";
|
||||
return m_vArgs[idx];
|
||||
}
|
||||
|
||||
// for range-based loops
|
||||
std::vector<std::string>::iterator begin() {
|
||||
return m_vArgs.begin();
|
||||
}
|
||||
std::vector<std::string>::const_iterator begin() const {
|
||||
return m_vArgs.begin();
|
||||
}
|
||||
std::vector<std::string>::iterator end() {
|
||||
return m_vArgs.end();
|
||||
}
|
||||
std::vector<std::string>::const_iterator end() const {
|
||||
return m_vArgs.end();
|
||||
}
|
||||
|
||||
bool contains(const std::string& el) {
|
||||
for (auto& a : m_vArgs) {
|
||||
if (a == el)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_vArgs;
|
||||
};
|
||||
|
|
@ -9,8 +9,16 @@
|
|||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
#include "VarList.hpp"
|
||||
|
||||
using namespace Hyprlang;
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <crt_externs.h>
|
||||
#define environ (*_NSGetEnviron())
|
||||
#else
|
||||
extern "C" char** environ;
|
||||
#endif
|
||||
|
||||
// defines
|
||||
inline constexpr const char* ANONYMOUS_KEY = "__hyprlang_internal_anonymous_key";
|
||||
|
|
@ -295,7 +303,37 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std::
|
|||
|
||||
const auto VALUEONLYNAME = command.starts_with(catPrefix) ? command.substr(catPrefix.length()) : command;
|
||||
|
||||
auto VALUEIT = impl->values.find(valueName);
|
||||
// FIXME: this will bug with nested.
|
||||
if (valueName.contains('[') && valueName.contains(']')) {
|
||||
const auto L = valueName.find_first_of('[');
|
||||
const auto R = valueName.find_last_of(']');
|
||||
|
||||
if (L < R) {
|
||||
const auto CATKEY = valueName.substr(L + 1, R - L - 1);
|
||||
impl->currentSpecialKey = CATKEY;
|
||||
|
||||
valueName = valueName.substr(0, L) + valueName.substr(R + 1);
|
||||
|
||||
// if it doesn't exist, make it
|
||||
for (auto& sc : impl->specialCategoryDescriptors) {
|
||||
if (sc->key.empty() || !valueName.starts_with(sc->name))
|
||||
continue;
|
||||
|
||||
// bingo
|
||||
const auto PCAT = impl->specialCategories.emplace_back(std::make_unique<SSpecialCategory>()).get();
|
||||
PCAT->descriptor = sc.get();
|
||||
PCAT->name = sc->name;
|
||||
PCAT->key = sc->key;
|
||||
addSpecialConfigValue(sc->name.c_str(), sc->key.c_str(), CConfigValue(CATKEY.c_str()));
|
||||
|
||||
applyDefaultsToCat(*PCAT);
|
||||
|
||||
PCAT->values[sc->key].setFrom(CATKEY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto VALUEIT = impl->values.find(valueName);
|
||||
if (VALUEIT == impl->values.end()) {
|
||||
// it might be in a special category
|
||||
bool found = false;
|
||||
|
|
@ -474,11 +512,31 @@ CParseResult CConfig::parseVariable(const std::string& lhs, const std::string& r
|
|||
return result;
|
||||
}
|
||||
|
||||
void CConfigImpl::parseComment(const std::string& comment) {
|
||||
const auto COMMENT = removeBeginEndSpacesTabs(comment);
|
||||
|
||||
if (!COMMENT.starts_with("hyprlang"))
|
||||
return;
|
||||
|
||||
CVarList 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";
|
||||
}
|
||||
|
||||
CParseResult CConfig::parseLine(std::string line, bool dynamic) {
|
||||
CParseResult result;
|
||||
|
||||
auto commentPos = line.find('#');
|
||||
size_t lastHashPos = 0;
|
||||
line = removeBeginEndSpacesTabs(line);
|
||||
|
||||
auto commentPos = line.find('#');
|
||||
|
||||
if (commentPos == 0) {
|
||||
impl->parseComment(line.substr(1));
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t lastHashPos = 0;
|
||||
|
||||
while (commentPos != std::string::npos) {
|
||||
bool escaped = false;
|
||||
|
|
@ -500,9 +558,12 @@ CParseResult CConfig::parseLine(std::string line, bool dynamic) {
|
|||
|
||||
line = removeBeginEndSpacesTabs(line);
|
||||
|
||||
if (line.empty())
|
||||
return result;
|
||||
|
||||
auto equalsPos = line.find('=');
|
||||
|
||||
if (equalsPos == std::string::npos && !line.ends_with("{") && line != "}" && !line.empty()) {
|
||||
if (equalsPos == std::string::npos && !line.ends_with("{") && line != "}") {
|
||||
// invalid line
|
||||
result.setError("Invalid config line");
|
||||
return result;
|
||||
|
|
@ -519,14 +580,14 @@ CParseResult CConfig::parseLine(std::string line, bool dynamic) {
|
|||
return result;
|
||||
}
|
||||
|
||||
if (*LHS.begin() == '$')
|
||||
return parseVariable(LHS, RHS, dynamic);
|
||||
const bool ISVARIABLE = *LHS.begin() == '$';
|
||||
|
||||
// limit unwrapping iterations to 100. if exceeds, raise error
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
bool anyMatch = false;
|
||||
for (auto& var : impl->variables) {
|
||||
const auto LHSIT = LHS.find("$" + var.name);
|
||||
// don't parse LHS variables if this is a variable...
|
||||
const auto LHSIT = ISVARIABLE ? std::string::npos : LHS.find("$" + var.name);
|
||||
const auto RHSIT = RHS.find("$" + var.name);
|
||||
|
||||
if (LHSIT != std::string::npos)
|
||||
|
|
@ -551,6 +612,9 @@ CParseResult CConfig::parseLine(std::string line, bool dynamic) {
|
|||
}
|
||||
}
|
||||
|
||||
if (ISVARIABLE)
|
||||
return parseVariable(LHS, RHS, dynamic);
|
||||
|
||||
bool found = false;
|
||||
for (auto& h : impl->handlers) {
|
||||
if (!h.options.allowFlags && h.name != LHS)
|
||||
|
|
@ -568,7 +632,7 @@ CParseResult CConfig::parseLine(std::string line, bool dynamic) {
|
|||
|
||||
if (ret.error)
|
||||
return ret;
|
||||
} else if (!line.empty()) {
|
||||
} else {
|
||||
// has to be a set
|
||||
if (line.contains("}")) {
|
||||
// easiest. } or invalid.
|
||||
|
|
@ -689,7 +753,7 @@ CParseResult CConfig::parseFile(const char* file) {
|
|||
|
||||
const auto RET = parseLine(line);
|
||||
|
||||
if (RET.error && (impl->parseError.empty() || impl->configOptions.throwAllErrors)) {
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -87,4 +87,10 @@ class CConfigImpl {
|
|||
std::string parseError = "";
|
||||
|
||||
Hyprlang::SConfigOptions configOptions;
|
||||
|
||||
void parseComment(const std::string& comment);
|
||||
|
||||
struct {
|
||||
bool noError = false;
|
||||
} currentFlags;
|
||||
};
|
||||
|
|
@ -1,5 +1,10 @@
|
|||
|
||||
# Test comment
|
||||
## This is also a comment
|
||||
## This is a comment with space as a first character
|
||||
## This is a comment with tab as a first character
|
||||
## This is a comment with leading spaces and tabs
|
||||
##### Comment with more hash tags
|
||||
|
||||
testInt = 123
|
||||
testFloat = 123.456
|
||||
|
|
@ -17,6 +22,12 @@ customType = abc
|
|||
|
||||
testStringColon = ee:ee:ee
|
||||
|
||||
# hyprlang noerror true
|
||||
|
||||
errorVariable = true
|
||||
|
||||
# hyprlang noerror false
|
||||
|
||||
testCategory {
|
||||
testValueInt = 123456
|
||||
testValueHex = 0xF
|
||||
|
|
@ -40,8 +51,7 @@ special {
|
|||
value = $SPECIALVAL1
|
||||
}
|
||||
|
||||
special {
|
||||
key = b
|
||||
special[b] {
|
||||
value = 2
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +77,10 @@ specialAnonymous {
|
|||
|
||||
testCategory:testValueHex = 0xFFfFaAbB
|
||||
|
||||
$RECURSIVE1 = a
|
||||
$RECURSIVE2 = $RECURSIVE1b
|
||||
testStringRecursive = $RECURSIVE2c
|
||||
|
||||
testStringQuotes = "Hello World!"
|
||||
#testDefault = 123
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ int main(int argc, char** argv, char** envp) {
|
|||
config.addConfigValue("testEnv", "");
|
||||
config.addConfigValue("testVar", (Hyprlang::INT)0);
|
||||
config.addConfigValue("testStringQuotes", "");
|
||||
config.addConfigValue("testStringRecursive", "");
|
||||
config.addConfigValue("testCategory:testValueInt", (Hyprlang::INT)0);
|
||||
config.addConfigValue("testCategory:testValueHex", (Hyprlang::INT)0xA);
|
||||
config.addConfigValue("testCategory:nested1:testValueNest", (Hyprlang::INT)0);
|
||||
|
|
@ -178,12 +179,16 @@ int main(int argc, char** argv, char** envp) {
|
|||
// test variables
|
||||
std::cout << " → Testing variables\n";
|
||||
EXPECT(std::any_cast<int64_t>(config.getConfigValue("testVar")), 13371337);
|
||||
EXPECT(std::any_cast<const char*>(config.getConfigValue("testStringRecursive")), std::string{"abc"});
|
||||
|
||||
// test dynamic variables
|
||||
std::cout << " → Testing dynamic variables\n";
|
||||
EXPECT(config.parseDynamic("$MY_VAR_2 = 420").error, false);
|
||||
EXPECT(std::any_cast<int64_t>(config.getConfigValue("testVar")), 1337420);
|
||||
|
||||
EXPECT(config.parseDynamic("$RECURSIVE1 = d").error, false);
|
||||
EXPECT(std::any_cast<const char*>(config.getConfigValue("testStringRecursive")), std::string{"dbc"});
|
||||
|
||||
// test env variables
|
||||
std::cout << " → Testing env variables\n";
|
||||
EXPECT(std::any_cast<const char*>(config.getConfigValue("testEnv")), std::string{getenv("SHELL")});
|
||||
|
|
@ -194,6 +199,8 @@ int main(int argc, char** argv, char** envp) {
|
|||
EXPECT(std::any_cast<int64_t>(config.getSpecialConfigValue("special", "value", "b")), 2);
|
||||
EXPECT(std::any_cast<int64_t>(config.getSpecialConfigValue("specialGeneric:one", "value")), 1);
|
||||
EXPECT(std::any_cast<int64_t>(config.getSpecialConfigValue("specialGeneric:two", "value")), 2);
|
||||
EXPECT(config.parseDynamic("special[b]:value = 3").error, false);
|
||||
EXPECT(std::any_cast<int64_t>(config.getSpecialConfigValue("special", "value", "b")), 3);
|
||||
|
||||
// test dynamic special variable
|
||||
EXPECT(config.parseDynamic("$SPECIALVAL1 = 2").error, false);
|
||||
|
|
|
|||
Loading…
Reference in New Issue