3
0
mirror of https://github.com/hyprwm/Hyprland.git synced 2026-08-18 11:02:10 +00:00

config/lua: improve error handle-ability with Lua require (#14937)

* config/lua: make `require` throw an actual error for nonexistent modules

`require` uses pcall to catch errors and display them to the user. This
is usually okay, but it also hides errors if Lua tries to load a
nonexistent module, which the Lua config might actually want to detect
and handle on its own (e.g. by loading a different module, or disabling
functionality).

Ref #14534

* config/lua: make vanilla `require` available as `__require`

If `safeLuaRequire()`'s error-catching behavior isn't wanted, this
allows the user to call the original version directly, as `__require`.
Or, they could bring it back as the default by doing e.g.
`require = __require`, which might be desired to avoid breaking
third-party modules that want to catch errors during module load.
This commit is contained in:
Lucas Ritzdorf
2026-06-05 15:20:02 -06:00
committed by Vaxry
parent 70cd53676c
commit 3a67eb7982

View File

@ -128,6 +128,17 @@ static int safeLuaRequire(lua_State* L) {
lua_pop(L, 1);
}
// if we failed to resolve the require'd module, return that as an actual
// error (so the user can catch it via pcall)
{
std::string moduleErrPrefix = std::format("module '{}' not found", moduleName);
if (err.starts_with(moduleErrPrefix))
return luaL_error(L, err.c_str());
}
// otherwise, throw the error message into the config-errors list, and
// return an empty table to Lua (weird from a Lua perspective, but
// hopefully acceptable since the error is directly visible to the user)
if (auto* mgr = CConfigManager::fromLuaState(L); mgr) {
if (!moduleName.empty()) {
trackRequiredLuaModulePath(L, mgr, moduleName);
@ -138,7 +149,7 @@ static int safeLuaRequire(lua_State* L) {
lua_pop(L, 1); // error object
lua_newtable(L); // fallback module
lua_newtable(L); // empty table as fallback return
const int fallbackIdx = lua_gettop(L);
if (!moduleName.empty()) {
@ -322,8 +333,10 @@ void CConfigManager::reinitLuaState() {
lua_getglobal(m_lua, "require");
if (lua_isfunction(m_lua, -1)) {
lua_pushvalue(m_lua, -1);
lua_setglobal(m_lua, "__require"); // original `require` as `__require`
lua_pushcclosure(m_lua, safeLuaRequire, 1);
lua_setglobal(m_lua, "require");
lua_setglobal(m_lua, "require"); // safe require as `require`
} else
lua_pop(m_lua, 1);