diff options
| author | user <user@clank> | 2026-09-29 14:26:28 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-09-29 14:26:28 +0200 |
| commit | ca1b5bdf5bf7b5ff01ab515846802b3487599d3a (patch) | |
| tree | a047fc09bccbe077b98acd0bf2648c2e02616b04 /src/app_session.c | |
| parent | panes: read and write a pane by id, without taking focus (diff) | |
| download | slosh-ca1b5bdf5bf7b5ff01ab515846802b3487599d3a.tar.gz slosh-ca1b5bdf5bf7b5ff01ab515846802b3487599d3a.tar.xz slosh-ca1b5bdf5bf7b5ff01ab515846802b3487599d3a.zip | |
layouts, moves: build panes without pulling the view to them
Applying a layout landed on the first tab it made, and moving a pane into a
tab took focus there. For a program building a pane in the background that
is two failures at once: it yanks the view off the human mid-sentence, and
it leaves the *next* caller to read focus as "where I am" and put its work
in a stranger's tab.
`apply-layout focus:false` builds the tabs and keeps looking at whatever was
on screen; a layout naming an `active` tab still wins, because that is a
statement about where to be. `move-pane` gains `beside` (which pane in the
destination to split, rather than whatever it has focused) and `focus:false`
-- the two things a caller placing a pane next to *itself* needs.
That uncovered a sizing bug that was unreachable before: a pane's size comes
from a layout pass, and a tab nobody has looked at never had one, so a pane
built in the background stayed 1x1 and its program drew into a single cell.
The jump is what used to size it. layout_tab() gives a background tab a real
pass, borrowing the tab cursor for its length -- nothing composes, reads
input or draws a frame in between.
Diffstat (limited to 'src/app_session.c')
| -rw-r--r-- | src/app_session.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/src/app_session.c b/src/app_session.c index 716b5d1..8900088 100644 --- a/src/app_session.c +++ b/src/app_session.c @@ -147,6 +147,10 @@ static node_t *build_pane(app_t *a, const kdl_node_t *node, const char *cwd, bool app_apply_layout(app_t *a, const kdl_node_t *root, bool replace, const char *base, char *err, size_t errcap) { + /* Taken and cleared up front, so one request's "keep my view" cannot leak + * into the next layout applied for any other reason. */ + bool keep_view = a->layout_keep_view; + a->layout_keep_view = false; a->restore_tab = (size_t)-1; const kdl_node_t *lay = kdl_child(root, "layout"); if (!lay) lay = root; /* allow a bare list of tabs */ @@ -227,13 +231,24 @@ bool app_apply_layout(app_t *a, const kdl_node_t *root, bool replace, a->restore_tab -= before; if (a->restore_tab != (size_t)-1 && a->restore_tab < a->ntabs) a->cur = a->restore_tab; - else + else if (!keep_view) a->cur = replace ? 0 : before; + else if (a->cur >= a->ntabs && a->ntabs) + a->cur = a->ntabs - 1; /* the view we kept is gone (replace): clamp */ a->restore_tab = (size_t)-1; layout(a); + /* Every tab this layout built gets a pass, on screen or not: a pane's size + * comes from a layout pass, and `focus:false` means nobody is going to look + * at these and give them one. Without it a background pane runs at 1x1 -- + * which used to be impossible to hit only because applying a layout always + * jumped the view to it. */ + if (keep_view && !replace) + for (size_t i = before; i < a->ntabs; i++) layout_tab(a, i); return true; } +void app_layout_keep_view(app_t *a) { a->layout_keep_view = true; } + bool app_apply_layout_text_at(app_t *a, const char *text, bool replace, const char *base, char *err, size_t errcap) { kdl_node_t *root = kdl_parse(text, err, errcap); |
