mirror of
https://github.com/hyprwm/Hyprland
synced 2026-05-09 05:58:13 +02:00
config: allow hashes for parsing colors (#14337)
This commit is contained in:
parent
a6a0cc308c
commit
b94f149854
18 changed files with 277 additions and 195 deletions
|
|
@ -14,6 +14,7 @@
|
|||
#include "../shared/workspace/WorkspaceRuleManager.hpp"
|
||||
#include "../shared/animation/AnimationTree.hpp"
|
||||
#include "../shared/monitor/Parser.hpp"
|
||||
#include "../shared/parserUtils/ParserUtils.hpp"
|
||||
#include "../supplementary/executor/Executor.hpp"
|
||||
#include "../supplementary/jeremy/Jeremy.hpp"
|
||||
#include "../../protocols/LayerShell.hpp"
|
||||
|
|
@ -131,7 +132,7 @@ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void**
|
|||
}
|
||||
|
||||
try {
|
||||
const auto COL = configStringToInt(std::string(var));
|
||||
const auto COL = ParserUtils::parseColor(var);
|
||||
if (!COL)
|
||||
throw std::runtime_error(std::format("failed to parse {} as a color", var));
|
||||
DATA->m_colors.emplace_back(COL.value());
|
||||
|
|
@ -1424,7 +1425,7 @@ std::optional<std::string> CConfigManager::handleAnimation(const std::string& co
|
|||
return "no such animation";
|
||||
|
||||
// This helper casts strings like "1", "true", "off", "yes"... to int.
|
||||
int64_t enabledInt = configStringToInt(ARGS[1]).value_or(0) == 1;
|
||||
int64_t enabledInt = ParserUtils::parseInt(ARGS[1]).value_or(0) == 1;
|
||||
|
||||
// Checking that the int is 1 or 0 because the helper can return integers out of range.
|
||||
if (enabledInt != 0 && enabledInt != 1)
|
||||
|
|
@ -1715,24 +1716,24 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
|
|||
wsRule.m_borderSize = std::stoi(rule.substr(delim + 11));
|
||||
} catch (...) { return "Error parsing workspace rule bordersize: {}", rule.substr(delim + 11); }
|
||||
else if ((delim = rule.find("border:")) != std::string::npos) {
|
||||
CHECK_OR_THROW(configStringToInt(rule.substr(delim + 7)))
|
||||
CHECK_OR_THROW(ParserUtils::parseInt(rule.substr(delim + 7)))
|
||||
wsRule.m_noBorder = !*X;
|
||||
} else if ((delim = rule.find("shadow:")) != std::string::npos) {
|
||||
CHECK_OR_THROW(configStringToInt(rule.substr(delim + 7)))
|
||||
CHECK_OR_THROW(ParserUtils::parseInt(rule.substr(delim + 7)))
|
||||
wsRule.m_noShadow = !*X;
|
||||
} else if ((delim = rule.find("rounding:")) != std::string::npos) {
|
||||
CHECK_OR_THROW(configStringToInt(rule.substr(delim + 9)))
|
||||
CHECK_OR_THROW(ParserUtils::parseInt(rule.substr(delim + 9)))
|
||||
wsRule.m_noRounding = !*X;
|
||||
} else if ((delim = rule.find("decorate:")) != std::string::npos) {
|
||||
CHECK_OR_THROW(configStringToInt(rule.substr(delim + 9)))
|
||||
CHECK_OR_THROW(ParserUtils::parseInt(rule.substr(delim + 9)))
|
||||
wsRule.m_decorate = *X;
|
||||
} else if ((delim = rule.find("monitor:")) != std::string::npos)
|
||||
wsRule.m_monitor = rule.substr(delim + 8);
|
||||
else if ((delim = rule.find("default:")) != std::string::npos) {
|
||||
CHECK_OR_THROW(configStringToInt(rule.substr(delim + 8)))
|
||||
CHECK_OR_THROW(ParserUtils::parseInt(rule.substr(delim + 8)))
|
||||
wsRule.m_isDefault = *X;
|
||||
} else if ((delim = rule.find("persistent:")) != std::string::npos) {
|
||||
CHECK_OR_THROW(configStringToInt(rule.substr(delim + 11)))
|
||||
CHECK_OR_THROW(ParserUtils::parseInt(rule.substr(delim + 11)))
|
||||
wsRule.m_isPersistent = *X;
|
||||
} else if ((delim = rule.find("defaultName:")) != std::string::npos)
|
||||
wsRule.m_defaultName = trim(rule.substr(delim + 12));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "LuaBindingsInternal.hpp"
|
||||
|
||||
#include "../objects/LuaNotification.hpp"
|
||||
#include "../../shared/parserUtils/ParserUtils.hpp"
|
||||
|
||||
#include "../../../helpers/MiscFunctions.hpp"
|
||||
#include "../../../notification/NotificationOverlay.hpp"
|
||||
|
|
@ -52,7 +53,7 @@ static std::optional<CHyprColor> parseColorArg(lua_State* L, int idx) {
|
|||
return CHyprColor(sc<uint64_t>(lua_tonumber(L, idx)));
|
||||
|
||||
if (lua_isstring(L, idx)) {
|
||||
auto parsed = configStringToInt(lua_tostring(L, idx));
|
||||
auto parsed = ParserUtils::parseColor(lua_tostring(L, idx));
|
||||
if (!parsed)
|
||||
return std::nullopt;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "../../shared/parserUtils/ParserUtils.hpp"
|
||||
|
||||
using namespace Config;
|
||||
using namespace Config::Lua;
|
||||
|
||||
static constexpr const char* MT = "HL.Notification";
|
||||
|
|
@ -23,7 +26,7 @@ namespace {
|
|||
return CHyprColor(sc<uint64_t>(lua_tonumber(L, idx)));
|
||||
|
||||
if (lua_isstring(L, idx)) {
|
||||
auto parsed = configStringToInt(lua_tostring(L, idx));
|
||||
auto parsed = ParserUtils::parseColor(lua_tostring(L, idx));
|
||||
if (!parsed)
|
||||
return std::nullopt;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
#include <expected>
|
||||
#include <format>
|
||||
|
||||
#include "../../shared/parserUtils/ParserUtils.hpp"
|
||||
|
||||
#include "../../../helpers/Color.hpp"
|
||||
#include "../../../helpers/MiscFunctions.hpp"
|
||||
|
||||
|
|
@ -10,7 +12,7 @@ using namespace Config;
|
|||
using namespace Config::Lua;
|
||||
|
||||
static std::expected<CHyprColor, std::string> parseColorString(const std::string& str) {
|
||||
auto result = configStringToInt(str);
|
||||
auto result = ParserUtils::parseColor(str);
|
||||
if (!result)
|
||||
return std::unexpected(std::format("invalid color \"{}\"", str));
|
||||
return CHyprColor(sc<uint64_t>(*result));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "LuaConfigGradient.hpp"
|
||||
#include "../../shared/parserUtils/ParserUtils.hpp"
|
||||
#include "../../../helpers/MiscFunctions.hpp"
|
||||
|
||||
#include <numbers>
|
||||
|
|
@ -7,7 +8,7 @@ using namespace Config;
|
|||
using namespace Config::Lua;
|
||||
|
||||
static std::expected<CHyprColor, std::string> parseColorString(const std::string& str) {
|
||||
auto result = configStringToInt(str);
|
||||
auto result = ParserUtils::parseColor(str);
|
||||
if (!result)
|
||||
return std::unexpected(std::format("invalid color \"{}\"", str));
|
||||
return CHyprColor(sc<uint64_t>(*result));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "ConfigActions.hpp"
|
||||
#include "../parserUtils/ParserUtils.hpp"
|
||||
#include "../../../desktop/state/FocusState.hpp"
|
||||
#include "../../../desktop/view/Window.hpp"
|
||||
#include "../../../desktop/view/Group.hpp"
|
||||
|
|
@ -726,15 +727,15 @@ ActionResult Actions::setProp(const std::string& PROP, const std::string& VAL, s
|
|||
if (TOKEN.ends_with("deg"))
|
||||
colorData.m_angle = std::stoi(std::string(TOKEN.substr(0, TOKEN.size() - 3))) * (PI / 180.0);
|
||||
else
|
||||
configStringToInt(std::string(TOKEN)).and_then([&colorData](const auto& e) {
|
||||
ParserUtils::parseColor(std::string(TOKEN)).and_then([&colorData](const auto& e) {
|
||||
colorData.m_colors.push_back(e);
|
||||
return std::invoke_result_t<decltype(::configStringToInt), const std::string&>(1);
|
||||
return std::invoke_result_t<decltype(ParserUtils::parseColor), const std::string&>(1);
|
||||
});
|
||||
}
|
||||
} else if (VAL != "-1")
|
||||
configStringToInt(VAL).and_then([&colorData](const auto& e) {
|
||||
ParserUtils::parseColor(VAL).and_then([&colorData](const auto& e) {
|
||||
colorData.m_colors.push_back(e);
|
||||
return std::invoke_result_t<decltype(::configStringToInt), const std::string&>(1);
|
||||
return std::invoke_result_t<decltype(ParserUtils::parseColor), const std::string&>(1);
|
||||
});
|
||||
|
||||
colorData.updateColorsOk();
|
||||
|
|
@ -754,15 +755,15 @@ ActionResult Actions::setProp(const std::string& PROP, const std::string& VAL, s
|
|||
Desktop::Types::SAlphaValue{std::stof(VAL), PWINDOW->m_ruleApplicator->alphaFullscreen().valueOrDefault().overridden}, Desktop::Types::PRIORITY_SET_PROP));
|
||||
} else if (PROP == "opacity_override") {
|
||||
PWINDOW->m_ruleApplicator->alphaOverride(Desktop::Types::COverridableVar(
|
||||
Desktop::Types::SAlphaValue{PWINDOW->m_ruleApplicator->alpha().valueOrDefault().alpha, sc<bool>(configStringToInt(VAL).value_or(0))},
|
||||
Desktop::Types::SAlphaValue{PWINDOW->m_ruleApplicator->alpha().valueOrDefault().alpha, sc<bool>(ParserUtils::parseInt(VAL).value_or(0))},
|
||||
Desktop::Types::PRIORITY_SET_PROP));
|
||||
} else if (PROP == "opacity_inactive_override") {
|
||||
PWINDOW->m_ruleApplicator->alphaInactiveOverride(Desktop::Types::COverridableVar(
|
||||
Desktop::Types::SAlphaValue{PWINDOW->m_ruleApplicator->alphaInactive().valueOrDefault().alpha, sc<bool>(configStringToInt(VAL).value_or(0))},
|
||||
Desktop::Types::SAlphaValue{PWINDOW->m_ruleApplicator->alphaInactive().valueOrDefault().alpha, sc<bool>(ParserUtils::parseInt(VAL).value_or(0))},
|
||||
Desktop::Types::PRIORITY_SET_PROP));
|
||||
} else if (PROP == "opacity_fullscreen_override") {
|
||||
PWINDOW->m_ruleApplicator->alphaFullscreenOverride(Desktop::Types::COverridableVar(
|
||||
Desktop::Types::SAlphaValue{PWINDOW->m_ruleApplicator->alphaFullscreen().valueOrDefault().alpha, sc<bool>(configStringToInt(VAL).value_or(0))},
|
||||
Desktop::Types::SAlphaValue{PWINDOW->m_ruleApplicator->alphaFullscreen().valueOrDefault().alpha, sc<bool>(ParserUtils::parseInt(VAL).value_or(0))},
|
||||
Desktop::Types::PRIORITY_SET_PROP));
|
||||
} else if (PROP == "allows_input")
|
||||
parsePropTrivial(PWINDOW->m_ruleApplicator->allowsInput(), VAL);
|
||||
|
|
|
|||
150
src/config/shared/parserUtils/ParserUtils.cpp
Normal file
150
src/config/shared/parserUtils/ParserUtils.cpp
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
#include "ParserUtils.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/string/Numeric.hpp>
|
||||
|
||||
#include <format>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include "../../../helpers/memory/Memory.hpp"
|
||||
|
||||
using namespace Config;
|
||||
using namespace Config::ParserUtils;
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
static std::expected<uint64_t, std::string> parseHex(std::string_view value) {
|
||||
auto res = value.starts_with("0x") ? strToNumber<uint64_t>(value) : strToNumber<uint64_t>(std::string{"0x"} + value);
|
||||
if (!res)
|
||||
return std::unexpected(std::format("invalid hex \"{}\"", value));
|
||||
return *res;
|
||||
}
|
||||
|
||||
std::expected<int64_t, std::string> ParserUtils::parseColor(std::string_view val) {
|
||||
|
||||
if (val.starts_with("#")) {
|
||||
// parse either rgb or rgba
|
||||
val = val.substr(1);
|
||||
|
||||
if (val.length() != 6 && val.length() != 8 && val.length() != 3)
|
||||
return std::unexpected(std::format("couldn't parse \"{}\" as a color", val));
|
||||
|
||||
if (val.length() == 3) {
|
||||
auto r = parseHex(val.substr(0, 1));
|
||||
auto g = parseHex(val.substr(1, 1));
|
||||
auto b = parseHex(val.substr(2, 1));
|
||||
|
||||
if (!r || !g || !b)
|
||||
return std::unexpected(std::format("couldn't parse \"{}\" as a color (bad hex)", val));
|
||||
|
||||
return 0xFF000000 | ((*r | (*r << 4)) << 16) | ((*g | (*g << 4)) << 8) | (*b | (*b << 4));
|
||||
}
|
||||
|
||||
if (val.length() == 6) {
|
||||
auto r = parseHex(val.substr(0, 2));
|
||||
auto g = parseHex(val.substr(2, 2));
|
||||
auto b = parseHex(val.substr(4, 2));
|
||||
|
||||
if (!r || !g || !b)
|
||||
return std::unexpected(std::format("couldn't parse \"{}\" as a color (bad hex)", val));
|
||||
|
||||
return 0xFF000000 | (*r << 16) | (*g << 8) | *b;
|
||||
}
|
||||
|
||||
if (val.length() == 8) {
|
||||
auto r = parseHex(val.substr(0, 2));
|
||||
auto g = parseHex(val.substr(2, 2));
|
||||
auto b = parseHex(val.substr(4, 2));
|
||||
auto a = parseHex(val.substr(6, 2));
|
||||
|
||||
if (!r || !g || !b || !a)
|
||||
return std::unexpected(std::format("couldn't parse \"{}\" as a color (bad hex)", val));
|
||||
|
||||
return (*a << 24) | (*r << 16) | (*g << 8) | *b;
|
||||
}
|
||||
}
|
||||
|
||||
if (val.starts_with("0x"))
|
||||
return parseHex(val);
|
||||
|
||||
if (val.starts_with("rgba(") && val.ends_with(')')) {
|
||||
const auto VALUEWITHOUTFUNC = trim(val.substr(5, val.length() - 6));
|
||||
|
||||
// try doing it the comma way first
|
||||
if (std::ranges::count(VALUEWITHOUTFUNC, ',') == 3) {
|
||||
// cool
|
||||
std::string_view rolling = VALUEWITHOUTFUNC;
|
||||
auto r = strToNumber<uint8_t>(trim(rolling.substr(0, rolling.find(','))));
|
||||
rolling = rolling.substr(rolling.find(',') + 1);
|
||||
auto g = strToNumber<uint8_t>(trim(rolling.substr(0, rolling.find(','))));
|
||||
rolling = rolling.substr(rolling.find(',') + 1);
|
||||
auto b = strToNumber<uint8_t>(trim(rolling.substr(0, rolling.find(','))));
|
||||
rolling = rolling.substr(rolling.find(',') + 1);
|
||||
auto a = strToNumber<float>(trim(rolling.substr(0, rolling.find(','))));
|
||||
|
||||
if (!r || !g || !b || !a)
|
||||
return std::unexpected(std::format("failed parsing \"{}\" as a color", val));
|
||||
|
||||
return (sc<uint64_t>(std::floor(*a * 255.F)) << 24) | (*r << 16) | (*g << 8) | *b;
|
||||
} else if (VALUEWITHOUTFUNC.length() == 8) {
|
||||
const auto RGBA = parseHex(VALUEWITHOUTFUNC);
|
||||
|
||||
if (!RGBA)
|
||||
return RGBA;
|
||||
// now we need to RGBA -> ARGB. The config holds ARGB only.
|
||||
return (*RGBA >> 8) + (0x1000000 * (*RGBA & 0xFF));
|
||||
}
|
||||
|
||||
return std::unexpected("rgba() expects length of 8 characters (4 bytes) or 4 comma separated values");
|
||||
}
|
||||
|
||||
if (val.starts_with("rgb(") && val.ends_with(')')) {
|
||||
const auto VALUEWITHOUTFUNC = trim(val.substr(4, val.length() - 5));
|
||||
|
||||
// try doing it the comma way first
|
||||
if (std::ranges::count(VALUEWITHOUTFUNC, ',') == 2) {
|
||||
// cool
|
||||
std::string_view rolling = VALUEWITHOUTFUNC;
|
||||
auto r = strToNumber<uint8_t>(trim(rolling.substr(0, rolling.find(','))));
|
||||
rolling = rolling.substr(rolling.find(',') + 1);
|
||||
auto g = strToNumber<uint8_t>(trim(rolling.substr(0, rolling.find(','))));
|
||||
rolling = rolling.substr(rolling.find(',') + 1);
|
||||
auto b = strToNumber<uint8_t>(trim(rolling.substr(0, rolling.find(','))));
|
||||
|
||||
if (!r || !g || !b)
|
||||
return std::unexpected(std::format("failed parsing \"{}\" as a color", val));
|
||||
|
||||
return 0xFF000000 | (*r << 16) | (*g << 8) | *b;
|
||||
} else if (VALUEWITHOUTFUNC.length() == 6) {
|
||||
const auto r = parseHex(VALUEWITHOUTFUNC);
|
||||
return r ? *r + 0xFF000000 : r;
|
||||
}
|
||||
|
||||
return std::unexpected("rgb() expects length of 6 characters (3 bytes) or 3 comma separated values");
|
||||
}
|
||||
|
||||
if (isNumber2(val)) {
|
||||
if (const auto v = strToNumber<uint32_t>(val); v)
|
||||
return *v;
|
||||
}
|
||||
|
||||
return std::unexpected(std::format("cannot parse \"{}\" as a color", val));
|
||||
}
|
||||
|
||||
std::expected<int64_t, std::string> ParserUtils::parseInt(std::string_view val) {
|
||||
if (val.starts_with("0x"))
|
||||
return parseHex(val);
|
||||
|
||||
if (val.starts_with("true") || val.starts_with("on") || val.starts_with("yes"))
|
||||
return 1;
|
||||
|
||||
if (val.starts_with("false") || val.starts_with("off") || val.starts_with("no"))
|
||||
return 0;
|
||||
|
||||
auto res = strToNumber<int64_t>(val);
|
||||
|
||||
if (!res)
|
||||
return std::unexpected(std::format("Failed to parse \"{}\" as an integer", val));
|
||||
|
||||
return *res;
|
||||
}
|
||||
10
src/config/shared/parserUtils/ParserUtils.hpp
Normal file
10
src/config/shared/parserUtils/ParserUtils.hpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace Config::ParserUtils {
|
||||
std::expected<int64_t, std::string> parseColor(std::string_view val);
|
||||
std::expected<int64_t, std::string> parseInt(std::string_view val);
|
||||
};
|
||||
|
|
@ -36,6 +36,7 @@ using namespace Hyprutils::OS;
|
|||
#include "../config/legacy/ConfigManager.hpp"
|
||||
#include "../config/lua/ConfigManager.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../config/shared/parserUtils/ParserUtils.hpp"
|
||||
#include "../config/shared/complex/ComplexDataTypes.hpp"
|
||||
#include "../config/shared/inotify/ConfigWatcher.hpp"
|
||||
#include "../config/shared/workspace/WorkspaceRuleManager.hpp"
|
||||
|
|
@ -1404,7 +1405,7 @@ static std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string req
|
|||
return "ok";
|
||||
}
|
||||
|
||||
const CHyprColor COLOR = configStringToInt(vars[1]).value_or(0);
|
||||
const CHyprColor COLOR = Config::ParserUtils::parseColor(vars[1]).value_or(0);
|
||||
|
||||
for (size_t i = 2; i < vars.size(); ++i)
|
||||
errorMessage += vars[i] + ' ';
|
||||
|
|
@ -1871,7 +1872,7 @@ static std::string dispatchNotify(eHyprCtlOutputFormat format, std::string reque
|
|||
time = std::stoi(TIME);
|
||||
} catch (std::exception& e) { return "invalid arg 2"; }
|
||||
|
||||
const auto COLOR_RESULT = configStringToInt(vars[3]);
|
||||
const auto COLOR_RESULT = Config::ParserUtils::parseColor(vars[3]);
|
||||
if (!COLOR_RESULT)
|
||||
return "invalid arg 3";
|
||||
CHyprColor color = *COLOR_RESULT;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "view/Group.hpp"
|
||||
#include "view/LayerSurface.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../config/shared/parserUtils/ParserUtils.hpp"
|
||||
#include "../config/shared/animation/AnimationTree.hpp"
|
||||
#include "../config/shared/workspace/WorkspaceRuleManager.hpp"
|
||||
#include "../config/supplementary/executor/Executor.hpp"
|
||||
|
|
@ -199,7 +200,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
|
|||
|
||||
prop = prop.substr(2, prop.length() - 3);
|
||||
|
||||
const auto SHOULDBESPECIAL = configStringToInt(prop);
|
||||
const auto SHOULDBESPECIAL = Config::ParserUtils::parseInt(prop);
|
||||
|
||||
if (SHOULDBESPECIAL && sc<bool>(*SHOULDBESPECIAL) != m_isSpecialWorkspace)
|
||||
return false;
|
||||
|
|
@ -234,7 +235,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
|
|||
if (prop.starts_with("e:") && !m_name.ends_with(prop.substr(2)))
|
||||
return false;
|
||||
|
||||
const auto WANTSNAMED = configStringToInt(prop);
|
||||
const auto WANTSNAMED = Config::ParserUtils::parseInt(prop);
|
||||
|
||||
if (WANTSNAMED && *WANTSNAMED != (m_id <= -1337))
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "../../../managers/TokenManager.hpp"
|
||||
#include "../../../desktop/state/FocusState.hpp"
|
||||
#include "../../../protocols/types/ContentType.hpp"
|
||||
#include "../../../config/shared/parserUtils/ParserUtils.hpp"
|
||||
|
||||
#include <hyprutils/string/Numeric.hpp>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
|
|
@ -45,7 +46,7 @@ static std::expected<float, std::string> parseFloat(std::string_view effectName,
|
|||
}
|
||||
|
||||
static std::expected<CHyprColor, std::string> parseBorderColorToken(const std::string& raw, const std::string& token) {
|
||||
auto parsed = configStringToInt(token);
|
||||
auto parsed = Config::ParserUtils::parseColor(token);
|
||||
if (!parsed)
|
||||
return std::unexpected(std::format(R"(border_color rule "{}" has invalid color "{}": {})", raw, token, parsed.error()));
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#include "../defines.hpp"
|
||||
#include "../render/Texture.hpp"
|
||||
#include "../helpers/AnimatedVariable.hpp"
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
#include "../config/shared/complex/ComplexDataTypes.hpp"
|
||||
|
||||
namespace ErrorOverlay {
|
||||
|
|
@ -13,10 +12,8 @@ namespace ErrorOverlay {
|
|||
namespace Colors {
|
||||
constexpr const float ANGLE_30 = 0.52359877;
|
||||
|
||||
static const Config::CGradientValueData ERROR =
|
||||
Config::CGradientValueData{std::vector<CHyprColor>{*configStringToInt("0xffff6666"), *configStringToInt("0xff800000")}, ANGLE_30};
|
||||
static const Config::CGradientValueData WARNING =
|
||||
Config::CGradientValueData{std::vector<CHyprColor>{*configStringToInt("0xffffdb4d"), *configStringToInt("0xff665200")}, ANGLE_30};
|
||||
static const Config::CGradientValueData ERROR = Config::CGradientValueData{std::vector<CHyprColor>{0xffff6666, 0xff800000}, ANGLE_30};
|
||||
static const Config::CGradientValueData WARNING = Config::CGradientValueData{std::vector<CHyprColor>{0xffffdb4d, 0xff665200}, ANGLE_30};
|
||||
};
|
||||
|
||||
class COverlay {
|
||||
|
|
|
|||
|
|
@ -572,119 +572,6 @@ int64_t getPPIDof(int64_t pid) {
|
|||
#endif
|
||||
}
|
||||
|
||||
std::expected<int64_t, std::string> configStringToInt(const std::string& VALUE) {
|
||||
auto parseHex = [](const std::string& value) -> std::expected<int64_t, std::string> {
|
||||
try {
|
||||
size_t position;
|
||||
auto result = stoll(value, &position, 16);
|
||||
if (position == value.size())
|
||||
return result;
|
||||
} catch (const std::exception&) {}
|
||||
return std::unexpected("invalid hex " + value);
|
||||
};
|
||||
if (VALUE.starts_with("0x")) {
|
||||
// Values with 0x are hex
|
||||
return parseHex(VALUE);
|
||||
} else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) {
|
||||
const auto VALUEWITHOUTFUNC = trim(VALUE.substr(5, VALUE.length() - 6));
|
||||
|
||||
// try doing it the comma way first
|
||||
if (std::ranges::count(VALUEWITHOUTFUNC, ',') == 3) {
|
||||
// cool
|
||||
std::string rolling = VALUEWITHOUTFUNC;
|
||||
auto r = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
|
||||
rolling = rolling.substr(rolling.find(',') + 1);
|
||||
auto g = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
|
||||
rolling = rolling.substr(rolling.find(',') + 1);
|
||||
auto b = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
|
||||
rolling = rolling.substr(rolling.find(',') + 1);
|
||||
uint8_t a = 0;
|
||||
|
||||
if (!r || !g || !b)
|
||||
return std::unexpected("failed parsing " + VALUEWITHOUTFUNC);
|
||||
|
||||
try {
|
||||
a = std::round(std::stof(trim(rolling.substr(0, rolling.find(',')))) * 255.f);
|
||||
} catch (std::exception& e) { return std::unexpected("failed parsing " + VALUEWITHOUTFUNC); }
|
||||
|
||||
return a * sc<Config::INTEGER>(0x1000000) + *r * sc<Config::INTEGER>(0x10000) + *g * sc<Config::INTEGER>(0x100) + *b;
|
||||
} else if (VALUEWITHOUTFUNC.length() == 8) {
|
||||
const auto RGBA = parseHex(VALUEWITHOUTFUNC);
|
||||
|
||||
if (!RGBA)
|
||||
return RGBA;
|
||||
// now we need to RGBA -> ARGB. The config holds ARGB only.
|
||||
return (*RGBA >> 8) + 0x1000000 * (*RGBA & 0xFF);
|
||||
}
|
||||
|
||||
return std::unexpected("rgba() expects length of 8 characters (4 bytes) or 4 comma separated values");
|
||||
|
||||
} else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) {
|
||||
const auto VALUEWITHOUTFUNC = trim(VALUE.substr(4, VALUE.length() - 5));
|
||||
|
||||
// try doing it the comma way first
|
||||
if (std::ranges::count(VALUEWITHOUTFUNC, ',') == 2) {
|
||||
// cool
|
||||
std::string rolling = VALUEWITHOUTFUNC;
|
||||
auto r = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
|
||||
rolling = rolling.substr(rolling.find(',') + 1);
|
||||
auto g = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
|
||||
rolling = rolling.substr(rolling.find(',') + 1);
|
||||
auto b = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
|
||||
|
||||
if (!r || !g || !b)
|
||||
return std::unexpected("failed parsing " + VALUEWITHOUTFUNC);
|
||||
|
||||
return sc<Config::INTEGER>(0xFF000000) + *r * sc<Config::INTEGER>(0x10000) + *g * sc<Config::INTEGER>(0x100) + *b;
|
||||
} else if (VALUEWITHOUTFUNC.length() == 6) {
|
||||
auto r = parseHex(VALUEWITHOUTFUNC);
|
||||
return r ? *r + 0xFF000000 : r;
|
||||
}
|
||||
|
||||
return std::unexpected("rgb() expects length of 6 characters (3 bytes) or 3 comma separated values");
|
||||
} else if (VALUE.starts_with("true") || VALUE.starts_with("on") || VALUE.starts_with("yes")) {
|
||||
return 1;
|
||||
} else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (VALUE.empty() || !isNumber(VALUE, false))
|
||||
return std::unexpected("cannot parse \"" + VALUE + "\" as an int.");
|
||||
|
||||
try {
|
||||
const auto RES = std::stoll(VALUE);
|
||||
return RES;
|
||||
} catch (std::exception& e) { return std::unexpected(std::string{"stoll threw: "} + e.what()); }
|
||||
|
||||
return std::unexpected("parse error");
|
||||
}
|
||||
|
||||
Vector2D configStringToVector2D(const std::string& VALUE) {
|
||||
std::istringstream iss(VALUE);
|
||||
std::string token;
|
||||
|
||||
if (!std::getline(iss, token, ' ') && !std::getline(iss, token, ','))
|
||||
throw std::invalid_argument("Invalid string format");
|
||||
|
||||
if (!isNumber(token))
|
||||
throw std::invalid_argument("Invalid x value");
|
||||
|
||||
long long x = std::stoll(token);
|
||||
|
||||
if (!std::getline(iss, token))
|
||||
throw std::invalid_argument("Invalid string format");
|
||||
|
||||
if (!isNumber(token))
|
||||
throw std::invalid_argument("Invalid y value");
|
||||
|
||||
long long y = std::stoll(token);
|
||||
|
||||
if (std::getline(iss, token))
|
||||
throw std::invalid_argument("Invalid string format");
|
||||
|
||||
return Vector2D(sc<double>(x), sc<double>(y));
|
||||
}
|
||||
|
||||
double normalizeAngleRad(double ang) {
|
||||
if (ang > M_PI * 2) {
|
||||
while (ang > M_PI * 2)
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ std::optional<std::string> cleanCmdForWorkspace(const std::string&,
|
|||
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
|
||||
std::string execAndGet(const char*);
|
||||
int64_t getPPIDof(int64_t pid);
|
||||
std::expected<int64_t, std::string> configStringToInt(const std::string&);
|
||||
Vector2D configStringToVector2D(const std::string&);
|
||||
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
|
||||
double normalizeAngleRad(double ang);
|
||||
std::vector<SCallstackFrameInfo> getBacktrace();
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/string/Numeric.hpp>
|
||||
#include <hyprutils/os/Process.hpp>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
|
|
@ -62,13 +63,13 @@ CVersionKeeperManager::CVersionKeeperManager() {
|
|||
bool CVersionKeeperManager::isMajorVersionOlderThanRunning(const std::string& ver) {
|
||||
const CVarList verStrings(ver, 0, '.', true);
|
||||
|
||||
const int V1 = configStringToInt(verStrings[0]).value_or(0);
|
||||
const int V2 = configStringToInt(verStrings[1]).value_or(0);
|
||||
const int V1 = strToNumber<uint32_t>(verStrings[0]).value_or(0);
|
||||
const int V2 = strToNumber<uint32_t>(verStrings[1]).value_or(0);
|
||||
|
||||
static const CVarList runningStrings(HYPRLAND_VERSION, 0, '.', true);
|
||||
|
||||
static const int R1 = configStringToInt(runningStrings[0]).value_or(0);
|
||||
static const int R2 = configStringToInt(runningStrings[1]).value_or(0);
|
||||
static const int R1 = strToNumber<uint32_t>(runningStrings[0]).value_or(0);
|
||||
static const int R2 = strToNumber<uint32_t>(runningStrings[1]).value_or(0);
|
||||
|
||||
if (R1 > V1)
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <hyprutils/string/Numeric.hpp>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
CFunctionHook::CFunctionHook(HANDLE owner, void* source, void* destination) : m_source(source), m_destination(destination), m_owner(owner) {
|
||||
;
|
||||
}
|
||||
|
|
@ -92,7 +96,7 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr
|
|||
size_t plusPresent = tokens[1][0] == '+' ? 1 : 0;
|
||||
size_t minusPresent = tokens[1][0] == '-' ? 1 : 0;
|
||||
std::string addr = tokens[1].substr((plusPresent || minusPresent), tokens[1].find("(%rip)") - (plusPresent || minusPresent));
|
||||
auto addrResult = configStringToInt(addr);
|
||||
auto addrResult = strToNumber<int64_t>(addr);
|
||||
if (!addrResult)
|
||||
return {};
|
||||
const int32_t OFFSET = (minusPresent ? -1 : 1) * *addrResult;
|
||||
|
|
|
|||
69
tests/config/shared/ParserUtils.cpp
Normal file
69
tests/config/shared/ParserUtils.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
|
||||
#include <config/shared/parserUtils/ParserUtils.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace Config;
|
||||
|
||||
TEST(ParserUtils, parseIntDecimal) {
|
||||
EXPECT_EQ(ParserUtils::parseInt("42").value(), 42);
|
||||
EXPECT_EQ(ParserUtils::parseInt("0").value(), 0);
|
||||
EXPECT_EQ(ParserUtils::parseInt("-1").value(), -1);
|
||||
}
|
||||
|
||||
TEST(ParserUtils, parseIntHex) {
|
||||
EXPECT_EQ(ParserUtils::parseInt("0xFF").value(), 255);
|
||||
EXPECT_EQ(ParserUtils::parseInt("0x00").value(), 0);
|
||||
EXPECT_EQ(ParserUtils::parseInt("0x10").value(), 16);
|
||||
}
|
||||
|
||||
TEST(ParserUtils, parseIntBooleanStrings) {
|
||||
// "true", "yes", "on" -> 1; "false", "no", "off" -> 0
|
||||
EXPECT_EQ(ParserUtils::parseInt("true").value(), 1);
|
||||
EXPECT_EQ(ParserUtils::parseInt("yes").value(), 1);
|
||||
EXPECT_EQ(ParserUtils::parseInt("on").value(), 1);
|
||||
EXPECT_EQ(ParserUtils::parseInt("false").value(), 0);
|
||||
EXPECT_EQ(ParserUtils::parseInt("no").value(), 0);
|
||||
EXPECT_EQ(ParserUtils::parseInt("off").value(), 0);
|
||||
}
|
||||
|
||||
TEST(ParserUtils, parseIntInvalid) {
|
||||
EXPECT_FALSE(ParserUtils::parseInt("").has_value());
|
||||
EXPECT_FALSE(ParserUtils::parseInt("abc").has_value());
|
||||
EXPECT_FALSE(ParserUtils::parseInt("rgba(20,20,20,5)").has_value());
|
||||
EXPECT_FALSE(ParserUtils::parseInt("#fff").has_value());
|
||||
}
|
||||
|
||||
TEST(ParserUtils, parseColor) {
|
||||
EXPECT_EQ(ParserUtils::parseColor("0xDEADBEEF").value_or(0), 0xDEADBEEF);
|
||||
EXPECT_EQ(ParserUtils::parseColor("rgba(20, 21, 22, 0.5)").value_or(0), 0x7F141516);
|
||||
EXPECT_EQ(ParserUtils::parseColor("rgb(20, 21, 22)").value_or(0), 0xFF141516);
|
||||
EXPECT_EQ(ParserUtils::parseColor("rgb(141516)").value_or(0), 0xFF141516);
|
||||
EXPECT_EQ(ParserUtils::parseColor("rgba(1415167f)").value_or(0), 0x7F141516);
|
||||
EXPECT_EQ(ParserUtils::parseColor("4279506198").value_or(0), 0xFF141516);
|
||||
EXPECT_EQ(ParserUtils::parseColor("1").value_or(0), 0x1);
|
||||
EXPECT_EQ(ParserUtils::parseColor("#fed").value_or(0), 0xFFFFEEDD);
|
||||
EXPECT_EQ(ParserUtils::parseColor("#FED").value_or(0), 0xFFFFEEDD);
|
||||
EXPECT_EQ(ParserUtils::parseColor("#deffad").value_or(0), 0xFFDEFFAD);
|
||||
EXPECT_EQ(ParserUtils::parseColor("#DEFFaD").value_or(0), 0xFFDEFFAD);
|
||||
EXPECT_EQ(ParserUtils::parseColor("#DEFFaDAA").value_or(0), 0xAADEFFAD);
|
||||
EXPECT_EQ(ParserUtils::parseColor("#DEFFaDaa").value_or(0), 0xAADEFFAD);
|
||||
}
|
||||
|
||||
TEST(ParserUtils, parseColorBad) {
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("mak"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("true"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("on"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("fucker"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("I sniff glue"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("0DEADBEEF"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("6270000000"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("rgba(20, 21, 22)"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("rgb(20, 21, 22, 0.2)"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("#afed"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("#FE"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("#defd"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("#DEFFD"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("#DEFFaDAAe"));
|
||||
EXPECT_FALSE(!!ParserUtils::parseColor("#DEFFaDa"));
|
||||
}
|
||||
|
|
@ -97,49 +97,3 @@ TEST(Helpers, truthyFalse) {
|
|||
EXPECT_FALSE(truthy(""));
|
||||
EXPECT_FALSE(truthy("random"));
|
||||
}
|
||||
|
||||
// configStringToInt
|
||||
|
||||
TEST(Helpers, configStringToIntDecimal) {
|
||||
EXPECT_EQ(configStringToInt("42").value(), 42);
|
||||
EXPECT_EQ(configStringToInt("0").value(), 0);
|
||||
EXPECT_EQ(configStringToInt("-1").value(), -1);
|
||||
}
|
||||
|
||||
TEST(Helpers, configStringToIntHex) {
|
||||
EXPECT_EQ(configStringToInt("0xFF").value(), 255);
|
||||
EXPECT_EQ(configStringToInt("0x00").value(), 0);
|
||||
EXPECT_EQ(configStringToInt("0x10").value(), 16);
|
||||
}
|
||||
|
||||
TEST(Helpers, configStringToIntRgba) {
|
||||
auto result = configStringToInt("rgba(255, 0, 0, 1.0)");
|
||||
EXPECT_TRUE(result.has_value());
|
||||
}
|
||||
|
||||
TEST(Helpers, configStringToIntBooleanStrings) {
|
||||
// "true", "yes", "on" -> 1; "false", "no", "off" -> 0
|
||||
EXPECT_EQ(configStringToInt("true").value(), 1);
|
||||
EXPECT_EQ(configStringToInt("yes").value(), 1);
|
||||
EXPECT_EQ(configStringToInt("on").value(), 1);
|
||||
EXPECT_EQ(configStringToInt("false").value(), 0);
|
||||
EXPECT_EQ(configStringToInt("no").value(), 0);
|
||||
EXPECT_EQ(configStringToInt("off").value(), 0);
|
||||
}
|
||||
|
||||
TEST(Helpers, configStringToIntInvalid) {
|
||||
EXPECT_FALSE(configStringToInt("").has_value());
|
||||
EXPECT_FALSE(configStringToInt("abc").has_value());
|
||||
}
|
||||
|
||||
// configStringToVector2D
|
||||
|
||||
TEST(Helpers, configStringToVector2DValid) {
|
||||
EXPECT_EQ(configStringToVector2D("1920 1080"), Vector2D(1920, 1080));
|
||||
EXPECT_EQ(configStringToVector2D("0 0"), Vector2D(0, 0));
|
||||
}
|
||||
|
||||
TEST(Helpers, configStringToVector2DInvalid) {
|
||||
EXPECT_THROW(configStringToVector2D("notvalid"), std::invalid_argument);
|
||||
EXPECT_THROW(configStringToVector2D(""), std::invalid_argument);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue