aboutsummaryrefslogtreecommitdiffstats
path: root/src/app.c
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-15 23:21:40 +0200
committeruser <user@clank>2026-08-15 23:21:40 +0200
commitb9ae6cbcbce3816c2b2e8f760f082d3eaa3b5184 (patch)
tree8dd1f16ac15edd16f51ba07e37c312ccb89f53f1 /src/app.c
parentsl0ppty: watch what the config was built from, not just what it was called (diff)
downloadslosh-b9ae6cbcbce3816c2b2e8f760f082d3eaa3b5184.tar.gz
slosh-b9ae6cbcbce3816c2b2e8f760f082d3eaa3b5184.tar.xz
slosh-b9ae6cbcbce3816c2b2e8f760f082d3eaa3b5184.zip
sl0ppty: say what the config could not honour
A config that half-applied said nothing. An unknown shader, a binding that does not parse, an include that is not there: the file loaded, that line did not, and the session announced "config reloaded" as though nothing had happened. Every one of those messages was already being produced -- config_load has filled `err` on a successful load since it was written -- and then dropped on the floor by every caller, because a non-zero return meant "fine". So the complaint from the last load is kept, and the front end says it where it would have said "config reloaded". Once at startup too: a config that loaded with a complaint still started the session, and the stderr line goes where nobody attached can read it. The `reload` control verb answers `{"ok":true,"warning":"..."}` -- ok, because the file did apply, with the reason attached for a script that cares. Two things fell out of writing the test for it. An include's complaint was reported by nobody when the file in the middle was fine. apply_includes only looked at the return value, so a theme that loaded while *its* include was missing swallowed the message: the child returned true, and true meant there was nothing to say. The complaint now travels up whether or not the include itself loaded. And a complaint now carries the name of the file it happened in, exactly once -- added by the file that produced it, never by the files that included it, because prefixing at every level builds a chain that truncates before the part that matters. So: t.kdl: unknown shader: bloom keys.kdl: line 2: unknown action fly b.kdl: includes nested too deep (a cycle?) cannot open /home/you/.config/sl0ppty/themes/nope.kdl which is enough to know which file to open, in a message that fits in a toast.
Diffstat (limited to 'src/app.c')
-rw-r--r--src/app.c20
1 files changed, 19 insertions, 1 deletions
diff --git a/src/app.c b/src/app.c
index 9c33601..fefb2ba 100644
--- a/src/app.c
+++ b/src/app.c
@@ -26,6 +26,13 @@
* look; `reload` re-reads it in place, which is why nothing caches a colour. */
static config_t CFG;
static bool CFG_LOADED = false;
+/* What the config in force complained about while loading, or "". A complaint
+ * is not a failure: an include that is not there, a shader nobody has heard of,
+ * a binding that does not parse — the rest of the file applied and the session
+ * is running (D9). But dropping it on the floor is how a mistyped theme name
+ * turns into ten minutes of wondering, so it is kept for whoever can say it out
+ * loud. The front end toasts it; the log gets it either way. */
+static char CFG_COMPLAINT[256];
static void ensure_config(void) {
if (CFG_LOADED) return;
@@ -35,14 +42,23 @@ static void ensure_config(void) {
if (!config_load(&CFG, path, err, sizeof err)) {
/* A missing file is the normal case; a broken one is worth a line in the
* log, and in both the compiled-in defaults stand (fail open). */
- if (access(path, R_OK) == 0)
+ if (access(path, R_OK) == 0) {
fprintf(stderr, "sl0ppty: %s: %s\n", path, err[0] ? err : "parse error");
+ snprintf(CFG_COMPLAINT, sizeof CFG_COMPLAINT, "%s",
+ err[0] ? err : "config parse error");
+ }
} else if (err[0]) {
fprintf(stderr, "sl0ppty: %s: %s\n", path, err);
+ snprintf(CFG_COMPLAINT, sizeof CFG_COMPLAINT, "%s", err);
}
CFG_LOADED = true;
}
+const char *app_config_complaint(void) {
+ ensure_config();
+ return CFG_COMPLAINT;
+}
+
bool app_reload_config(char *err, size_t errcap) {
config_t fresh;
config_defaults(&fresh);
@@ -54,6 +70,8 @@ bool app_reload_config(char *err, size_t errcap) {
config_free(&CFG);
CFG = fresh;
CFG_LOADED = true;
+ /* Whatever the new file had to say about itself, including nothing. */
+ snprintf(CFG_COMPLAINT, sizeof CFG_COMPLAINT, "%s", err && err[0] ? err : "");
return true;
}