diff options
| author | user <user@clank> | 2026-08-20 23:22:33 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-20 23:22:33 +0200 |
| commit | b33e8c13ff7981effc7ec2735e6aeaaaf1705af7 (patch) | |
| tree | 4933eb476b5d09e9d8131986c84bb966bca317a2 /tests/test_palette.py | |
| parent | fuzz: libFuzzer harness for all six parser surfaces (diff) | |
| download | slosh-b33e8c13ff7981effc7ec2735e6aeaaaf1705af7.tar.gz slosh-b33e8c13ff7981effc7ec2735e6aeaaaf1705af7.tar.xz slosh-b33e8c13ff7981effc7ec2735e6aeaaaf1705af7.zip | |
slosh: floating panes and the drop grammar
A pane can float: lifted out of the layout, drawn over the tiled panes and
under the modals, freely moved and shaped. The model is a flag and a rect on
the leaf, exactly like `minimized` -- the seat in the tree is kept, layout
skips it, the siblings absorb its share, and un-floating returns it home.
The drawn rect is the wanted one clamped to the tab every frame, never
written back, so a terminal squeeze round-trips exactly; an explicit move or
resize *does* write back, because the hand is the author of the intent.
Floating pops the pane to the centre: the jump is what says it happened.
Painted after everything tiled, so the hit list -- searched backwards --
resolves an overlap to the float you can see: the z-order and the click
order are the same list. It casts a shadow (float_shadow, one number), and
`floating` joins the states table above `unfocused`, so a float is never
dimmed as merely-unfocused.
The hands: the title moves it, any other border resizes it (a bottom corner
on both axes; the grabbed edge pins at walls and floors, never sliding the
window), H J K L move a focused float, the =/+ key grows it about its
centre, `-` shrinks it (its split was a refusal anyway), and hovering shows
which edges a grab would take, from the same derivation the press uses.
Equalize moved to `0` to free the key; `C-a f` floats (finder went to `s`,
where it reads as search); `C-a F` opens a new floating shell -- the
throwaway terminal; the function row f1..f12 became nameable in configs
along the way. Guards throughout: the last tiled pane cannot float or
minimize away, closing it lands the top float, splits are refused with
their own words, floats are not swap targets.
Dropping got a grammar: while a pane is carried, the pane under the pointer
subdivides into a swap centre and four edge bands meaning "insert me beside
this pane, on this side" -- detach_leaf + place_beside, the surgery
cross-tab moves already had. Bands are thirds (the first map of quarters
showed the swap owning half of each axis), the hovered band fills the half
the drop would hand over, the release resolves against the painted frame's
hits so it cannot disagree with the fill, and a drop between siblings along
the axis is a reorder that always fits -- refusing it was refusing the most
ordinary drag there is.
Also: rename-pane/rename-tab as palette actions (renaming was a
double-click and nothing else, the one verb the palette could not reach),
and C-u clears the rename editor like it clears the picker's query.
Design log in PLAN-FLOATING-PANES.md; to fold into DESIGN.md as D22/M10-11.
Diffstat (limited to 'tests/test_palette.py')
| -rw-r--r-- | tests/test_palette.py | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/tests/test_palette.py b/tests/test_palette.py index 9741227..fbd2e47 100644 --- a/tests/test_palette.py +++ b/tests/test_palette.py @@ -151,6 +151,47 @@ def test_enter_runs_the_command(): check("and the palette closed behind it", not is_open(s)) +def test_rename_is_reachable_from_the_palette(): + """Renaming was a double-click and nothing else, which made it the one + verb the palette could not reach -- exactly what the palette exists to + prevent. The editor it opens is the same in-place one the gesture uses, + seeded with the current label.""" + with Session(SH, cols=80, rows=22) as s: + s.settle() + s.send(OPEN) + s.send("rename this tab") + s.settle(80) + s.send(r"\r") + s.settle(80) + s.send("deploys") + s.settle(40) + s.send(r"\r") + s.settle(40) + check( + "rename-tab renames the tab in place", + [t["name"] for t in s.tabs()] == ["deploys"], + str(s.tabs()), + ) + + s.send(OPEN) + s.send("rename this pane") + s.settle(80) + s.send(r"\r") + s.settle(80) + # The editor seeds with the current title (a rename is an edit); + # clear it first so the name is what was typed. + s.send(r"\x15") # C-u: clear the field + s.send("agent") + s.settle(40) + s.send(r"\r") + s.settle(40) + check( + "rename-pane renames the pane in place", + [p["title"] for p in s.panes()] == ["agent"], + str([p["title"] for p in s.panes()]), + ) + + def test_clicking_a_row_runs_it(): with Session(SH, cols=80, rows=22) as s: s.settle() @@ -234,7 +275,7 @@ def test_the_finder_is_still_its_own_thing(): """They share a box; they must not share a list.""" with Session(SH, cols=80, rows=22) as s: s.settle() - s.send(r"\x01f") + s.send(r"\x01s") s.settle(100) check( "the finder lists panes, not commands", @@ -269,6 +310,7 @@ def test_every_label_fits_the_column(): if __name__ == "__main__": test_every_label_fits_the_column() + test_rename_is_reachable_from_the_palette() test_it_opens_and_lists_commands() test_it_lists_actions_that_have_no_key() test_typing_filters_it() |
