diff options
| author | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2026-04-28 15:56:07 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-28 15:56:07 +0100 |
| commit | 98fbbafef78057c818fb02b15c27e38ad2f5b5bc (patch) | |
| tree | c62aa1eae704e7595d58f7edeb3804e8bfd0099d /src/config/shared | |
| parent | d4c6ff434c5c7aa66bc7c28e5ce336d2a694bfcc (diff) | |
config/errors: Report and categorize errors properly for actions (#14192)
Makes all errors categorized, some not displayed, some displayed.
All errors can be obtained after hl.dispatch()
Diffstat (limited to 'src/config/shared')
| -rw-r--r-- | src/config/shared/ConfigErrors.hpp | 69 | ||||
| -rw-r--r-- | src/config/shared/actions/ConfigActions.cpp | 68 | ||||
| -rw-r--r-- | src/config/shared/actions/ConfigActions.hpp | 12 |
3 files changed, 114 insertions, 35 deletions
diff --git a/src/config/shared/ConfigErrors.hpp b/src/config/shared/ConfigErrors.hpp new file mode 100644 index 00000000..b6723400 --- /dev/null +++ b/src/config/shared/ConfigErrors.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include <expected> +#include <cstdint> +#include <string> +#include <utility> + +namespace Config { + enum class eConfigErrorLevel : uint8_t { + SILENT = 0, + INFO, + WARNING, + ERROR, + }; + + enum class eConfigErrorCode : uint8_t { + UNKNOWN = 0, + INVALID_ARGUMENT, + NOT_FOUND, + NO_TARGET, + INVALID_STATE, + UNAVAILABLE, + EXECUTION_FAILED, + LUA_ERROR, + INTERNAL, + }; + + struct SConfigError { + SConfigError() = default; + SConfigError(std::string msg, eConfigErrorLevel lvl = eConfigErrorLevel::ERROR, eConfigErrorCode c = eConfigErrorCode::UNKNOWN) : + message(std::move(msg)), level(lvl), code(c) {} + SConfigError(const char* msg) : message(msg ? msg : "") {} + + std::string message; + eConfigErrorLevel level = eConfigErrorLevel::ERROR; + eConfigErrorCode code = eConfigErrorCode::UNKNOWN; + }; + + using ErrorResult = std::expected<void, SConfigError>; + + inline const char* toString(eConfigErrorLevel level) { + switch (level) { + case eConfigErrorLevel::SILENT: return "silent"; + case eConfigErrorLevel::INFO: return "info"; + case eConfigErrorLevel::WARNING: return "warning"; + case eConfigErrorLevel::ERROR: return "error"; + } + return "unknown"; + } + + inline const char* toString(eConfigErrorCode code) { + switch (code) { + case eConfigErrorCode::UNKNOWN: return "unknown"; + case eConfigErrorCode::INVALID_ARGUMENT: return "invalid_argument"; + case eConfigErrorCode::NOT_FOUND: return "not_found"; + case eConfigErrorCode::NO_TARGET: return "no_target"; + case eConfigErrorCode::INVALID_STATE: return "invalid_state"; + case eConfigErrorCode::UNAVAILABLE: return "unavailable"; + case eConfigErrorCode::EXECUTION_FAILED: return "execution_failed"; + case eConfigErrorCode::LUA_ERROR: return "lua_error"; + case eConfigErrorCode::INTERNAL: return "internal"; + } + return "unknown"; + } + + inline std::unexpected<SConfigError> configError(std::string message, eConfigErrorLevel level = eConfigErrorLevel::ERROR, eConfigErrorCode code = eConfigErrorCode::UNKNOWN) { + return std::unexpected(SConfigError{std::move(message), level, code}); + } +} diff --git a/src/config/shared/actions/ConfigActions.cpp b/src/config/shared/actions/ConfigActions.cpp index fb2029a5..c36a149f 100644 --- a/src/config/shared/actions/ConfigActions.cpp +++ b/src/config/shared/actions/ConfigActions.cpp @@ -131,7 +131,7 @@ ActionResult Actions::closeWindow(std::optional<PHLWINDOW> w) { return {}; if (window->m_closeableSince > Time::steadyNow()) - return std::unexpected("can't close window, it's not closeable yet (noclosefor)"); + return actionError("can't close window, it's not closeable yet (noclosefor)", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); window->sendClose(); @@ -217,7 +217,7 @@ ActionResult Actions::pinWindow(eTogglableAction action, std::optional<PHLWINDOW return {}; if (!window->m_isFloating || window->isFullscreen()) - return {}; + return actionError("Window does not qualify to be pinned", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); bool wantPin = false; switch (action) { @@ -289,7 +289,7 @@ ActionResult Actions::moveToWorkspace(PHLWORKSPACE ws, bool silent, std::optiona return {}; if (!ws) - return {}; + return std::unexpected("Invalid workspace"); if (ws->m_id == window->workspaceID()) return {}; @@ -373,11 +373,11 @@ ActionResult Actions::moveFocus(Math::eDirection dir) { static auto PNOFALLBACK = CConfigValue<Config::INTEGER>("general:no_focus_fallback"); if (*PNOFALLBACK) - return {}; + return actionError(std::format("Nothing to focus to in direction {}", Math::toString(dir)), eActionErrorLevel::INFO, eActionErrorCode::NOT_FOUND); const auto PMONITOR = PLASTWINDOW->m_monitor.lock(); if (!PMONITOR) - return {}; + return std::unexpected("Window has no monitor"); if (dir == Math::DIRECTION_LEFT || dir == Math::DIRECTION_RIGHT) { if (STICKS(PLASTWINDOW->m_position.x, PMONITOR->m_position.x) && STICKS(PLASTWINDOW->m_size.x, PMONITOR->m_size.x)) @@ -440,7 +440,7 @@ ActionResult Actions::moveInDirection(Math::eDirection dir, std::optional<PHLWIN return {}; if (window->isFullscreen()) - return {}; + return actionError("Can't move fullscreen window", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); updateRelativeCursorCoords(); @@ -456,12 +456,12 @@ ActionResult Actions::swapInDirection(Math::eDirection dir, std::optional<PHLWIN return {}; if (window->isFullscreen()) - return {}; + return actionError("Can't swap fullscreen window", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(window, dir); if (!PWINDOWTOCHANGETO || PWINDOWTOCHANGETO == window) - return {}; + return actionError("No window to swap with in that direction", eActionErrorLevel::INFO, eActionErrorCode::NOT_FOUND); updateRelativeCursorCoords(); g_layoutManager->switchTargets(window->layoutTarget(), PWINDOWTOCHANGETO->layoutTarget(), true); @@ -476,13 +476,13 @@ ActionResult Actions::swapWith(PHLWINDOW other, std::optional<PHLWINDOW> w) { return {}; if (!other) - return {}; + return actionError("No window to swap with", eActionErrorLevel::INFO, eActionErrorCode::NOT_FOUND); if (other == window) - return {}; + return actionError("Can't swap a window with itself", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); if (window->isFullscreen() || other->isFullscreen()) - return {}; + return actionError("Can't swap fullscreen window", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); updateRelativeCursorCoords(); g_layoutManager->switchTargets(window->layoutTarget(), other->layoutTarget(), true); @@ -495,12 +495,12 @@ ActionResult Actions::focusCurrentOrLast() { const auto& HISTORY = Desktop::History::windowTracker()->fullHistory(); if (HISTORY.size() <= 1) - return {}; + return actionError("History too short", eActionErrorLevel::INFO, eActionErrorCode::NOT_FOUND); const auto PWINDOWPREV = HISTORY[HISTORY.size() - 2].lock(); if (!PWINDOWPREV) - return {}; + return actionError("Window not found", eActionErrorLevel::INFO, eActionErrorCode::NOT_FOUND); switchToWindow(PWINDOWPREV); @@ -513,7 +513,7 @@ ActionResult Actions::focusUrgentOrLast() { const auto PWINDOWPREV = Desktop::focusState()->window() ? (HISTORY.size() < 2 ? nullptr : HISTORY[1].lock()) : (HISTORY.empty() ? nullptr : HISTORY[0].lock()); if (!PWINDOWURGENT && !PWINDOWPREV) - return {}; + return actionError("Window not found", eActionErrorLevel::INFO, eActionErrorCode::NOT_FOUND); switchToWindow(PWINDOWURGENT ? PWINDOWURGENT : PWINDOWPREV); @@ -523,7 +523,7 @@ ActionResult Actions::focusUrgentOrLast() { ActionResult Actions::center(std::optional<PHLWINDOW> w) { auto window = xtract(w); if (!window || !window->m_isFloating || window->isFullscreen()) - return {}; + return actionError("No floating window found", eActionErrorLevel::INFO, eActionErrorCode::NOT_FOUND); const auto PMONITOR = window->m_monitor.lock(); @@ -560,7 +560,7 @@ ActionResult Actions::resize(const Vector2D& size, bool relative, std::optional< return {}; if (window->isFullscreen()) - return {}; + return actionError("Window is fullscreen", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); if (!relative && (size.x < 1 || size.y < 1)) return std::unexpected("Invalid size"); @@ -581,7 +581,7 @@ ActionResult Actions::move(const Vector2D& pos, bool relative, std::optional<PHL return {}; if (window->isFullscreen()) - return {}; + return actionError("Window is fullscreen", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); const auto delta = relative ? pos : pos - window->m_realPosition->goal(); @@ -617,7 +617,7 @@ ActionResult Actions::swapNext(const bool next, std::optional<PHLWINDOW> w) { toSwap = g_pCompositor->getWindowCycle(window, true, std::nullopt, false, !next); if (!toSwap) - return {}; + return actionError("No window to swap with", eActionErrorLevel::INFO, eActionErrorCode::NOT_FOUND); g_layoutManager->switchTargets(window->layoutTarget(), toSwap->layoutTarget(), false); window->m_lastCycledWindow = toSwap; @@ -851,10 +851,10 @@ ActionResult Actions::changeGroupActive(bool forward, std::optional<PHLWINDOW> w return {}; if (!window->m_group) - return {}; + return actionError("Window is not in a group", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); if (window->m_group->size() == 1) - return {}; + return actionError("Only one window in group", eActionErrorLevel::INFO, eActionErrorCode::INVALID_STATE); window->m_group->moveCurrent(forward); @@ -867,15 +867,15 @@ ActionResult Actions::setGroupActive(int index, std::optional<PHLWINDOW> w) { return {}; if (!window->m_group) - return {}; + return actionError("Window is not in a group", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); if (window->m_group->size() == 1) - return {}; + return actionError("Only one window in group", eActionErrorLevel::INFO, eActionErrorCode::INVALID_STATE); if (index <= 0) window->m_group->setCurrent(window->m_group->size() - 1); else if (sc<size_t>(index) > window->m_group->size()) - return {}; + return actionError("Index out of range", eActionErrorLevel::ERROR, eActionErrorCode::INVALID_ARGUMENT); else window->m_group->setCurrent(index - 1); @@ -884,14 +884,14 @@ ActionResult Actions::setGroupActive(int index, std::optional<PHLWINDOW> w) { ActionResult Actions::changeWorkspace(PHLWORKSPACE ws) { if (!ws) - return {}; + return std::unexpected("Invalid workspace"); static auto PHIDESPECIALONWORKSPACECHANGE = CConfigValue<Config::INTEGER>("binds:hide_special_on_workspace_change"); static auto PWORKSPACECENTERON = CConfigValue<Config::INTEGER>("binds:workspace_center_on"); const auto PMONITOR = Desktop::focusState()->monitor(); if (!PMONITOR) - return {}; + return std::unexpected("No monitor"); if (ws->m_isSpecialWorkspace) { PMONITOR->setSpecialWorkspace(ws); @@ -905,7 +905,7 @@ ActionResult Actions::changeWorkspace(PHLWORKSPACE ws) { const auto PMONITORWORKSPACEOWNER = PMONITOR == ws->m_monitor ? PMONITOR : ws->m_monitor.lock(); if (!PMONITORWORKSPACEOWNER) - return {}; + return std::unexpected("Workspace has no monitor"); updateRelativeCursorCoords(); @@ -1219,10 +1219,10 @@ ActionResult Actions::lockGroups(eTogglableAction action) { ActionResult Actions::lockActiveGroup(eTogglableAction action) { const auto PWINDOW = Desktop::focusState()->window(); if (!PWINDOW) - return {}; + return actionError("No window found", eActionErrorLevel::INFO, eActionErrorCode::NO_TARGET); if (!PWINDOW->m_group) - return {}; + return actionError("Window not in a group", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); switch (action) { case TOGGLE_ACTION_TOGGLE: PWINDOW->m_group->setLocked(!PWINDOW->m_group->locked()); break; @@ -1306,14 +1306,14 @@ ActionResult Actions::moveOutOfGroup(Math::eDirection direction, std::optional<P static auto PIGNOREGROUPLOCK = CConfigValue<Config::INTEGER>("binds:ignore_group_lock"); if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_groupsLocked) - return {}; + return actionError("Groups locked", eActionErrorLevel::INFO, eActionErrorCode::INVALID_STATE); auto window = xtract(w); if (!window) return {}; if (!window->m_group) - return {}; + return actionError("Window not in a group", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); moveWindowOutOfGroupHelper(window, direction); @@ -1323,10 +1323,10 @@ ActionResult Actions::moveOutOfGroup(Math::eDirection direction, std::optional<P ActionResult Actions::moveGroupWindow(bool forward) { const auto PLASTWINDOW = Desktop::focusState()->window(); if (!PLASTWINDOW) - return {}; + return actionError("No window found", eActionErrorLevel::INFO, eActionErrorCode::NO_TARGET); if (!PLASTWINDOW->m_group) - return {}; + return actionError("Window not in a group", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE); if (forward) PLASTWINDOW->m_group->swapWithNext(); @@ -1406,7 +1406,7 @@ ActionResult Actions::pass(std::optional<PHLWINDOW> w) { return {}; if (!g_pSeatManager->m_keyboard) - return {}; + return std::unexpected("No keyboard"); const auto& S = *Config::Actions::state(); const auto XWTOXW = window->m_isX11 && Desktop::focusState()->window() && Desktop::focusState()->window()->m_isX11; @@ -1474,7 +1474,7 @@ ActionResult Actions::pass(uint32_t modMask, uint32_t key, std::optional<PHLWIND if (window) { if (!g_pSeatManager->m_keyboard) - return {}; + return std::unexpected("No keyboard"); if (!isMouse) g_pSeatManager->setKeyboardFocus(window->wlSurface()->resource()); diff --git a/src/config/shared/actions/ConfigActions.hpp b/src/config/shared/actions/ConfigActions.hpp index b9f54f50..0f16aff7 100644 --- a/src/config/shared/actions/ConfigActions.hpp +++ b/src/config/shared/actions/ConfigActions.hpp @@ -7,19 +7,29 @@ #include "../../../desktop/DesktopTypes.hpp" #include "../../../desktop/Workspace.hpp" #include "../../../helpers/math/Direction.hpp" +#include "../ConfigErrors.hpp" namespace Config::Actions { struct SActionResult { bool passEvent = false; }; + using eActionErrorLevel = Config::eConfigErrorLevel; + using eActionErrorCode = Config::eConfigErrorCode; + using SActionError = Config::SConfigError; + using Config::toString; + + inline std::unexpected<SActionError> actionError(std::string message, eActionErrorLevel level = eActionErrorLevel::ERROR, eActionErrorCode code = eActionErrorCode::UNKNOWN) { + return Config::configError(std::move(message), level, code); + } + enum eTogglableAction : uint8_t { TOGGLE_ACTION_TOGGLE = 0, TOGGLE_ACTION_ENABLE, TOGGLE_ACTION_DISABLE, }; - using ActionResult = std::expected<SActionResult, std::string>; + using ActionResult = std::expected<SActionResult, SActionError>; ActionResult closeWindow(std::optional<PHLWINDOW> window = std::nullopt /* Active */); ActionResult killWindow(std::optional<PHLWINDOW> window = std::nullopt /* Active */); |
