diff options
| author | user <user@clank> | 2026-08-17 13:38:33 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-17 13:38:33 +0200 |
| commit | 7a91885c3b063c8d231daceb2b2e29e1f1a81aa6 (patch) | |
| tree | 7210a201bc59bd0c871cbc82afc21de16d3959b5 /src | |
| parent | sl0ppty: a --script pane is told no session rather than somebody else's (diff) | |
| download | slosh-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.c | 22 | ||||
| -rw-r--r-- | src/app.h | 3 | ||||
| -rw-r--r-- | src/cmd.c | 16 |
3 files changed, 32 insertions, 9 deletions
@@ -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); } @@ -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); @@ -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"); |
