diff options
| author | user <user@clank> | 2026-08-16 19:13:28 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-16 19:13:28 +0200 |
| commit | c58d873b409c7a166a64ceabf178692b0b4467c2 (patch) | |
| tree | 45ed8190996bfa1c7b59309c1b07d50f5dadae19 /src/cmd.c | |
| parent | sl0ppty: the prompt speaks config, not a dialect of it (diff) | |
| download | slosh-c58d873b409c7a166a64ceabf178692b0b4467c2.tar.gz slosh-c58d873b409c7a166a64ceabf178692b0b4467c2.tar.xz slosh-c58d873b409c7a166a64ceabf178692b0b4467c2.zip | |
sl0ppty: a pane can change tabs
sl0ppty cmd '{"cmd":"move-pane","id":3,"tab":2}'
sl0ppty cmd '{"cmd":"move-pane","id":3,"tab":2,"dir":"rows"}'
sl0ppty cmd '{"cmd":"move-pane","id":3,"tab":0,"name":"logs"}'
The mechanism only. There is no key and no gesture for it yet -- that is the next
conversation, and guessing at it now would mean building the wrong one twice.
**The pane keeps running.** Measured, not assumed: `pid=3062557` before the move
and `pid=3062557` after, in a different tab, with its scrollback intact and still
answering what it is sent. That is the whole reason to move a pane rather than open
one where you wanted it and close this one.
It is tree surgery and it reuses the surgery that was already here. `place_beside`
is the second half of `split_node_with` -- everything after "make the leaf" --
lifted out so that a leaf which already exists somewhere else can be grafted the
same way, flat sibling or new split, on either side. It takes the tab rather than
`cur(a)` now, because replacing a root has to land on the right one and `cur(a)` was
only right while the sole caller was splitting the pane you were looking at.
`detach_leaf` is `close_leaf` without the funeral.
Three decisions worth naming:
**The destination is a tab id, not an index.** A tab whose last pane leaves has
nothing to be, so it is removed -- and every index after it moves. An id survives
that; an index quietly means a different tab. The move re-finds the destination by
id *after* the removal for exactly this reason, and there is a test that empties a
tab and checks the pane landed where it was sent.
**A move drops what the old tab thought about the pane** -- a zoom naming it, and
its minimised flag. Both are the tab's opinion and not the pane's: carried across,
the first zooms a pane that has left and the second files the arrival in a strip
nobody asked for.
**It does not follow the pane.** Which tab you are looking at is a question about
intent, and this is the mechanism; `move-pane` answers with the tab id so a caller
can select it if that is what it meant. "Into a tab of its own" is its own call
rather than new-tab-then-move, because a pane that is the only thing in its tab
would otherwise have its tab removed from under the new one, and the order those
two happen in is precisely the bug.
Verified: `tests/test_move_pane.py`, 25 checks -- the pane still running and still
talking afterwards, placement beside and under the destination's focus, focus
landing on the arrival, the emptied tab, a tab of its own, every refusal (no such
pane, no such tab, already there, already alone), the dropped zoom and minimise,
and after three moves a layout with no overlaps that dumps and rebuilds as itself.
Diffstat (limited to 'src/cmd.c')
| -rw-r--r-- | src/cmd.c | 15 |
1 files changed, 15 insertions, 0 deletions
@@ -176,6 +176,21 @@ static char *cmd_json(app_t *a, screen_t *s, input_parser_t *in, bool had = app_clear_pane_shaders(a, (uint32_t)jv_geti(req, "id", 0)); return jok_int("cleared", had ? 1 : 0); } + /* `tab` is an id, `0` a tab of its own -- the same "0 means the obvious thing" + * the pane arguments use. `dir` decides beside or under, like `split`. */ + if (strcmp(cmd, "move-pane") == 0) { + uint32_t pid = (uint32_t)jv_geti(req, "id", 0); + uint32_t tid = (uint32_t)jv_geti(req, "tab", 0); + bool rows = strcmp(jv_gets(req, "dir", "cols"), "rows") == 0; + if (!tid) { + uint32_t made = app_move_pane_to_new_tab(a, pid, jv_gets(req, "name", "")); + 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"); + return jok_int("tab", (long long)tid); + } if (strcmp(cmd, "new-tab") == 0) { uint32_t id = app_new_tab(a, jv_gets(req, "name", "")); if (!id) return jerr("cannot create tab"); |
