mirror of
https://github.com/hyprwm/hyprlang.git
synced 2024-11-17 02:25:59 +01:00
feat: implement multiline support
This commit is contained in:
parent
ec6938c662
commit
e15cfdcd97
4 changed files with 116 additions and 9 deletions
|
@ -3,6 +3,7 @@
|
|||
#include <fstream>
|
||||
#include <string>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <expected>
|
||||
|
@ -473,8 +474,9 @@ void CConfigImpl::parseComment(const std::string& comment) {
|
|||
|
||||
CParseResult CConfig::parseLine(std::string line, bool dynamic) {
|
||||
CParseResult result;
|
||||
bool shouldPreverseLeadingWhitespace = impl->multiline.delimiter == '\\';
|
||||
|
||||
line = trim(line);
|
||||
line = shouldPreverseLeadingWhitespace ? line.substr(0, line.find_last_not_of(MULTILINE_SPACE_CHARSET) + 1) : trim(line);
|
||||
|
||||
auto commentPos = line.find('#');
|
||||
|
||||
|
@ -496,6 +498,8 @@ CParseResult CConfig::parseLine(std::string line, bool dynamic) {
|
|||
|
||||
if (!escaped) {
|
||||
line = line.substr(0, commentPos);
|
||||
// there might be trailing whitespaces after the comment that weren't previous trimmed
|
||||
line = line.substr(0, line.find_last_not_of(MULTILINE_SPACE_CHARSET) + 1);
|
||||
break;
|
||||
} else {
|
||||
line = line.substr(0, commentPos + 1) + line.substr(commentPos + 2);
|
||||
|
@ -503,27 +507,29 @@ CParseResult CConfig::parseLine(std::string line, bool dynamic) {
|
|||
}
|
||||
}
|
||||
|
||||
line = trim(line);
|
||||
if (line.empty()) {
|
||||
if (impl->multiline.active)
|
||||
result.setError("Found empty line while parsing multiline value");
|
||||
|
||||
if (line.empty())
|
||||
return result;
|
||||
}
|
||||
|
||||
auto equalsPos = line.find('=');
|
||||
|
||||
if (equalsPos == std::string::npos && !line.ends_with("{") && line != "}") {
|
||||
if (equalsPos == std::string::npos && !line.ends_with("{") && line != "}" && !impl->multiline.active) {
|
||||
// invalid line
|
||||
result.setError("Invalid config line");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (equalsPos != std::string::npos) {
|
||||
if (equalsPos != std::string::npos || impl->multiline.active) {
|
||||
// set value or call handler
|
||||
CParseResult ret;
|
||||
auto LHS = trim(line.substr(0, equalsPos));
|
||||
auto RHS = trim(line.substr(equalsPos + 1));
|
||||
auto LHS = impl->multiline.active ? impl->multiline.lhs : trim(line.substr(0, equalsPos));
|
||||
auto RHS = impl->multiline.active ? line : trim(line.substr(equalsPos + 1));
|
||||
|
||||
if (LHS.empty()) {
|
||||
result.setError("Empty lhs.");
|
||||
result.setError("Empty lhs");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -562,6 +568,34 @@ CParseResult CConfig::parseLine(std::string line, bool dynamic) {
|
|||
if (ISVARIABLE)
|
||||
return parseVariable(LHS, RHS, dynamic);
|
||||
|
||||
auto lastChar = RHS[RHS.size() - 1];
|
||||
bool isMultilineContinuation = lastChar == '\\' || lastChar == '>';
|
||||
|
||||
if (isMultilineContinuation && impl->multiline.active && impl->multiline.delimiter != lastChar) {
|
||||
result.setError("Multiline continuation character mismatch. Make sure you are not mixing \\ and >");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (impl->multiline.buffer.size() > 0 && impl->multiline.delimiter == '>')
|
||||
impl->multiline.buffer += " ";
|
||||
|
||||
impl->multiline.active = isMultilineContinuation;
|
||||
|
||||
if (isMultilineContinuation) {
|
||||
impl->multiline.lhs = LHS;
|
||||
impl->multiline.delimiter = lastChar;
|
||||
RHS.erase(RHS.size() - 1);
|
||||
impl->multiline.buffer += RHS.substr(0, RHS.find_last_not_of(MULTILINE_SPACE_CHARSET) + 1);
|
||||
|
||||
return CParseResult{};
|
||||
}
|
||||
|
||||
if (!impl->multiline.buffer.empty()) {
|
||||
RHS = impl->multiline.buffer + RHS;
|
||||
impl->multiline.buffer.clear();
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (auto& h : impl->handlers) {
|
||||
if (!h.options.allowFlags && h.name != LHS)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
static const char* MULTILINE_SPACE_CHARSET = " \t";
|
||||
|
||||
struct SHandler {
|
||||
std::string name = "";
|
||||
Hyprlang::SHandlerOptions options;
|
||||
|
@ -33,6 +35,13 @@ enum eDataType {
|
|||
CONFIGDATATYPE_CUSTOM,
|
||||
};
|
||||
|
||||
struct SMultiLine {
|
||||
std::string buffer;
|
||||
char delimiter = 0;
|
||||
bool active = false;
|
||||
std::string lhs;
|
||||
};
|
||||
|
||||
// CUSTOM is stored as STR!!
|
||||
struct SConfigDefaultValue {
|
||||
std::any data;
|
||||
|
@ -83,6 +92,8 @@ class CConfigImpl {
|
|||
std::vector<std::string> categories;
|
||||
std::string currentSpecialKey = "";
|
||||
SSpecialCategory* currentSpecialCategory = nullptr; // if applicable
|
||||
bool isSpecialCategory = false;
|
||||
SMultiLine multiline;
|
||||
|
||||
std::string parseError = "";
|
||||
|
||||
|
@ -93,4 +104,4 @@ class CConfigImpl {
|
|||
struct {
|
||||
bool noError = false;
|
||||
} currentFlags;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -79,6 +79,51 @@ flagsStuff {
|
|||
value = 2
|
||||
}
|
||||
|
||||
|
||||
# '\' POSIX shell-like multiline syntax
|
||||
# Leading spaces are preserved while trailing spaces and linebreaks are discarded
|
||||
multilineSimple = I use C++ because \
|
||||
I hate Java
|
||||
|
||||
multilineTrim = I use Javascript because \ # Spaces should be trimmed before and after the delimiter
|
||||
I hate Python # here also.
|
||||
|
||||
multilineVar = $SPECIALVAL1 \
|
||||
$SPECIALVAL1 \
|
||||
$SPECIALVAL1 \
|
||||
$SPECIALVAL1
|
||||
|
||||
$NAME = multiline
|
||||
|
||||
multilineBreakWord = Hello $NAME, how are you to\
|
||||
day?
|
||||
|
||||
multilineMultiBreakWord = oui \
|
||||
oui \
|
||||
b \
|
||||
a \
|
||||
g \
|
||||
u \
|
||||
e \
|
||||
t \
|
||||
t \
|
||||
e
|
||||
|
||||
# Another syntax for multiline.
|
||||
# Ignores leading and trailing whitespaces. Linebreaks are turned into spaces.
|
||||
|
||||
multilineCategory {
|
||||
indentedMultiline = Hello >
|
||||
world >
|
||||
this is another syntax for >
|
||||
multiline that trims all spaces
|
||||
|
||||
multilineUneven = Hello >
|
||||
world >
|
||||
this is another syntax for >
|
||||
multiline that trims all spaces
|
||||
}
|
||||
|
||||
testCategory:testValueHex = 0xFFfFaAbB
|
||||
|
||||
$RECURSIVE1 = a
|
||||
|
|
|
@ -103,6 +103,14 @@ int main(int argc, char** argv, char** envp) {
|
|||
config.addConfigValue("myColors:green", (Hyprlang::INT)0);
|
||||
config.addConfigValue("myColors:random", (Hyprlang::INT)0);
|
||||
config.addConfigValue("customType", {Hyprlang::CConfigCustomValueType{&handleCustomValueSet, &handleCustomValueDestroy, "def"}});
|
||||
config.addConfigValue("multilineSimple", (Hyprlang::STRING) "");
|
||||
config.addConfigValue("multilineTrim", (Hyprlang::STRING) "");
|
||||
config.addConfigValue("multilineVar", (Hyprlang::STRING) "");
|
||||
config.addConfigValue("multilineTrim", (Hyprlang::STRING) "");
|
||||
config.addConfigValue("multilineBreakWord", (Hyprlang::STRING) "");
|
||||
config.addConfigValue("multilineMultiBreakWord", (Hyprlang::STRING) "");
|
||||
config.addConfigValue("multilineCategory:indentedMultiline", (Hyprlang::STRING) "");
|
||||
config.addConfigValue("multilineCategory:multilineUneven", (Hyprlang::STRING) "");
|
||||
|
||||
config.registerHandler(&handleDoABarrelRoll, "doABarrelRoll", {false});
|
||||
config.registerHandler(&handleFlagsTest, "flags", {true});
|
||||
|
@ -149,6 +157,15 @@ int main(int argc, char** argv, char** envp) {
|
|||
EXPECT(std::any_cast<int64_t>(config.getConfigValue("testCategory:testColor2")), (Hyprlang::INT)0xFF000000);
|
||||
EXPECT(std::any_cast<int64_t>(config.getConfigValue("testCategory:testColor3")), (Hyprlang::INT)0x22ffeeff);
|
||||
EXPECT(std::any_cast<const char*>(config.getConfigValue("testStringColon")), std::string{"ee:ee:ee"});
|
||||
EXPECT(std::any_cast<const char*>(config.getConfigValue("multilineSimple")), std::string{"I use C++ because I hate Java"});
|
||||
EXPECT(std::any_cast<const char*>(config.getConfigValue("multilineTrim")), std::string{"I use Javascript because I hate Python"});
|
||||
EXPECT(std::any_cast<const char*>(config.getConfigValue("multilineVar")), std::string{"1 1 1 1"});
|
||||
EXPECT(std::any_cast<const char*>(config.getConfigValue("multilineBreakWord")), std::string{"Hello multiline, how are you today?"});
|
||||
EXPECT(std::any_cast<const char*>(config.getConfigValue("multilineMultiBreakWord")), std::string{"oui oui baguette"});
|
||||
EXPECT(std::any_cast<const char*>(config.getConfigValue("multilineCategory:indentedMultiline")),
|
||||
std::string{"Hello world this is another syntax for multiline that trims all spaces"});
|
||||
EXPECT(std::any_cast<const char*>(config.getConfigValue("multilineCategory:multilineUneven")),
|
||||
std::string{"Hello world this is another syntax for multiline that trims all spaces"});
|
||||
|
||||
// test static values
|
||||
std::cout << " → Testing static values\n";
|
||||
|
|
Loading…
Reference in a new issue