From 0408f951e5d31fee16c7c838ae752fc7533f54a7 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Thu, 7 May 2026 21:16:36 +0200 Subject: [PATCH] config(service): show startup notifications for settings.toml parse errors --- src/config/config_service.cpp | 54 ++++++++++++++++++++++------------- src/config/config_service.h | 2 ++ 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/config/config_service.cpp b/src/config/config_service.cpp index 9eba0ec8b..2e1462dcb 100644 --- a/src/config/config_service.cpp +++ b/src/config/config_service.cpp @@ -688,6 +688,7 @@ void ConfigService::loadOverridesFromFile() { m_defaultWallpaperPath.clear(); m_monitorWallpaperPaths.clear(); m_setupWizardCompleted = false; + m_overridesParseError.clear(); if (m_overridesPath.empty() || !std::filesystem::exists(m_overridesPath)) { return; @@ -697,7 +698,12 @@ void ConfigService::loadOverridesFromFile() { try { m_overridesTable = toml::parse_file(m_overridesPath); } catch (const toml::parse_error& e) { - kLog.warn("parse error in {}: {}", m_overridesPath, e.what()); + const auto& src = e.source(); + kLog.warn("parse error in {} at line {}, column {}: {}", m_overridesPath, src.begin.line, src.begin.column, + e.description()); + m_overridesParseError = + std::format("{} line {}, column {}: {}", std::filesystem::path(m_overridesPath).filename().string(), + src.begin.line, src.begin.column, e.description()); m_overridesTable = toml::table{}; return; } @@ -706,6 +712,28 @@ void ConfigService::loadOverridesFromFile() { extractWallpaperFromOverrides(); } +void ConfigService::setConfigParseError(std::string parseError) { + if (parseError.empty()) { + // Dismiss any previous config-error notification. + if (m_notificationManager != nullptr && m_configErrorNotificationId != 0) { + m_notificationManager->close(m_configErrorNotificationId); + m_configErrorNotificationId = 0; + } + m_pendingError.clear(); + return; + } + + if (m_notificationManager != nullptr) { + if (m_configErrorNotificationId != 0) { + m_notificationManager->close(m_configErrorNotificationId); + } + m_configErrorNotificationId = + m_notificationManager->addInternal("Noctalia", "Config parse error", parseError, Urgency::Critical, 0); + } else { + m_pendingError = std::move(parseError); + } +} + void ConfigService::deepMerge(toml::table& base, const toml::table& overlay) { for (const auto& [k, v] : overlay) { if (const auto* overlayTbl = v.as_table()) { @@ -857,6 +885,7 @@ void ConfigService::loadAll() { }); m_config.bars.push_back(BarConfig{}); m_config.controlCenter.shortcuts = defaultControlCenterShortcuts(); + setConfigParseError(m_overridesParseError); return; } @@ -868,25 +897,10 @@ void ConfigService::loadAll() { kLog.warn("config parse error: {}", semanticError); } - const std::string parseError = !firstError.empty() ? firstError : semanticError; - if (parseError.empty()) { - // Dismiss any previous config-error notification. - if (m_notificationManager != nullptr && m_configErrorNotificationId != 0) { - m_notificationManager->close(m_configErrorNotificationId); - m_configErrorNotificationId = 0; - } - m_pendingError.clear(); - } else { - if (m_notificationManager != nullptr) { - if (m_configErrorNotificationId != 0) { - m_notificationManager->close(m_configErrorNotificationId); - } - m_configErrorNotificationId = - m_notificationManager->addInternal("Noctalia", "Config parse error", parseError, Urgency::Critical, 0); - } else { - m_pendingError = parseError; - } - } + const std::string parseError = !firstError.empty() ? firstError + : !m_overridesParseError.empty() ? m_overridesParseError + : semanticError; + setConfigParseError(parseError); } void ConfigService::parseTable(const toml::table& tbl) { parseTableInto(tbl, m_config, true); } diff --git a/src/config/config_service.h b/src/config/config_service.h index 8d101cba1..cf3ce1391 100644 --- a/src/config/config_service.h +++ b/src/config/config_service.h @@ -97,6 +97,7 @@ private: void setupWatch(); void fireReloadCallbacks(); void loadOverridesFromFile(); + void setConfigParseError(std::string parseError); bool writeOverridesToFile(); void extractWallpaperFromOverrides(); @@ -116,6 +117,7 @@ private: bool m_setupWizardCompleted = false; mutable std::unordered_map m_effectiveOverrideCache; + std::string m_overridesParseError; std::string m_pendingError; // parse error from initial load, sent as notification once manager is wired up uint32_t m_configErrorNotificationId = 0; // ID of the active config-error notification, 0 if none NotificationManager* m_notificationManager = nullptr;