aboutsummaryrefslogtreecommitdiffstats
path: root/src/cmd.c
diff options
context:
space:
mode:
authoruser <user@clank>2026-09-29 14:26:28 +0200
committeruser <user@clank>2026-09-29 14:26:28 +0200
commitca1b5bdf5bf7b5ff01ab515846802b3487599d3a (patch)
treea047fc09bccbe077b98acd0bf2648c2e02616b04 /src/cmd.c
parentpanes: read and write a pane by id, without taking focus (diff)
downloadslosh-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/cmd.c')
-rw-r--r--src/cmd.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/src/cmd.c b/src/cmd.c
index 39a55db..a310e2a 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -271,8 +271,15 @@ static char *cmd_json(app_t *a, screen_t *s, input_parser_t *in,
if (!made) return jerr("cannot move it to a tab of its own");
return jok_int("tab", (long long)made);
}
- if (!app_move_pane_to_tab(a, pid, tid, rows))
- return jerr("cannot move it there");
+ /* `beside` says which pane in the destination to land next to, and
+ * `focus:false` says not to take focus (and so not to pull the view)
+ * on arrival: the two things a caller placing a pane beside *itself*
+ * needs, neither of which can be expressed by "that tab's focus". */
+ uint32_t beside = (uint32_t)jv_geti(req, "beside", 0);
+ bool take_focus = jv_getb(req, "focus", true);
+ if (!app_move_pane_beside(a, pid, tid, beside, rows, take_focus))
+ return jerr(beside ? "cannot move it there (is `beside` in that tab?)"
+ : "cannot move it there");
return jok_int("tab", (long long)tid);
}
if (strcmp(cmd, "new-tab") == 0) {
@@ -352,6 +359,9 @@ static char *cmd_json(app_t *a, screen_t *s, input_parser_t *in,
const char *path = jv_gets(req, "path", NULL);
const char *text = jv_gets(req, "kdl", NULL);
bool replace = jv_getb(req, "replace", false);
+ /* `focus:false` builds the tabs without going to them. A layout that names
+ * an `active` tab still wins -- that is a statement about where to be. */
+ if (!jv_getb(req, "focus", true)) app_layout_keep_view(a);
char err[256] = {0};
bool ok = text ? app_apply_layout_text(a, text, replace, err, sizeof err)
: path ? app_apply_layout_file(a, path, replace, err, sizeof err)