config/lua: report errors better without check* (#14695)

This commit is contained in:
Vaxry
2026-05-22 10:39:15 +01:00
committed by GitHub
parent 4c89bfc2c9
commit c5154131b1
9 changed files with 232 additions and 61 deletions
+52
View File
@@ -0,0 +1,52 @@
#include "Check.hpp"
#include <format>
using namespace Config::Lua;
using namespace Config::Lua::Bindings;
static const char* idxType(lua_State* L, int idx) {
if (lua_isstring(L, idx))
return "string";
if (lua_isnoneornil(L, idx))
return "nil";
if (lua_isboolean(L, idx))
return "bool";
if (lua_isfunction(L, idx))
return "function";
if (lua_istable(L, idx))
return "table";
if (lua_isnumber(L, idx))
return "number";
if (lua_isinteger(L, idx))
return "integer";
return "?";
}
std::expected<std::string, std::string> Check::string(lua_State* L, int idx) {
if (!lua_isstring(L, idx))
return std::unexpected(std::format("expected string, got {}", idxType(L, idx)));
return lua_tostring(L, idx);
}
std::expected<int64_t, std::string> Check::integer(lua_State* L, int idx) {
if (!lua_isinteger(L, idx))
return std::unexpected(std::format("expected integer, got {}", idxType(L, idx)));
return lua_tointeger(L, idx);
}
std::expected<double, std::string> Check::number(lua_State* L, int idx) {
if (!lua_isnumber(L, idx))
return std::unexpected(std::format("expected number, got {}", idxType(L, idx)));
return lua_tonumber(L, idx);
}
std::expected<bool, std::string> Check::boolean(lua_State* L, int idx) {
if (!lua_isboolean(L, idx))
return std::unexpected(std::format("expected boolean, got {}", idxType(L, idx)));
return lua_toboolean(L, idx);
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <string>
#include <cstdint>
#include <expected>
extern "C" {
#include <lua.h>
}
namespace Config::Lua::Bindings::Check {
std::expected<std::string, std::string> string(lua_State* L, int idx);
std::expected<int64_t, std::string> integer(lua_State* L, int idx);
std::expected<double, std::string> number(lua_State* L, int idx);
std::expected<bool, std::string> boolean(lua_State* L, int idx);
};
@@ -1,4 +1,5 @@
#include "LuaBindingsInternal.hpp"
#include "Check.hpp"
#include "../objects/LuaLayerRule.hpp"
#include "../objects/LuaWindowRule.hpp"
@@ -569,9 +570,16 @@ static int hlPermission(lua_State* L) {
typeStr = *t;
modeStr = *m;
} else {
binary = luaL_checkstring(L, 1);
typeStr = luaL_checkstring(L, 2);
modeStr = luaL_checkstring(L, 3);
auto b = Check::string(L, 1);
auto t = Check::string(L, 2);
auto m = Check::string(L, 3);
if (!b || !t || !m)
return Internal::configError(L, "hl.permission: expected binary, type, mode");
binary = *b;
typeStr = *t;
modeStr = *m;
}
if (binary.empty())
@@ -910,9 +918,13 @@ static int hlConfig(lua_State* L) {
}
static int hlGetConfig(lua_State* L) {
auto* self = sc<CConfigManager*>(lua_touserdata(L, lua_upvalueindex(1)));
auto* self = sc<CConfigManager*>(lua_touserdata(L, lua_upvalueindex(1)));
std::string key = luaL_checkstring(L, 1);
auto arg = Check::string(L, 1);
if (!arg)
return Internal::configError(L, std::format("hl.get_config: bad type for arg 1, {}", arg.error()));
std::string key = *arg;
auto it = self->m_configValues.find(key);
if (it == self->m_configValues.end()) {
@@ -2,6 +2,8 @@
#include <hyprutils/string/String.hpp>
#include "Check.hpp"
#include "../../supplementary/executor/Executor.hpp"
#include "../../../managers/SeatManager.hpp"
@@ -220,10 +222,14 @@ static int dsp_forceIdle(lua_State* L) {
}
static int hlExecCmd(lua_State* L) {
const auto proc = luaL_checkstring(L, 1);
const auto proc = Check::string(L, 1);
if (!proc)
return Internal::configError(L, std::format("exec_cmd: bad argument 1: {}", proc.error()));
const bool hasRuleArg = !lua_isnoneornil(L, 2);
lua_pushstring(L, proc);
lua_pushstring(L, proc->c_str());
if (hasRuleArg)
lua_pushvalue(L, 2);
@@ -235,7 +241,11 @@ static int hlExecCmd(lua_State* L) {
}
static int hlExecRaw(lua_State* L) {
lua_pushstring(L, luaL_checkstring(L, 1));
auto proc = Check::string(L, 1);
if (!proc)
return Internal::configError(L, std::format("exec_raw: bad argument 1: {}", proc.error()));
lua_pushstring(L, proc->c_str());
lua_pushcclosure(L, dsp_execRaw, 1);
return 1;
}
@@ -246,7 +256,11 @@ static int hlExit(lua_State* L) {
}
static int hlSubmap(lua_State* L) {
lua_pushstring(L, luaL_checkstring(L, 1));
auto str = Check::string(L, 1);
if (!str)
return Internal::configError(L, std::format("submap: bad argument 1: {}", str.error()));
lua_pushstring(L, str->c_str());
lua_pushcclosure(L, dsp_submap, 1);
return 1;
}
@@ -262,7 +276,11 @@ static int hlPass(lua_State* L) {
}
static int hlLayout(lua_State* L) {
lua_pushstring(L, luaL_checkstring(L, 1));
auto str = Check::string(L, 1);
if (!str)
return Internal::configError(L, std::format("layout: bad argument 1: {}", str.error()));
lua_pushstring(L, str->c_str());
lua_pushcclosure(L, dsp_layoutMsg, 1);
return 1;
}
@@ -284,13 +302,21 @@ static int hlDpms(lua_State* L) {
}
static int hlEvent(lua_State* L) {
lua_pushstring(L, luaL_checkstring(L, 1));
auto str = Check::string(L, 1);
if (!str)
return Internal::configError(L, std::format("event: bad argument 1: {}", str.error()));
lua_pushstring(L, str->c_str());
lua_pushcclosure(L, dsp_event, 1);
return 1;
}
static int hlGlobal(lua_State* L) {
lua_pushstring(L, luaL_checkstring(L, 1));
auto str = Check::string(L, 1);
if (!str)
return Internal::configError(L, std::format("global: bad argument 1: {}", str.error()));
lua_pushstring(L, str->c_str());
lua_pushcclosure(L, dsp_global, 1);
return 1;
}
@@ -301,7 +327,11 @@ static int hlForceRendererReload(lua_State* L) {
}
static int hlForceIdle(lua_State* L) {
lua_pushnumber(L, luaL_checknumber(L, 1));
auto timeout = Check::number(L, 1);
if (!timeout)
return Internal::configError(L, std::format("force_idle: bad argument 1: {}", timeout.error()));
lua_pushnumber(L, *timeout);
lua_pushcclosure(L, dsp_forceIdle, 1);
return 1;
}
+12 -2
View File
@@ -1,5 +1,7 @@
#include "LuaBindingsInternal.hpp"
#include "Check.hpp"
#include "../objects/LuaLayerSurface.hpp"
#include "../objects/LuaMonitor.hpp"
#include "../objects/LuaWindow.hpp"
@@ -242,8 +244,16 @@ static int hlGetMonitorAt(lua_State* L) {
x = *tx;
y = *ty;
} else {
x = luaL_checknumber(L, 1);
y = luaL_checknumber(L, 2);
const auto tx = Check::number(L, 1);
if (!tx)
return Internal::configError(L, std::format("get_monitor_at: bad argument 1: {}", tx.error()));
const auto ty = Check::number(L, 2);
if (!ty)
return Internal::configError(L, std::format("get_monitor_at: bad argument 2: {}", ty.error()));
x = *tx;
y = *ty;
}
const auto PMONITOR = g_pCompositor->getMonitorFromVector(Vector2D{x, y});
+24 -13
View File
@@ -1,4 +1,5 @@
#include "LuaBindingsInternal.hpp"
#include "Check.hpp"
#include "../objects/LuaEventSubscription.hpp"
#include "../objects/LuaKeybind.hpp"
@@ -122,9 +123,13 @@ static std::expected<void, std::string> parseKeyString(SKeybind& kb, std::string
}
static int hlBind(lua_State* L) {
auto* mgr = sc<CConfigManager*>(lua_touserdata(L, lua_upvalueindex(1)));
auto* mgr = sc<CConfigManager*>(lua_touserdata(L, lua_upvalueindex(1)));
std::string_view keys = luaL_checkstring(L, 1);
auto str = Check::string(L, 1);
if (!str)
return Internal::configError(L, std::format("bind: bad argument 1: {}", str.error()));
std::string_view keys = *str;
SKeybind kb;
kb.submap.name = mgr->m_currentSubmap;
@@ -243,8 +248,10 @@ static int hlBind(lua_State* L) {
}
static int hlDefineSubmap(lua_State* L) {
auto* mgr = sc<CConfigManager*>(lua_touserdata(L, lua_upvalueindex(1)));
const char* name = luaL_checkstring(L, 1);
auto* mgr = sc<CConfigManager*>(lua_touserdata(L, lua_upvalueindex(1)));
auto name = Check::string(L, 1);
if (!name)
return Internal::configError(L, std::format("define_submap: bad argument 1: {}", name.error()));
std::string reset;
int fnIdx = 2;
@@ -257,12 +264,12 @@ static int hlDefineSubmap(lua_State* L) {
std::string prev = mgr->m_currentSubmap;
std::string prevReset = mgr->m_currentSubmapReset;
mgr->m_currentSubmap = name;
mgr->m_currentSubmap = *name;
mgr->m_currentSubmapReset = reset;
lua_pushvalue(L, fnIdx);
if (mgr->guardedPCall(0, 0, 0, CConfigManager::LUA_TIMEOUT_DISPATCH_MS, std::format("hl.define_submap(\"{}\")", name)) != LUA_OK) {
mgr->addError(std::format("hl.define_submap: error in submap \"{}\": {}", name, lua_tostring(L, -1)));
if (mgr->guardedPCall(0, 0, 0, CConfigManager::LUA_TIMEOUT_DISPATCH_MS, std::format("hl.define_submap(\"{}\")", *name)) != LUA_OK) {
mgr->addError(std::format("hl.define_submap: error in submap \"{}\": {}", *name, lua_tostring(L, -1)));
lua_pop(L, 1);
}
@@ -345,14 +352,16 @@ static int hlDispatch(lua_State* L) {
}
static int hlOn(lua_State* L) {
auto* mgr = sc<CConfigManager*>(lua_touserdata(L, lua_upvalueindex(1)));
const char* eventName = luaL_checkstring(L, 1);
auto* mgr = sc<CConfigManager*>(lua_touserdata(L, lua_upvalueindex(1)));
auto evName = Check::string(L, 1);
if (!evName)
return Internal::configError(L, std::format("on: bad argument 1: {}", evName.error()));
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_pushvalue(L, 2);
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
const auto handle = mgr->m_eventHandler->registerEvent(eventName, ref);
const auto handle = mgr->m_eventHandler->registerEvent(*evName, ref);
if (!handle.has_value()) {
luaL_unref(L, LUA_REGISTRYINDEX, ref);
const auto& known = CLuaEventHandler::knownEvents();
@@ -362,7 +371,7 @@ static int hlOn(lua_State* L) {
}
list.pop_back();
list.pop_back();
return Internal::configError(L, "hl.on: unknown event \"{}\". Known events:{}", eventName, list);
return Internal::configError(L, "hl.on: unknown event \"{}\". Known events:{}", *evName, list);
}
Objects::CLuaEventSubscription::push(L, mgr->m_eventHandler.get(), *handle);
@@ -375,8 +384,10 @@ static int hlUnbind(lua_State* L) {
return 0;
}
const char* str = luaL_checkstring(L, 1);
g_pKeybindManager->removeKeybind(str);
auto str = Check::string(L, 1);
if (!str)
return Internal::configError(L, std::format("unbind: bad argument 1: {}", str.error()));
g_pKeybindManager->removeKeybind(*str);
return 0;
}
+55 -23
View File
@@ -2,12 +2,14 @@
#include "LuaLayoutTarget.hpp"
#include "../bindings/LuaBindingsInternal.hpp"
#include "../bindings/Check.hpp"
#include <algorithm>
#include <cmath>
#include <string_view>
using namespace Config::Lua::Layouts;
using namespace Config::Lua;
void Config::Lua::Layouts::pushBox(lua_State* L, const CBox& box) {
lua_newtable(L);
@@ -61,39 +63,63 @@ static size_t targetCountFromContext(lua_State* L, int idx) {
static int ctxGridCell(lua_State* L) {
const auto AREA = areaFromContext(L, 1);
const int i = std::max(1, sc<int>(luaL_checkinteger(L, 2)));
const int cols = std::max(1, sc<int>(luaL_checkinteger(L, 3)));
int rows = 0;
const auto i = Bindings::Check::integer(L, 2);
if (!i)
return Bindings::Internal::configError(L, std::format("grid_cell: bad argument 2: {}", i.error()));
const auto cols = Bindings::Check::integer(L, 3);
if (!cols)
return Bindings::Internal::configError(L, std::format("grid_cell: bad argument 3: {}", cols.error()));
const int index = std::max(1, sc<int>(*i));
const int width = std::max(1, sc<int>(*cols));
int rows = 0;
if (lua_gettop(L) >= 4 && lua_isnumber(L, 4))
rows = std::max(1, sc<int>(lua_tointeger(L, 4)));
else {
const auto count = std::max<size_t>(1, targetCountFromContext(L, 1));
rows = std::max(1, sc<int>(std::ceil(sc<double>(count) / sc<double>(cols))));
rows = std::max(1, sc<int>(std::ceil(sc<double>(count) / sc<double>(width))));
}
const int row = (i - 1) / cols;
const int col = (i - 1) % cols;
const int row = (index - 1) / width;
const int col = (index - 1) % width;
pushBox(L, CBox{AREA.x + AREA.w * col / cols, AREA.y + AREA.h * row / rows, AREA.w / cols, AREA.h / rows}.noNegativeSize());
pushBox(L, CBox{AREA.x + AREA.w * col / width, AREA.y + AREA.h * row / rows, AREA.w / width, AREA.h / rows}.noNegativeSize());
return 1;
}
static int ctxColumn(lua_State* L) {
const auto AREA = areaFromContext(L, 1);
const int i = std::max(1, sc<int>(luaL_checkinteger(L, 2)));
const int n = std::max(1, sc<int>(luaL_checkinteger(L, 3)));
const auto i = Bindings::Check::integer(L, 2);
if (!i)
return Bindings::Internal::configError(L, std::format("column: bad argument 2: {}", i.error()));
pushBox(L, CBox{AREA.x + AREA.w * (i - 1) / n, AREA.y, AREA.w / n, AREA.h}.noNegativeSize());
const auto n = Bindings::Check::integer(L, 3);
if (!n)
return Bindings::Internal::configError(L, std::format("column: bad argument 3: {}", n.error()));
const int index = std::max(1, sc<int>(*i));
const int count = std::max(1, sc<int>(*n));
pushBox(L, CBox{AREA.x + AREA.w * (index - 1) / count, AREA.y, AREA.w / count, AREA.h}.noNegativeSize());
return 1;
}
static int ctxRow(lua_State* L) {
const auto AREA = areaFromContext(L, 1);
const int i = std::max(1, sc<int>(luaL_checkinteger(L, 2)));
const int n = std::max(1, sc<int>(luaL_checkinteger(L, 3)));
const auto i = Bindings::Check::integer(L, 2);
if (!i)
return Bindings::Internal::configError(L, std::format("row: bad argument 2: {}", i.error()));
pushBox(L, CBox{AREA.x, AREA.y + AREA.h * (i - 1) / n, AREA.w, AREA.h / n}.noNegativeSize());
const auto n = Bindings::Check::integer(L, 3);
if (!n)
return Bindings::Internal::configError(L, std::format("row: bad argument 3: {}", n.error()));
const int index = std::max(1, sc<int>(*i));
const int count = std::max(1, sc<int>(*n));
pushBox(L, CBox{AREA.x, AREA.y + AREA.h * (index - 1) / count, AREA.w, AREA.h / count}.noNegativeSize());
return 1;
}
@@ -102,17 +128,23 @@ static int ctxSplit(lua_State* L) {
if (!boxFromTable(L, 2, area))
return Config::Lua::Bindings::Internal::configError(L, "ctx:split expects a box table as first argument");
const std::string_view side = luaL_checkstring(L, 3);
const double ratio = std::clamp(luaL_checknumber(L, 4), 0.0, 1.0);
const auto side = Config::Lua::Bindings::Check::string(L, 1);
if (!side)
return Config::Lua::Bindings::Internal::configError(L, std::format("split: bad argument 1: {}", side.error()));
const auto ratio = Bindings::Check::number(L, 4);
if (!ratio)
return Bindings::Internal::configError(L, std::format("split: bad argument 4: {}", ratio.error()));
if (side == "left")
pushBox(L, CBox{area.x, area.y, area.w * ratio, area.h}.noNegativeSize());
else if (side == "right")
pushBox(L, CBox{area.x + area.w * (1.0 - ratio), area.y, area.w * ratio, area.h}.noNegativeSize());
else if (side == "top" || side == "up")
pushBox(L, CBox{area.x, area.y, area.w, area.h * ratio}.noNegativeSize());
else if (side == "bottom" || side == "down")
pushBox(L, CBox{area.x, area.y + area.h * (1.0 - ratio), area.w, area.h * ratio}.noNegativeSize());
const double clampedRatio = std::clamp(*ratio, 0.0, 1.0);
if (*side == "left")
pushBox(L, CBox{area.x, area.y, area.w * clampedRatio, area.h}.noNegativeSize());
else if (*side == "right")
pushBox(L, CBox{area.x + area.w * (1.0 - clampedRatio), area.y, area.w * clampedRatio, area.h}.noNegativeSize());
else if (*side == "top" || *side == "up")
pushBox(L, CBox{area.x, area.y, area.w, area.h * clampedRatio}.noNegativeSize());
else if (*side == "bottom" || *side == "down")
pushBox(L, CBox{area.x, area.y + area.h * (1.0 - clampedRatio), area.w, area.h * clampedRatio}.noNegativeSize());
else
return Config::Lua::Bindings::Internal::configError(L, "ctx:split side must be left, right, top, or bottom");
+7 -3
View File
@@ -3,6 +3,7 @@
#include "LuaLayoutContext.hpp"
#include "LuaLayoutTarget.hpp"
#include "../ConfigManager.hpp"
#include "../bindings/Check.hpp"
#include "../bindings/LuaBindingsInternal.hpp"
#include "../../../debug/log/Logger.hpp"
@@ -303,11 +304,14 @@ void CConfigManager::clearLuaLayoutProviders() {
}
static int hlLayoutRegister(lua_State* L) {
auto* mgr = sc<CConfigManager*>(lua_touserdata(L, lua_upvalueindex(1)));
const char* name = luaL_checkstring(L, 1);
auto* mgr = sc<CConfigManager*>(lua_touserdata(L, lua_upvalueindex(1)));
const auto name = Bindings::Check::string(L, 1);
if (!name)
return Bindings::Internal::configError(L, std::format("layout.register: bad argument 1: {}", name.error()));
luaL_checktype(L, 2, LUA_TTABLE);
auto result = mgr->registerLuaLayoutProvider(name, L, 2);
auto result = mgr->registerLuaLayoutProvider(*name, L, 2);
if (!result)
return Config::Lua::Bindings::Internal::configError(L, "hl.layout.register: {}", result.error());
+11 -7
View File
@@ -4,6 +4,7 @@
#include "../bindings/LuaBindingsInternal.hpp"
#include "../objects/LuaObjectHelpers.hpp"
#include "../objects/LuaWindow.hpp"
#include "../bindings/Check.hpp"
#include "../../../layout/target/Target.hpp"
@@ -36,26 +37,29 @@ static int layoutTargetPlace(lua_State* L) {
}
static int layoutTargetIndex(lua_State* L) {
auto* ref = sc<SLuaLayoutTargetRef*>(luaL_checkudata(L, 1, TARGET_MT));
const std::string_view key = luaL_checkstring(L, 2);
auto* ref = sc<SLuaLayoutTargetRef*>(luaL_checkudata(L, 1, TARGET_MT));
auto target = ref->target.lock();
const auto key = Bindings::Check::string(L, 2);
if (!key)
return Bindings::Internal::configError(L, std::format("HL.LayoutTarget.__index: bad argument 2: {}", key.error()));
auto target = ref->target.lock();
if (!target) {
lua_pushnil(L);
return 1;
}
if (key == "index")
if (*key == "index")
lua_pushinteger(L, sc<lua_Integer>(ref->index));
else if (key == "window") {
else if (*key == "window") {
const auto window = target->window();
if (window)
Objects::CLuaWindow::push(L, window);
else
lua_pushnil(L);
} else if (key == "box")
} else if (*key == "box")
pushBox(L, target->position());
else if (key == "place" || key == "set_box")
else if (*key == "place" || *key == "set_box")
lua_pushcfunction(L, layoutTargetPlace);
else
lua_pushnil(L);