diff options
| author | user <user@clank> | 2026-08-15 16:27:50 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-15 16:27:50 +0200 |
| commit | 4f64774f910347ce8a27c3aecc7f1c2ac167301b (patch) | |
| tree | f1c762382e86171de1b9212aa0c04a9e7b655a72 /src | |
| parent | sl0ppty: render the config instead of shipping a copy of it (diff) | |
| download | slosh-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.c | 26 | ||||
| -rw-r--r-- | src/main.c | 8 | ||||
| -rw-r--r-- | src/server.c | 7 |
3 files changed, 33 insertions, 8 deletions
@@ -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); @@ -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, |
