aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-17 13:38:33 +0200
committeruser <user@clank>2026-08-17 13:38:33 +0200
commit7a91885c3b063c8d231daceb2b2e29e1f1a81aa6 (patch)
tree7210a201bc59bd0c871cbc82afc21de16d3959b5 /src
parentsl0ppty: a --script pane is told no session rather than somebody else's (diff)
downloadslosh-7a91885c3b063c8d231daceb2b2e29e1f1a81aa6.tar.gz
slosh-7a91885c3b063c8d231daceb2b2e29e1f1a81aa6.tar.xz
slosh-7a91885c3b063c8d231daceb2b2e29e1f1a81aa6.zip
sl0ppty: `set-name target="pane"`, so a script can overrule a program's title
A pane's name already outranks the title its program sets -- `pane_title` prefers the name while there is one -- and that is the whole remedy for a program announcing something it stopped meaning: an agent still spinning the summary of a task it finished, a build script that titled itself once. The remedy was reachable by double-clicking the title on somebody's screen, and from a layout file, but not from the socket, while `set-purpose` next to it has taken `target:"pane"|"tab"` all along. `target` defaults to `tab`, which is what this verb has always meant. Two verbs whose defaults differ is a smaller wrong than a verb that quietly changes its subject under scripts already written against it. The refusals say `no such pane` or `no such tab`, so a mistyped target shows up in the reply rather than as a label that did not move. The gesture now calls the same function, so the two ways in cannot disagree about where a pane's name lives -- there is a test that a name set over the socket is the name the double-click editor offers to edit. Verified: eight checks in `tests/test_pane_title.py`. A pane named while its program keeps setting OSC 2 titles keeps the name; clearing it hands the label back to what the program calls itself *now*; `id: 0` is the focused pane and leaves the other one alone; `set-name` with no target still renames the tab and leaves the pane's title alone.
Diffstat (limited to 'src')
-rw-r--r--src/app.c22
-rw-r--r--src/app.h3
-rw-r--r--src/cmd.c16
3 files changed, 32 insertions, 9 deletions
diff --git a/src/app.c b/src/app.c
index a792ade..37bf04b 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1944,6 +1944,22 @@ static node_t *pane_by_id(app_t *a, uint32_t id) {
return b.found;
}
+/* Naming a pane, for the double-click gesture and for a script: 0 is the focused
+ * one, and an empty name clears it.
+ *
+ * This is the whole answer to a program that keeps setting a title it stopped
+ * meaning -- an agent still spinning the summary of a task it finished, say.
+ * `pane_title` prefers a name only while there is one, so what a person or a
+ * script wrote outranks the program's own until they hand it back. Naming does
+ * not select the pane's tab, unlike the verbs that rearrange things: a label is
+ * not a reason to move what somebody is looking at. */
+bool app_set_pane_name(app_t *a, uint32_t id, const char *name) {
+ node_t *n = id ? pane_by_id(a, id) : cur(a)->focus;
+ if (!n) return false;
+ pane_set_name(n->pane, name);
+ return true;
+}
+
bool app_minimize(app_t *a, uint32_t id) {
node_t *n = id ? pane_by_id(a, id) : cur(a)->focus;
if (!n || n->minimized) return false;
@@ -5355,11 +5371,7 @@ static void rename_end(app_t *a, bool keep) {
what = "purpose";
done = app_set_pane_purpose(a, a->rename_id, a->rename_buf, true);
} else if (a->renaming == RENAME_PANE) {
- node_t *n = pane_by_id(a, a->rename_id);
- if (n) {
- pane_set_name(n->pane, a->rename_buf);
- done = true;
- }
+ done = app_set_pane_name(a, a->rename_id, a->rename_buf);
} else {
done = app_set_tab_name(a, a->rename_id, a->rename_buf);
}
diff --git a/src/app.h b/src/app.h
index 4559a55..f8025ba 100644
--- a/src/app.h
+++ b/src/app.h
@@ -82,6 +82,9 @@ void app_cycle_tab(app_t *a, int delta);
size_t app_tab_count(const app_t *a);
bool app_close_tab(app_t *a, uint32_t id);
bool app_set_tab_name(app_t *a, uint32_t id, const char *name);
+/* A pane's name, which outranks the title its program sets. 0 is the focused
+ * pane; an empty name clears it and hands the label back to the program. */
+bool app_set_pane_name(app_t *a, uint32_t id, const char *name);
/* Put a tab at a different position in the strip, 0-based. The strip is the
* order, so this is what dragging one does; you stay in the tab you were in. */
bool app_move_tab(app_t *a, uint32_t id, size_t index);
diff --git a/src/cmd.c b/src/cmd.c
index 32d6f4b..58e22e9 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -229,10 +229,18 @@ static char *cmd_json(app_t *a, screen_t *s, input_parser_t *in,
: jerr("no such tab");
}
if (strcmp(cmd, "set-name") == 0) {
- return app_set_tab_name(a, (uint32_t)jv_geti(req, "id", 0),
- jv_gets(req, "name", ""))
- ? jok_int(NULL, 0)
- : jerr("no such tab");
+ /* `target`, exactly as `set-purpose` already has it, because a name is a
+ * label on either thing. The default stays `tab`: that is what this verb has
+ * always meant, and a verb quietly changing its subject would be worse than
+ * two verbs with different defaults. Naming a pane is how a stale title gets
+ * overruled, so the id may be 0 for the focused one. */
+ const char *target = jv_gets(req, "target", "tab");
+ uint32_t id = (uint32_t)jv_geti(req, "id", 0);
+ const char *name = jv_gets(req, "name", "");
+ bool pane = strcmp(target, "pane") == 0;
+ bool ok = pane ? app_set_pane_name(a, id, name)
+ : app_set_tab_name(a, id, name);
+ return ok ? jok_int(NULL, 0) : jerr(pane ? "no such pane" : "no such tab");
}
if (strcmp(cmd, "set-purpose") == 0) {
const char *target = jv_gets(req, "target", "pane");