aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-14 16:46:42 +0200
committeruser <user@clank>2026-08-14 16:46:42 +0200
commit18e96314d5a4ea62b16ae0c9cb1558985d270800 (patch)
tree76be4a915fef5e16beb1dc36eb8fe67ab7b5824d /src
parentsl0ppty: the status line counts this tab's panes (diff)
downloadslosh-18e96314d5a4ea62b16ae0c9cb1558985d270800.tar.gz
slosh-18e96314d5a4ea62b16ae0c9cb1558985d270800.tar.xz
slosh-18e96314d5a4ea62b16ae0c9cb1558985d270800.zip
sl0ppty: the status line says which pane, not just how many
A bare count answered "how big is this tab" and left "where am I in it" to be worked out by counting frames — which is exactly the question you have once a tab has collapsed into a list and only one pane is open, and exactly when counting frames stops working. It reads `pane 2/5` now. It also stops looking like the session count in the opposite corner. Two numbers in two corners, both rendered "N panes" and disagreeing, was a puzzle the reader had to solve once and then remember. Both bars also take a `status_pad` for how far they are held off the left and right edges. They were using `gap * gap_aspect`, which is the space around the *panes*: the two match at the defaults and there was never a reason they had to be the same number. The count is kept as a fallback for when nothing is focused, which should not happen but says something true if it does.
Diffstat (limited to 'src')
-rw-r--r--src/app.c31
-rw-r--r--src/config.c5
-rw-r--r--src/config.h4
3 files changed, 32 insertions, 8 deletions
diff --git a/src/app.c b/src/app.c
index c013ed2..824bb98 100644
--- a/src/app.c
+++ b/src/app.c
@@ -270,7 +270,8 @@ size_t app_toast_count(app_t *a) {
return a->ntoasts;
}
-static size_t count_leaves(node_t *n); /* defined with the layout */
+static size_t count_leaves(node_t *n); /* both defined with the layout */
+static size_t collect_leaves(node_t *n, node_t **out, size_t cap, size_t k);
/* The line along the bottom: what you are looking at, rather than what you
* could switch to. The strip along the top already answers "which tab" and
@@ -283,8 +284,9 @@ static size_t count_leaves(node_t *n); /* defined with the layout */
static void draw_status_line(app_t *a, screen_t *s) {
if (!CFG.status_line || s->rows < 3) return;
uint16_t y = (uint16_t)(s->rows - CFG.gap - 1);
- uint16_t x = (uint16_t)(CFG.gap * CFG.gap_aspect);
- uint16_t right = (uint16_t)(s->cols > x ? s->cols - x : 0);
+ uint16_t x = CFG.status_pad;
+ uint16_t right =
+ (uint16_t)(s->cols > CFG.status_pad ? s->cols - CFG.status_pad : 0);
if (right <= x) return;
node_t *f = a->ntabs ? cur(a)->focus : NULL;
@@ -298,9 +300,21 @@ static void draw_status_line(app_t *a, screen_t *s) {
* a thing that does not. This count is *this tab's*; the strip above counts
* the whole session, which is why they can disagree. */
if (a->ntabs && cur(a)->root) {
- char cnt[32];
- size_t np = count_leaves(cur(a)->root);
- snprintf(cnt, sizeof cnt, "%zu pane%s", np, np == 1 ? "" : "s");
+ /* Which of this tab's panes, out of how many — the count alone answers
+ * "how big is this tab" and leaves "where am I in it" to be worked out by
+ * counting frames, which is the question you actually have when a tab has
+ * collapsed into a list and only one of them is open. */
+ node_t *leaves[64];
+ size_t nl = collect_leaves(cur(a)->root, leaves, 64, 0);
+ size_t idx = 0;
+ for (size_t i = 0; i < nl; i++)
+ if (leaves[i] == f) idx = i + 1;
+
+ char cnt[40];
+ if (idx)
+ snprintf(cnt, sizeof cnt, "pane %zu/%zu", idx, nl);
+ else /* nothing focused: still say how many there are */
+ snprintf(cnt, sizeof cnt, "%zu pane%s", nl, nl == 1 ? "" : "s");
uint16_t cw = (uint16_t)strlen(cnt);
if (right > x + cw + 2) {
screen_text(s, (uint16_t)(right - cw), y, cnt, FRAME_IDLE, NO_COLOR, 0);
@@ -1876,12 +1890,13 @@ static void draw_cb(node_t *n, void *ud) {
}
static void draw_tab_strip(app_t *a, screen_t *s) {
- uint16_t x = (uint16_t)(CFG.gap * CFG.gap_aspect);
+ uint16_t x = CFG.status_pad;
uint16_t y = CFG.gap;
/* Right side first, so a long tab list can never eat the indicators — the
* same budgeting rule as the split button and the OSC buttons. */
- uint16_t right = (uint16_t)(s->cols - CFG.gap * CFG.gap_aspect);
+ uint16_t right = (uint16_t)(s->cols > CFG.status_pad ? s->cols - CFG.status_pad
+ : s->cols);
char info[64];
size_t np = app_pane_count(a);
snprintf(info, sizeof info, "%zu pane%s", np, np == 1 ? "" : "s");
diff --git a/src/config.c b/src/config.c
index e0a40fe..142776c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -179,6 +179,9 @@ void config_defaults(config_t *c) {
c->double_click_ms = 400;
c->status_bar = true;
c->status_line = true;
+ /* Matches gap * gap_aspect at the defaults, so the strip lines up with the
+ * panes' outer edge until you say otherwise. */
+ c->status_pad = 2;
c->focus_follows_mouse = true;
c->default_fg = rgb(0xff, 0xff, 0xff);
@@ -297,6 +300,8 @@ bool config_load(config_t *c, const char *path, char *err, size_t errcap) {
c->status_bar = kdl_arg_bool(kdl_child(root, "status_bar"), 0, c->status_bar);
c->status_line =
kdl_arg_bool(kdl_child(root, "status_line"), 0, c->status_line);
+ c->status_pad =
+ (uint16_t)kdl_arg_int(kdl_child(root, "status_pad"), 0, c->status_pad);
c->focus_follows_mouse = kdl_arg_bool(kdl_child(root, "focus_follows_mouse"), 0,
c->focus_follows_mouse);
diff --git a/src/config.h b/src/config.h
index a85a204..9d0b022 100644
--- a/src/config.h
+++ b/src/config.h
@@ -112,6 +112,10 @@ typedef struct {
size_t state_n[PSTATE_COUNT];
bool status_bar; /* the strip along the top: tabs, prefix, pane count */
bool status_line; /* the line along the bottom: what you are looking at */
+ /* How far the strip and the line are held off the left and right edges.
+ * Separate from `gap`, which is the space around the *panes*: the two happen
+ * to match by default and there is no reason they must. */
+ uint16_t status_pad;
bool focus_follows_mouse;
/* What a cell's "terminal default" colour resolves to when a shader has to