Skip to content

refactor(orzmux): make a tab's layout tree non-empty by type - #389

Merged
not-elm merged 4 commits into
rename-workspace-to-tabfrom
nonempty-layout-tree
Oct 1, 2026
Merged

not-elm merged 4 commits into
rename-workspace-to-tabfrom
nonempty-layout-tree

Conversation

@not-elm

@not-elm not-elm commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Problem

A LayoutTree could be empty (root: Option<Node>, active() -> Option<PaneId>). retire_pane emptied the tree and removed the tab a few lines later, so "a tab has a pane" held only by call order.

Solution

orzmux::backend, with no change in behavior:

  • A LayoutTree is built only by with_root and always holds a pane: root is a Node, active() returns a PaneId, and Default and is_empty() are gone.
  • The consuming remove(self, pane) hands the tree back as Absent, Removed, or Last; removing the only pane leaves the tree unchanged.
  • Tabs::remove_pane drops the whole tab on Last. retire_pane and the rollback of a failed spawn both go through it.
  • LayoutTree::solve is renamed to tile, returning Tiling, and OrzmuxError::Unsolved to NoPaneRect: the method subdivides the window and cannot fail, and the error reports a pane with no rectangle.
  • LayoutTree::split no longer takes the window size. Whether the target has room is a policy of the moment, so Tabs::split_active asks the new Tiling::can_split before splitting. A missing target is UnresolvedTarget; SplitRefused now means only too little room.
  • The layout tests move from layout.rs to layout/tests/, one file per operation.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@not-elm not-elm added the skip-changelog Exclude this PR from the release notes label Oct 1, 2026
@not-elm
not-elm added this pull request to stack #391 October 1, 2026 07:20
notelm and others added 3 commits October 1, 2026 16:51
Move the inline `tests` module of `backend/layout.rs` to
`backend/layout/tests.rs`, which keeps the shared fixtures, and to one
file each for `split`, `remove`, `solve`, `select_direction`,
`resize_split`, and `resize_direction`. The tests themselves are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing here solves constraints: the method folds minimum sizes and
subdivides the window top-down. Call it `tile`, returning `Tiling`,
with `Node::tile_into` underneath, and move the tests to `tests/tile.rs`.

`OrzmuxError::Unsolved` becomes `NoPaneRect`. The computation cannot
fail; the variant reports that the new pane has no rectangle because
its tab is gone or the tab's tree does not hold it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`LayoutTree::split` took the window size only to refuse a target too
small to divide, although the tree stores ratios and a tree split past
its room is still a valid tree. The room is a policy applied when a
pane is split, so it moves to the caller: `Tiling::can_split` answers
whether a pane's rectangle holds two minimum leaves and a separator,
and `Tabs::split_active` asks it before splitting.

`split` no longer takes a window and reports a missing target as
`UnresolvedTarget`, leaving `SplitRefused` to mean too little room.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@not-elm
not-elm merged commit cb50fe7 into main Oct 1, 2026
10 checks passed
@not-elm
not-elm deleted the nonempty-layout-tree branch October 1, 2026 10:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changelog Exclude this PR from the release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant