aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-15 16:27:50 +0200
committeruser <user@clank>2026-08-15 16:27:50 +0200
commit4f64774f910347ce8a27c3aecc7f1c2ac167301b (patch)
treef1c762382e86171de1b9212aa0c04a9e7b655a72 /src
parentsl0ppty: render the config instead of shipping a copy of it (diff)
downloadslosh-4f64774f910347ce8a27c3aecc7f1c2ac167301b.tar.gz
slosh-4f64774f910347ce8a27c3aecc7f1c2ac167301b.tar.xz
slosh-4f64774f910347ce8a27c3aecc7f1c2ac167301b.zip
sl0ppty: watch the config directory even when it is not there yet
You were right. The watch is on the *directory* -- editors write a new file and rename it over the old one, so watching the file stops working the first time you save -- but a directory that does not exist cannot be watched at all. inotify_add_watch failed, the session gave up on watching for good, and writing a config later did nothing until a restart. Which is exactly the state a fresh machine is in, and exactly the state C-a e leaves you in. sl0ppty creates its own config directory at startup now, so there is always something to watch and a file appearing later is picked up. Tested from a home directory with no .config at all. Answering the other half of the question -- which settings actually reload -- turned up one that never worked at all: `shell`. main.c read $SHELL directly and nobody read the config's value, so the setting parsed, rendered in --dump-config, and did nothing. It is resolved per pane now, which fixes it and makes it live: edit it, save, and the next pane you open uses it. Everything else measured rather than assumed, and it is nearly everything: colours, geometry, the status bar and line, frame marks, shader chains and their states, and the keys including the leader itself. The two exceptions are about *when* a value is read, not reluctance -- `shell` at pane creation, and shader plugins which load on reload but never unload. Both are now written down where someone would look. One test needed rescuing from itself: it asserted the new leader worked by splitting, in panes that were by then too narrow to split. A test that fails on geometry while claiming to be about the prefix is worse than no test; it opens a tab instead.
Diffstat (limited to 'src')
-rw-r--r--src/app.c26
-rw-r--r--src/main.c8
-rw-r--r--src/server.c7
3 files changed, 33 insertions, 8 deletions
diff --git a/src/app.c b/src/app.c
index e6ce4b4..4b86fb2 100644
--- a/src/app.c
+++ b/src/app.c
@@ -730,8 +730,24 @@ static node_t *leaf_new_ex(app_t *a, const char *const argv[], const char *cwd,
return n;
}
+/* What a new pane runs when nobody said otherwise: whatever the session was
+ * started with, else the config's `shell`, else $SHELL, else /bin/sh.
+ *
+ * Resolved per pane rather than once at startup, so editing `shell` and
+ * saving affects the next pane you open instead of the next session you
+ * start. The array is static because pane_new copies what it is given before
+ * this could be called again. */
+static const char *const *default_argv(app_t *a) {
+ static const char *argv[2];
+ if (a->argv && a->argv[0]) return a->argv;
+ const char *sh = CFG.shell && *CFG.shell ? CFG.shell : getenv("SHELL");
+ argv[0] = sh && *sh ? sh : "/bin/sh";
+ argv[1] = NULL;
+ return argv;
+}
+
static node_t *leaf_new(app_t *a) {
- pane_t *p = pane_new(a->argv, 1, 1, NULL);
+ pane_t *p = pane_new(default_argv(a), 1, 1, NULL);
if (!p) return NULL;
node_t *n = calloc(1, sizeof *n);
n->kind = NODE_LEAF;
@@ -1859,12 +1875,14 @@ static node_t *build_pane(app_t *a, const kdl_node_t *node, const char *cwd) {
argv[2] = command;
argv[3] = NULL;
} else {
- argv[0] = a->argv[0];
+ const char *const *base = default_argv(a);
+ argv[0] = base[0];
argv[1] = NULL;
- for (size_t i = 1; a->argv[i] && i < 3; i++) argv[i] = a->argv[i];
+ for (size_t i = 1; base[i] && i < 3; i++) argv[i] = base[i];
}
- node_t *leaf = leaf_new_ex(a, command ? argv : a->argv, node_cwd, suspended,
+ node_t *leaf = leaf_new_ex(a, command ? argv : default_argv(a), node_cwd,
+ suspended,
command ? command : "");
if (!leaf) return NULL;
leaf->weight = (int)kdl_prop_int(node, "weight", WEIGHT_UNIT);
diff --git a/src/main.c b/src/main.c
index 53689ee..5a52a18 100644
--- a/src/main.c
+++ b/src/main.c
@@ -97,10 +97,10 @@ int main(int argc, char **argv) {
}
}
- if (cmd_n == 0) {
- const char *shell = getenv("SHELL");
- cmd_argv[cmd_n++] = shell && *shell ? shell : "/bin/sh";
- }
+ /* No `--` command: leave it empty and let the session decide, so the
+ * config's `shell` is consulted when a pane is made rather than baked in
+ * here -- where it was not consulted at all, which made `shell` a setting
+ * that did nothing. */
cmd_argv[cmd_n] = NULL;
if (list) {
diff --git a/src/server.c b/src/server.c
index 498b83f..242be26 100644
--- a/src/server.c
+++ b/src/server.c
@@ -239,6 +239,13 @@ int server_run(const char *name, const char *const argv[], uint16_t cols,
snprintf(cfg_dir, sizeof cfg_dir, ".");
snprintf(cfg_base, sizeof cfg_base, "%s", path);
}
+ /* The watch is on the directory, not the file -- editors write a new
+ * file and rename it over the old one, so watching the file itself
+ * stops working the first time you save. But a directory that is not
+ * there cannot be watched at all, and then nothing is ever noticed for
+ * the life of the session: no config, no watch, and saving one later
+ * does nothing until a restart. Ours to create, so create it. */
+ path_mkdirs(cfg_dir);
inofd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (inofd >= 0) {
inowd = inotify_add_watch(inofd, cfg_dir,