aboutsummaryrefslogtreecommitdiffstats
path: root/src/pane.c
diff options
context:
space:
mode:
authoruser <user@clank>2026-09-22 15:12:02 +0200
committeruser <user@clank>2026-09-22 15:12:02 +0200
commit720aa48e249c0c962e8f73372ceded6092414a6e (patch)
treedb713dc86f1333dab0f509e633077384005562c3 /src/pane.c
parentsidebar: air inside it, the way panes have padding (tab_bar_padding) (diff)
downloadslosh-720aa48e249c0c962e8f73372ceded6092414a6e.tar.gz
slosh-720aa48e249c0c962e8f73372ceded6092414a6e.tar.xz
slosh-720aa48e249c0c962e8f73372ceded6092414a6e.zip
osc 5577: `busy`, and a sidebar that shows it (busy_mark)
A status is a line of text, and a line of text cannot say whether it is still true. "building 3/7" reads exactly the same while it builds and ten minutes after it stopped, which is the one thing somebody reading it from another tab wants to know -- and the only workaround available to a program was to write the answer into the words and keep rewriting them. So `busy`: printf '\033]5577;1;status;make test\033\\' printf '\033]5577;1;busy;1\033\\' ... printf '\033]5577;1;busy;0\033\\' A flag of its own rather than a field of `status`, because a status is the *whole* payload after the verb -- `status;a;b;c` has always been the text "a;b;c" -- so anything added to that line would change what every existing sender means, including the five pi extensions D1 promises byte compatibility to. Orthogonal, so a program can leave one line up and toggle the other; anything but 0/false/no/off is on; `clear` takes both; and a pane whose program has gone is never busy, whatever it last claimed, because a spinner turning under a dead tab is a lie you keep looking at. In a sidebar the row turns `tab_status_busy` -- the theme's accent, derived like the other status colours, so no theme needs a line -- and takes a spinner in the column `tab_bar_padding` was already holding blank, so nothing reflows when a program starts or stops working. `busy_mark` is the frames, separated by spaces: one frame is a static mark and costs nothing, several make it turn, and only then does the session keep a frame clock -- via the same `animating` flag an animated shader uses, so the cost lands only while such a row is actually composed, and `""` drops the mark entirely and leaves the colour to say it. The frame is a pure function of the clock, like every other pulse here, so two clients attached to one session show the same one. `panes` now reports `status` and `busy`, which is the scriptable half of the same fact: what a pane says about itself, without reading its screen.
Diffstat (limited to 'src/pane.c')
-rw-r--r--src/pane.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/src/pane.c b/src/pane.c
index 47db104..b9b3f44 100644
--- a/src/pane.c
+++ b/src/pane.c
@@ -99,6 +99,12 @@ struct pane {
osc_scan_t scan;
char status[256];
+ /* Whether what the status describes is still happening. Its own flag rather
+ * than a field of the status text, because the text is the *whole* payload
+ * after the verb (`status;a;b;c` is "a;b;c") and always has been -- adding a
+ * field to it would change what every existing sender means. Orthogonal, so
+ * a program can leave one line up and toggle the other. */
+ bool busy;
pane_button_t buttons[8];
size_t nbuttons;
pane_osc_fn osc_cb;
@@ -115,6 +121,7 @@ void pane_set_osc_handler(pane_t *p, pane_osc_fn fn, void *ud) {
}
const char *pane_status(const pane_t *p) { return p->status; }
+bool pane_status_busy(const pane_t *p) { return p->busy && p->alive; }
size_t pane_buttons(const pane_t *p, const pane_button_t **out) {
*out = p->buttons;
return p->nbuttons;
@@ -176,10 +183,20 @@ static void on_osc5577(const char *verb, const char *payload, void *ud) {
if (strcmp(verb, "status") == 0) {
snprintf(p->status, sizeof p->status, "%s", payload);
p->dirty = true;
+ } else if (strcmp(verb, "busy") == 0) {
+ /* "is this still happening?" -- the one thing a line of text cannot say
+ * about itself. Off for the spellings of no, on for everything else
+ * including an empty payload, because `busy` with nothing after it is a
+ * program saying it is busy. */
+ bool on = !(strcmp(payload, "0") == 0 || strcmp(payload, "false") == 0 ||
+ strcmp(payload, "no") == 0 || strcmp(payload, "off") == 0);
+ if (p->busy != on) p->dirty = true;
+ p->busy = on;
} else if (strcmp(verb, "buttons") == 0) {
parse_buttons(p, payload);
} else if (strcmp(verb, "clear") == 0) {
p->status[0] = 0;
+ p->busy = false;
p->nbuttons = 0;
p->dirty = true;
} else if (strcmp(verb, "hello") == 0) {
@@ -690,6 +707,7 @@ bool pane_restart(pane_t *p) {
* status line and buttons from a program that is not there describe
* nothing, and the new run gets to say its own. */
p->status[0] = 0;
+ p->busy = false;
p->nbuttons = 0;
osc_scan_reset(&p->scan);
p->exit_known = false;