Repository navigation
Add horizontally scrolling columns to cmux-tui - #8850
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds viewport-width pane creation through ChangesViewport pane layout
Estimated code review effort: 5 (Critical) | ~100 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant App
participant Session
participant Mux
participant LayoutEngine
participant Renderer
User->>App: Press Ctrl-b g
App->>Session: Create right viewport pane
Session->>Mux: new_pane_right
Mux->>LayoutEngine: Store viewport split and compute virtual width
LayoutEngine-->>Mux: Viewport pane geometry
Mux-->>Session: Created surface
Session-->>App: Update screen state
App->>LayoutEngine: Compute clipped viewport layout
LayoutEngine-->>App: Logical pane placements
App->>Renderer: Draw cropped panes and scrollbar
Renderer-->>User: Render viewport and horizontal track
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (2 errors, 2 warnings)
✅ Passed checks (21 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR introduces horizontally scrollable viewport columns to cmux-tui:
Confidence Score: 5/5The change is safe to merge; the only finding is a cosmetic issue in one CLI success message. The viewport column and undo machinery is well-structured: capability gating protects older servers, the revision-fencing prevents stale confirmations from closing newer panes, and the 32-entry history cap bounds memory growth. Error paths are localized for both CLI and TUI surfaces, the renderer panic is caught and localized, and the horizontal scrollbar math is covered by unit tests including u16-boundary cases. The sole finding — the layout_undo_applied success message embedding an internal screen ID — is cosmetic and does not affect correctness or security. Files Needing Attention: No files require special attention; the cosmetic CLI message issue is in localization.rs. Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant App/CLI
participant OrderedSession
participant Session/Mux
participant Server
Note over User,Server: Ctrl-b g / new-pane-right
User->>App/CLI: Ctrl-b g (or CLI new-pane-right)
App/CLI->>OrderedSession: new_pane_right(pane, width, size)
OrderedSession->>Session/Mux: session.new_pane_right(pane, width, size)
Session/Mux->>Server: insert_layout_column_after + spawn PTY
Server-->>Session/Mux: SurfaceCreated(surface_id)
Session/Mux-->>OrderedSession: Ok(surface)
OrderedSession-->>App/CLI: SessionCompletionAction::SurfaceCreated
App/CLI-->>User: Viewport column appears (animated)
Note over User,Server: Ctrl-b U / undo-layout (pane-creating action)
User->>App/CLI: Ctrl-b U
App/CLI->>OrderedSession: undo_layout(pane, None, false)
OrderedSession->>Session/Mux: session.undo_layout(pane, None, false)
Session/Mux-->>OrderedSession: "ConfirmationRequired{revision, closes_panes}"
OrderedSession-->>App/CLI: "LayoutUndoConfirmation{pane, revision}"
App/CLI-->>User: Type CONFIRM to close pane(s)
User->>App/CLI: CONFIRM
App/CLI->>OrderedSession: undo_layout(pane, Some(revision), true)
OrderedSession->>Session/Mux: session.undo_layout(pane, Some(revision), true)
Session/Mux-->>OrderedSession: "Undone{screen, revision}"
App/CLI-->>User: Layout restored
Reviews (38): Last reviewed commit: "fix(cmux-tui): synchronize SDK versions ..." | Re-trigger Greptile |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cmux-tui/crates/cmux-tui/src/app.rs (1)
6482-6495: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winGate
SplitRightfor scrolling mode; it can produce partial-height "columns".
split_size_hint(Lines 6487-6495) adapts the size hint for scrolling-modeSplitRight, but nothing prevents the action itself (run_action'sAction::SplitRight, plusMenuAction::SplitRight) from running when the target pane is one row of a multi-row (Down-split) column — a fully supported scrolling-mode layout per this same PR's "vertical splits within columns" design.In that case the new sibling gets a different
rect.x(perwalk_scrollingincmux-tui-core/src/layout.rs) but only the partial height of that one row, sohorizontal_columns()buckets it into its own column that is shorter than the screen. Scrolling to that column leaves the remaining height blank.new_pane_smartwas already special-cased for scrolling mode (always usingcontent_area, bypassing this path entirely) —SplitRight/the%keybinding and the pane context-menu split action were not.Minimal fix: mirror the existing
resize_split/resize_focused_splitgating pattern and either no-opSplitRight(with a status message) or redirect it through the samenew_pane_smart-style full-height path wheneverself.config.layout.mode == PaneLayoutMode::Scrolling.🐛 Suggested minimal gating (mirrors existing resize_split pattern)
Action::SplitRight => { if let Some(pane) = pane { + if self.config.layout.mode == PaneLayoutMode::Scrolling { + self.status_message = + Some("Right splits are unavailable in scrolling layout; use Alt-n or `%` on a full-height pane".to_string()); + } else { self.split_pane(pane, SplitDir::Right)?; + } } }Also applies to: 6524-6550, 7729-7731, 10082-10086, 10133-10138
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui/src/app.rs` around lines 6482 - 6495, Gate all scrolling-mode SplitRight entry points so they cannot create a partial-height sibling: update run_action’s Action::SplitRight handling and the MenuAction::SplitRight path (including the related keybinding/context-menu routes) to mirror the existing resize_split/resize_focused_split gating. Either no-op with a status message or route through the full-height new_pane_smart-style path when layout mode is PaneLayoutMode::Scrolling, while preserving current behavior for other layout modes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@cmux-tui/crates/cmux-tui/src/app.rs`:
- Around line 6482-6495: Gate all scrolling-mode SplitRight entry points so they
cannot create a partial-height sibling: update run_action’s Action::SplitRight
handling and the MenuAction::SplitRight path (including the related
keybinding/context-menu routes) to mirror the existing
resize_split/resize_focused_split gating. Either no-op with a status message or
route through the full-height new_pane_smart-style path when layout mode is
PaneLayoutMode::Scrolling, while preserving current behavior for other layout
modes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 76903692-9933-4200-9cc5-4c3a80b0f2cb
📒 Files selected for processing (12)
cmux-tui/README.mdcmux-tui/crates/cmux-tui-core/src/layout.rscmux-tui/crates/cmux-tui-core/src/lib.rscmux-tui/crates/cmux-tui/src/app.rscmux-tui/crates/cmux-tui/src/config.rscmux-tui/crates/cmux-tui/src/main.rscmux-tui/crates/cmux-tui/src/ui/mod.rscmux-tui/crates/cmux-tui/src/ui/pane.rscmux-tui/crates/cmux-tui/src/ui/scrollbar.rscmux-tui/docs/configuration.mdcmux-tui/docs/keyboard.mdcmux-tui/docs/mouse.md
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
There was a problem hiding this comment.
Actionable comments posted: 13
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmux-tui/crates/cmux-tui-core/src/layout.rs`:
- Around line 531-545: Extract the shared viewport column geometry calculation
used by walk_viewport and the split-layout branch around a_rect, b_rect, and
split_area into a helper. Reuse it at both call sites for the fraction clamp and
width calculation so b_rect.x and the rendered viewport column remain identical,
preserving matches_boundary divider resolution.
In `@cmux-tui/crates/cmux-tui-core/src/mux.rs`:
- Around line 6204-6214: Prevent viewport layout probes from saturating u16
coordinates in both affected sites: cmux-tui/crates/cmux-tui-core/src/mux.rs
lines 6204-6214 and 6226-6236. Keep the 10,000-cell probe for tiled layout, but
use a bounded viewport probe width (such as 1,000) or otherwise scale it so
layout_screen_with_viewport cannot exceed u16::MAX; apply the same change
consistently to pane_neighbor and pane_focus_neighbor/focus_direction paths.
In `@cmux-tui/crates/cmux-tui-core/src/server.rs`:
- Around line 2119-2121: Extend the ApplyLayout request contract and handler to
accept and forward exported viewport_splits metadata to mux.apply_layout,
preserving viewport semantics during export/apply round trips. Add a round-trip
test covering export-layout followed by ApplyLayout, or explicitly document that
viewport metadata is intentionally not re-applicable.
In `@cmux-tui/crates/cmux-tui/src/app.rs`:
- Around line 10370-10399: The viewport-aware split lookup and viewport-split
exclusion are duplicated in resize_focused_split and resize_split. Extract this
logic into a shared exact_split_for_edge helper near the related resize methods,
then update both call sites to use it while preserving the existing active-pane,
area, pane, edge, and smallest-target selection behavior.
- Around line 10758-10765: Update the horizontal-scroll handling in
handle_horizontal_scroll so visible scrollbars do not consume wheel events
across the entire content_area. Apply the viewport scroll and early return only
when the pointer is on the horizontal scrollbar track or the pane content is
actually horizontally clipped; otherwise allow execution to reach
forward_pty_mouse_at.
In `@cmux-tui/crates/cmux-tui/src/cli.rs`:
- Around line 227-232: Update the help text for the new-pane-right VerbSpec to
state that the pane defaults to two-thirds width, while preserving the existing
optional --width behavior.
In `@cmux-tui/crates/cmux-tui/src/session/tree.rs`:
- Around line 352-363: Update the viewport_splits parsing in the remote snapshot
parser to retain entries only when width is finite and within the protocol range
0.1..=1.0. Continue ignoring entries with missing or invalid split/width fields,
so rejected entries are omitted and the existing fallback split ratio is used.
In `@cmux-tui/crates/cmux-tui/src/ui/graphics.rs`:
- Around line 17-18: Update the crop parameters used by place_image_cropped() to
replace source_x_px and source_width_px with a single optional horizontal crop
value such as source_crop_px: Option<(u32, u32)>. Build the `,x=...,w=...`
fragment only from that tuple, ensuring an offset cannot be supplied without its
corresponding width and preserving uncropped behavior when it is None.
In `@cmux-tui/crates/cmux-tui/src/ui/scrollbar.rs`:
- Around line 37-54: Update horizontal_offset_at and
horizontal_track_positions_map_to_offsets to map the position through the
thumb’s travel range rather than the full track, treating position as the thumb
centre; use horizontal_thumb_geometry’s thumb width and preserve clamping and
zero-range behavior. Ensure clicks and Drag::HorizontalScrollbar round-trip with
rendered geometry, and add the requested round-trip assertion covering
representative offsets.
In `@cmux-tui/docs/concepts.md`:
- Around line 39-42: Use the hyphenated compound modifier “two-thirds”
consistently in cmux-tui/docs/concepts.md lines 39-42 and
cmux-tui/docs/configuration.md lines 191-198, replacing each occurrence of “two
thirds” without changing the surrounding documentation.
In `@cmux-tui/README.md`:
- Around line 38-39: Update the README sentence describing the appended terminal
width to hyphenate “two-thirds,” so it reads “two-thirds of the viewport width.”
In `@cmux-tui/spec/commands.md`:
- Line 1152: Update the new-pane error-handling flow associated with
mux.new_pane_right so callers receive the stable user-facing error “pane
creation failed” instead of raw PTY or spawn details. Log the underlying failure
internally using the existing server/session logging mechanism, and update the
documented contract to describe the sanitized error.
- Line 1109: Update the command mappings in commands.md: remove --width
<fraction> from new-pane and add it to new-pane-right, matching the request
parameters and the existing CLI specification. Preserve the other new-pane and
new-pane-right flags unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 8618c6e4-9267-4154-aaad-e0d7fb2596fb
📒 Files selected for processing (27)
cmux-tui/README.mdcmux-tui/crates/cmux-tui-core/src/layout.rscmux-tui/crates/cmux-tui-core/src/lib.rscmux-tui/crates/cmux-tui-core/src/model.rscmux-tui/crates/cmux-tui-core/src/mux.rscmux-tui/crates/cmux-tui-core/src/server.rscmux-tui/crates/cmux-tui/src/app.rscmux-tui/crates/cmux-tui/src/cli.rscmux-tui/crates/cmux-tui/src/config.rscmux-tui/crates/cmux-tui/src/main.rscmux-tui/crates/cmux-tui/src/session/mod.rscmux-tui/crates/cmux-tui/src/session/tree.rscmux-tui/crates/cmux-tui/src/ui/graphics.rscmux-tui/crates/cmux-tui/src/ui/graphics_writer.rscmux-tui/crates/cmux-tui/src/ui/mod.rscmux-tui/crates/cmux-tui/src/ui/pane.rscmux-tui/crates/cmux-tui/src/ui/scrollbar.rscmux-tui/crates/cmux-tui/src/ui/terminal_grid.rscmux-tui/crates/cmux-tui/tests/cli.rscmux-tui/docs/concepts.mdcmux-tui/docs/configuration.mdcmux-tui/docs/keyboard.mdcmux-tui/docs/mouse.mdcmux-tui/docs/protocol.mdcmux-tui/spec/cli.mdcmux-tui/spec/commands.mdcmux-tui/spec/transports.md
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
cmux-tui/crates/cmux-tui-core/src/server.rs (1)
2130-2153: 🗄️ Data Integrity & Integration | 🟠 MajorViewport metadata still isn't round-trippable through apply-layout.
export_layout_jsonnow emitsviewport_splits/viewport_base_width, butCommand::ApplyLayoutstill only acceptslayout: LayoutRequest, and its handler still forwards just that layout tomux.apply_layout. Re-applying an exported layout therefore silently drops viewport column state. This was flagged on a previous commit and remains unresolved.Also applies to: 168-178, 3179-3189
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui-core/src/server.rs` around lines 2130 - 2153, Extend Command::ApplyLayout and its request parsing to accept viewport_splits and viewport_base_width alongside LayoutRequest. Update the ApplyLayout handler to forward these fields through mux.apply_layout, preserving them when reapplying JSON produced by export_layout_json, including empty or absent metadata behavior.cmux-tui/crates/cmux-tui/src/app.rs (1)
5717-5757: 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win
viewport_statesgrows without bound as screens are closed.
sync_viewport_motion/set_viewport_targetinsert aViewportMotionperScreenIdbut nothing removes entries when a screen is closed; the map only clears onreset_session_presentation. In a long-lived session with churning screens this retains one motion per historical screen, andviewport_animation_active/tick_viewport_animationiterate the whole map every idle tick. Prune against the live screen set when the tree is replaced.♻️ Suggested pruning hook (in `replace_tree`/`sync_layout`)
+ let live_screens = self + .tree + .workspaces + .iter() + .flat_map(|workspace| workspace.screens.iter()) + .map(|screen| screen.id) + .collect::<HashSet<_>>(); + self.viewport_states.retain(|screen, _| live_screens.contains(screen));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui/src/app.rs` around lines 5717 - 5757, Prune stale entries from viewport_states whenever the screen tree is replaced or synchronized, using the live ScreenId set from the current tree. Update the replace_tree/sync_layout flow rather than sync_viewport_motion or set_viewport_target, and retain motions only for screens still present so animation iteration cannot grow with closed screens.Source: Coding guidelines
♻️ Duplicate comments (5)
cmux-tui/spec/commands.md (2)
1107-1116: 🎯 Functional Correctness | 🟡 Minor
--widthdocumented onnew-pane, which doesn't accept it.
new-pane's Params table has nowidthfield, and its CLIallowedlist incli.rsdoesn't include"width"either — passing--widthtonew-panewill be rejected with "unexpected --width". This exact misplacement (move--widthtonew-pane-rightonly) was already flagged in a previous review round; this diff re-adds it tonew-pane's flags row instead of removing it.✏️ Proposed fix
-| Flags | `--pane <id> [--width <fraction>] [--cols <n> --rows <n>]` | +| Flags | `--pane <id> [--cols <n> --rows <n>]` |(applies to the
new-panerow at line 1112 only; thenew-pane-rightrow at line 1163 is already correct)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/spec/commands.md` around lines 1107 - 1116, Update the `new-pane` CLI mapping row to remove the unsupported `--width <fraction>` flag, leaving only its accepted pane, column, and row options. Keep the existing `new-pane-right` mapping unchanged, since it is the command that supports `--width`.
1149-1156: 🔒 Security & Privacy | 🟠 Major
new-pane-rightstill documents a raw spawn/PTY error string.Unlike
new-pane, which was updated to return a sanitizedpane creation failedmessage with "raw runtime details are logged internally only",new-pane-right's Errors table still lists "spawn or PTY error string" verbatim. This was flagged as a major security/privacy concern in a previous review round and remains unaddressed. As per coding guidelines, user-facing/API error bodies must not expose raw upstream errors and should state what happened in product terms.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/spec/commands.md` around lines 1149 - 1156, The new-pane-right Errors documentation still exposes raw spawn/PTY errors; update its error contract to describe the sanitized “pane creation failed” response and state that runtime details are logged internally only, matching new-pane. Retain the other documented conditions unchanged.Source: Coding guidelines
cmux-tui/crates/cmux-tui/src/cli.rs (1)
230-235: 📐 Maintainability & Code Quality | 🟡 MinorHelp text still says "two-thirds-width" despite the optional
--widthoverride.
new-pane-rightaccepts--width, so describing it as always two-thirds width is misleading. This was flagged on a previous commit and the text is unchanged.✏️ Proposed fix
- help: "Create a two-thirds-width viewport pane to the right.", + help: "Create a viewport pane to the right (default width: two-thirds).",🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui/src/cli.rs` around lines 230 - 235, Update the help text for the new-pane-right VerbSpec to describe the default right-pane sizing without implying it is always two-thirds width, while retaining that the optional width override is supported.cmux-tui/crates/cmux-tui/src/session/tree.rs (1)
346-376: 🎯 Functional Correctness | 🟡 MinorViewport widths from remote snapshots still aren't validated.
viewport_splitsandviewport_base_widthare parsed straight fromas_f64() as f32with no check against the protocol's documented0.1..=1.0range (or finiteness). A malformed/malicious remote response could injectNaN/Infinityor out-of-range widths into layout math. This was flagged on a previous commit forviewport_splits; the fix was never applied, andviewport_base_widthhas the same gap.🛡️ Proposed fix
+ viewport_base_width: value + .get("viewport_base_width") + .and_then(Value::as_f64) + .map(|width| width as f32) + .filter(|width| (0.1..=1.0).contains(width)), viewport_splits: value .get("viewport_splits") .and_then(Value::as_array) .map(|splits| { splits .iter() .filter_map(|value| { - Some((value.get("split")?.as_u64()?, value.get("width")?.as_f64()? as f32)) + let split = value.get("split")?.as_u64()?; + let width = value.get("width")?.as_f64()?; + (0.1..=1.0).contains(&width).then_some((split, width as f32)) }) .collect() }) .unwrap_or_default(),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui/src/session/tree.rs` around lines 346 - 376, Validate viewport widths in parse_screen before storing them: require finite values within the protocol’s inclusive 0.1..=1.0 range for both viewport_base_width and each viewport_splits width, rejecting invalid entries or the snapshot consistently with existing parsing behavior. Apply the same validation after as_f64 and before f64-to-f32 conversion, using the viewport_base_width and viewport_splits parsing paths.cmux-tui/crates/cmux-tui-core/src/mux.rs (1)
6379-6389: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winThe 10 000-cell probe can still saturate
u16for viewport layouts.Both neighbor helpers keep
Rect { width: 10_000, height: 10_000 }forlayout_screen_with_viewport. Unlike tiling, viewport columns appendround(10_000 * fraction)cells each (minimum 1 000 atMIN_VIEWPORT_PANE_WIDTH), so from roughly the 9th appended columnwalk_viewport'ssaturating_addclamps every further column to 65 535 and adjacency is computed from overlapping rects. A previous review flagged this and it was marked addressed, but the probe width is unchanged here — please confirm the fix landed elsewhere or bound the viewport probe (for examplewidth: 1_000) while keeping 10 000 for the tiled path.#!/bin/bash # Look for any bounding of the viewport probe width introduced elsewhere. rg -nP -C4 '10_000|65_535|probe' --type=rust cmux-tui/crates/cmux-tui-core/src/mux.rs rg -nP -C3 'saturating_add|virtual_width' --type=rust cmux-tui/crates/cmux-tui-core/src/layout.rsAlso applies to: 6402-6412
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui-core/src/mux.rs` around lines 6379 - 6389, Update the neighbor-helper probe dimensions used by layout_screen_with_viewport so viewport layouts use a bounded width (for example 1,000) rather than 10,000, preventing u16 saturation during appended-column calculation. Keep the 10,000-cell probe for the tiled layout path and preserve the existing height and adjacency behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmux-tui/crates/cmux-tui-core/src/mux.rs`:
- Around line 5106-5142: Avoid cloning layout snapshots for screens that do not
own the target pane: in split_with_viewport_width at
cmux-tui/crates/cmux-tui-core/src/mux.rs:5106-5142, continue when
!screen.root.contains(target) before calling screen.layout_snapshot(); in
set_ratio at cmux-tui/crates/cmux-tui-core/src/mux.rs:6229-6250, confirm the
screen owns pane before taking the snapshot. Preserve the existing mutation
behavior for matching screens.
- Around line 5232-5276: Extract the duplicated auto-layout rebuilding logic
from the column and non-column branches into a helper accepting &mut Node, &mut
Option<Vec<PaneId>>, and the new PaneId. Have the helper prune missing panes,
append the new pane, rebuild the default layout, and update the stored
auto-layout list; call it with the appropriate column or screen fields before
preserving projection synchronization for column layouts.
- Around line 6441-6462: Update the columns branch in swap_panes to detect when
pane and target are the same before mutating columns or setting changed. Return
false for this self-swap, matching the non-column Node::swap_leaves behavior, so
no projection sync, layout reset, undo entry, or change events are produced.
- Around line 6195-6204: Update the layout-columns branch around
expand_stack_pane to track whether either expansion call returns true, and call
sync_layout_column_projection only when at least one stack actually expanded.
Preserve the existing expansion calls and non-column behavior.
In `@cmux-tui/crates/cmux-tui/src/app.rs`:
- Around line 1886-1900: Introduce typed variants or a structured undo-error
type in cmux-tui-core’s Mux::undo_layout for unavailable and stale-revision
outcomes, preserving those distinctions through session.undo_layout and any
remote/error-wrapping paths. Update the enqueue_with_completion “undo layout”
handler to match the typed error/result variants rather than comparing
error.to_string() or using contains, mapping unavailable to
LayoutUndoUnavailable and stale revisions to LayoutUndoStale when confirm_close
is enabled.
In `@cmux-tui/crates/cmux-tui/src/localization.rs`:
- Line 198: Update the English and Japanese layout_undo_stale messages in
cmux-tui/crates/cmux-tui/src/localization.rs at lines 198-198 and 281-281 to
include a concrete “try undo again” recovery action and its Japanese equivalent,
then revise the localization assertions at lines 368-383 to match both updated
messages.
In `@cmux-tui/crates/cmux-tui/src/ui/pane.rs`:
- Around line 370-374: Clamp the raw-buffer copy in the pane rendering function
around visible_width and frame_buf so the loop never indexes beyond the frame’s
right edge. Account for bar.x plus the requested width, while preserving the
existing source_x/full_width clipping and early rejection for bars starting
outside the screen; ensure each (bar.x + dx, bar.y) coordinate is within frame
bounds.
In `@cmux-tui/spec/bindings.md`:
- Line 15: Update the Version check row in bindings.md to also require
viewport-splits-v1 for new-pane-right and viewport-column-resize-v1 for
set-viewport-pane-width, alongside the existing layout-undo-v1 requirement.
---
Outside diff comments:
In `@cmux-tui/crates/cmux-tui-core/src/server.rs`:
- Around line 2130-2153: Extend Command::ApplyLayout and its request parsing to
accept viewport_splits and viewport_base_width alongside LayoutRequest. Update
the ApplyLayout handler to forward these fields through mux.apply_layout,
preserving them when reapplying JSON produced by export_layout_json, including
empty or absent metadata behavior.
In `@cmux-tui/crates/cmux-tui/src/app.rs`:
- Around line 5717-5757: Prune stale entries from viewport_states whenever the
screen tree is replaced or synchronized, using the live ScreenId set from the
current tree. Update the replace_tree/sync_layout flow rather than
sync_viewport_motion or set_viewport_target, and retain motions only for screens
still present so animation iteration cannot grow with closed screens.
---
Duplicate comments:
In `@cmux-tui/crates/cmux-tui-core/src/mux.rs`:
- Around line 6379-6389: Update the neighbor-helper probe dimensions used by
layout_screen_with_viewport so viewport layouts use a bounded width (for example
1,000) rather than 10,000, preventing u16 saturation during appended-column
calculation. Keep the 10,000-cell probe for the tiled layout path and preserve
the existing height and adjacency behavior.
In `@cmux-tui/crates/cmux-tui/src/cli.rs`:
- Around line 230-235: Update the help text for the new-pane-right VerbSpec to
describe the default right-pane sizing without implying it is always two-thirds
width, while retaining that the optional width override is supported.
In `@cmux-tui/crates/cmux-tui/src/session/tree.rs`:
- Around line 346-376: Validate viewport widths in parse_screen before storing
them: require finite values within the protocol’s inclusive 0.1..=1.0 range for
both viewport_base_width and each viewport_splits width, rejecting invalid
entries or the snapshot consistently with existing parsing behavior. Apply the
same validation after as_f64 and before f64-to-f32 conversion, using the
viewport_base_width and viewport_splits parsing paths.
In `@cmux-tui/spec/commands.md`:
- Around line 1107-1116: Update the `new-pane` CLI mapping row to remove the
unsupported `--width <fraction>` flag, leaving only its accepted pane, column,
and row options. Keep the existing `new-pane-right` mapping unchanged, since it
is the command that supports `--width`.
- Around line 1149-1156: The new-pane-right Errors documentation still exposes
raw spawn/PTY errors; update its error contract to describe the sanitized “pane
creation failed” response and state that runtime details are logged internally
only, matching new-pane. Retain the other documented conditions unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: fea47a26-e520-4a86-9673-87d946260a16
📒 Files selected for processing (29)
cmux-tui/README.mdcmux-tui/crates/cmux-tui-core/src/layout.rscmux-tui/crates/cmux-tui-core/src/lib.rscmux-tui/crates/cmux-tui-core/src/model.rscmux-tui/crates/cmux-tui-core/src/mux.rscmux-tui/crates/cmux-tui-core/src/server.rscmux-tui/crates/cmux-tui/src/app.rscmux-tui/crates/cmux-tui/src/cli.rscmux-tui/crates/cmux-tui/src/config.rscmux-tui/crates/cmux-tui/src/localization.rscmux-tui/crates/cmux-tui/src/main.rscmux-tui/crates/cmux-tui/src/session/mod.rscmux-tui/crates/cmux-tui/src/session/tree.rscmux-tui/crates/cmux-tui/src/ui/graphics_writer.rscmux-tui/crates/cmux-tui/src/ui/mod.rscmux-tui/crates/cmux-tui/src/ui/pane.rscmux-tui/crates/cmux-tui/src/ui/terminal_grid.rscmux-tui/crates/cmux-tui/tests/cli.rscmux-tui/crates/cmux-tui/tests/terminal_host_recovery.rscmux-tui/docs/concepts.mdcmux-tui/docs/configuration.mdcmux-tui/docs/keyboard.mdcmux-tui/docs/mouse.mdcmux-tui/docs/protocol.mdcmux-tui/spec/README.mdcmux-tui/spec/bindings.mdcmux-tui/spec/cli.mdcmux-tui/spec/commands.mdcmux-tui/spec/transports.md
…tal-scroll # Conflicts: # cmux-tui/README.md # cmux-tui/crates/cmux-tui-core/src/server.rs # cmux-tui/crates/cmux-tui/src/app.rs # cmux-tui/crates/cmux-tui/src/config.rs # cmux-tui/crates/cmux-tui/src/main.rs # cmux-tui/crates/cmux-tui/src/ui/graphics_writer.rs # cmux-tui/crates/cmux-tui/src/ui/mod.rs # cmux-tui/crates/cmux-tui/src/ui/terminal_grid.rs # cmux-tui/crates/cmux-tui/tests/cli.rs # cmux-tui/docs/configuration.md # cmux-tui/docs/keyboard.md # cmux-tui/docs/protocol.md # cmux-tui/spec/README.md # cmux-tui/spec/commands.md # cmux-tui/spec/transports.md
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
cmux-tui/crates/cmux-tui/src/config.rs (1)
1474-1482: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick winIndex bindings once before resolving the catalog.
resolved_shortcuts()scansself.bindingsonce per catalog action: O(65 × B), where B is config-controlled binding count. BuildHashMap<Action, Vec<String>>in one pass, then emit entries in catalog order.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui/src/config.rs` around lines 1474 - 1482, Update resolved_shortcuts to build a HashMap<Action, Vec<String>> from self.bindings in a single pass, then resolve catalog entries from that index in action_definitions() order. Preserve filtering of actions without shortcuts and the existing return type/order.Source: Coding guidelines
cmux-tui/crates/cmux-tui/src/localization.rs (1)
49-58: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick winDo not echo raw CLI input or provider flags in errors.
These helpers interpolate arbitrary arguments directly into terminal-facing messages, including
--cloud-port. Use product-level diagnostics with a safe recovery action instead; retain exact values only in sanitized logs.As per coding guidelines, user-facing errors must not expose provider-specific flags or raw payloads and must provide concrete next actions.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui/src/localization.rs` around lines 49 - 58, Update argument_needs_value_message, invalid_cloud_port_message, and unknown_argument_message so terminal-facing errors use product-level diagnostics and concrete safe recovery actions rather than interpolating raw CLI arguments, values, or provider flags. Remove direct placeholder substitution from these helpers; preserve exact inputs only through appropriately sanitized logging paths.Source: Coding guidelines
♻️ Duplicate comments (4)
cmux-tui/crates/cmux-tui-core/src/mux.rs (1)
5375-5423: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate auto-layout rebuild logic (unaddressed from prior review).
The layout-columns branch (5384-5404) and the non-column branch (5406-5422) differ only in whether the owner is a
LayoutColumnor theScreen; the prune/append/rebuild/store sequence is otherwise identical and can drift.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui-core/src/mux.rs` around lines 5375 - 5423, Extract the shared pane auto-layout prune, append, rebuild, and store sequence from the layout-columns and non-column branches into a reusable helper, parameterized by the owning layout container and its pane IDs. Update both branches around layout_column_for_pane_mut and screen to call that helper, preserving the existing column projection synchronization only for the column path.cmux-tui/crates/cmux-tui/src/cli.rs (1)
232-236: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winStill says "two-thirds-width" even though
--widthoverrides it.This was already flagged on a prior commit and remains unfixed: the verb accepts
--width, so the help text should say the two-thirds width is only the default.🐛 Proposed fix
- help: "Create a two-thirds-width viewport pane to the right.", + help: "Create a viewport pane to the right (default width: two-thirds).",🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui/src/cli.rs` around lines 232 - 236, Update the help text for the new-pane-right command in the command definition containing build_new_pane_right to clarify that two-thirds width is the default and can be overridden by --width; leave the command behavior unchanged.cmux-tui/crates/cmux-tui/src/ui/scrollbar.rs (1)
191-209: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winThumb click/drag mapping still doesn't match rendered thumb geometry.
Unaddressed from a prior review:
horizontal_offset_atmapspositionlinearly over the full track (track_width - 1), buthorizontal_thumb_geometryplaces the thumb within the travel range (track_width - thumb_width). The two spaces diverge wheneverthumb_width > 1, so clicking on the rendered thumb (or draggingDrag::HorizontalScrollbar) will not track the cursor and will saturate before reaching the track end.🐛 Proposed fix (from prior review)
pub(crate) fn horizontal_offset_at( content_width: u16, viewport_width: u16, track_width: u16, position: u16, ) -> Option<u16> { if content_width == 0 || viewport_width == 0 || track_width == 0 { return None; } let maximum = content_width.saturating_sub(viewport_width); - if maximum == 0 || track_width == 1 { + let (_, thumb_width) = + horizontal_thumb_geometry(content_width, viewport_width, 0, track_width); + let travel = track_width.saturating_sub(thumb_width); + if maximum == 0 || travel == 0 { return Some(0); } - let position = position.min(track_width - 1) as u32; - let offset = (position * u32::from(maximum) + u32::from(track_width - 1) / 2) - / u32::from(track_width - 1); + let position = u32::from(position.min(track_width - 1)) + .saturating_sub(u32::from(thumb_width) / 2) + .min(u32::from(travel)); + let offset = + (position * u32::from(maximum) + u32::from(travel) / 2) / u32::from(travel); Some(offset as u16) }The existing test
horizontal_track_positions_map_to_offsetswill need updated expected values, and a round-trip assertion againsthorizontal_thumb_geometry's output would lock the invariant in.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui/src/ui/scrollbar.rs` around lines 191 - 209, Update horizontal_offset_at to map positions across the thumb’s travel range, using the same thumb width and track geometry produced by horizontal_thumb_geometry rather than the full track width. Keep clamping and zero-content behavior intact, update horizontal_track_positions_map_to_offsets expected values, and add a round-trip assertion verifying geometry-derived thumb positions map back consistently.cmux-tui/crates/cmux-tui/src/ui/pane.rs (1)
377-381: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winTab-bar frame copy can still panic if the pane rect overruns the frame edge.
Unaddressed from a prior review:
visible_widthis clamped against the logical bar's remaining width (full_width - source_x) but never against the frame's remaining width (frame_buf.area.width - bar.x), and there's nobar.y >= frame_buf.area.heightguard at this copy site. Unlike theset_stringn/Widget paths this replaced,frame_buf[(x, y)]does not clip — it panics on out-of-bounds coordinates. The early-return guard at lines 218-227 only checks thatbar.x/bar.ythemselves are in range, notbar.x + bar.width.🛡️ Proposed fix (from prior review)
- let visible_width = bar.width.min(full_width.saturating_sub(source_x)); let frame_buf = frame.buffer_mut(); + let visible_width = bar + .width + .min(full_width.saturating_sub(source_x)) + .min(frame_buf.area.width.saturating_sub(bar.x)); + if bar.y >= frame_buf.area.height { + return; + } for dx in 0..visible_width { frame_buf[(bar.x + dx, bar.y)] = logical[(source_x + dx, 0)].clone(); }This is worth re-raising now specifically: the new fractional-width viewport columns and live resizing make an off-by-one pane rect more plausible than before.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui/src/ui/pane.rs` around lines 377 - 381, Update the tab-bar frame copy around visible_width and the frame_buf indexing to guard bar.y against frame_buf.area.height and clamp the copy width to the frame’s remaining horizontal space (frame_buf.area.width.saturating_sub(bar.x)) as well as the logical bar width. Preserve the existing logical source_x bounds while ensuring every (bar.x + dx, bar.y) index is in range.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmux-tui/crates/cmux-tui/src/app.rs`:
- Around line 6259-6273: Prune stale entries from viewport_states whenever the
live screen tree is reconciled, using the existing sync_layout or replace_tree
flow. Retain ViewportMotion values only for screens currently present in the
tree, removing entries for closed screens so viewport_animation_active and
tick_viewport_animation scan a bounded map without adding repeated per-event
full-tree scans.
In `@cmux-tui/docs/configuration.md`:
- Line 200: Update the documentation sentence describing the insertion position
to use the hyphenated phrase “two-thirds of the current viewport width.”
In `@cmux-tui/spec/cli.md`:
- Around line 113-114: Escape the pipe separator in the direction alternatives
for the split and set-ratio command rows so each remains a five-cell Markdown
table row; preserve the existing right/down option text.
---
Outside diff comments:
In `@cmux-tui/crates/cmux-tui/src/config.rs`:
- Around line 1474-1482: Update resolved_shortcuts to build a HashMap<Action,
Vec<String>> from self.bindings in a single pass, then resolve catalog entries
from that index in action_definitions() order. Preserve filtering of actions
without shortcuts and the existing return type/order.
In `@cmux-tui/crates/cmux-tui/src/localization.rs`:
- Around line 49-58: Update argument_needs_value_message,
invalid_cloud_port_message, and unknown_argument_message so terminal-facing
errors use product-level diagnostics and concrete safe recovery actions rather
than interpolating raw CLI arguments, values, or provider flags. Remove direct
placeholder substitution from these helpers; preserve exact inputs only through
appropriately sanitized logging paths.
---
Duplicate comments:
In `@cmux-tui/crates/cmux-tui-core/src/mux.rs`:
- Around line 5375-5423: Extract the shared pane auto-layout prune, append,
rebuild, and store sequence from the layout-columns and non-column branches into
a reusable helper, parameterized by the owning layout container and its pane
IDs. Update both branches around layout_column_for_pane_mut and screen to call
that helper, preserving the existing column projection synchronization only for
the column path.
In `@cmux-tui/crates/cmux-tui/src/cli.rs`:
- Around line 232-236: Update the help text for the new-pane-right command in
the command definition containing build_new_pane_right to clarify that
two-thirds width is the default and can be overridden by --width; leave the
command behavior unchanged.
In `@cmux-tui/crates/cmux-tui/src/ui/pane.rs`:
- Around line 377-381: Update the tab-bar frame copy around visible_width and
the frame_buf indexing to guard bar.y against frame_buf.area.height and clamp
the copy width to the frame’s remaining horizontal space
(frame_buf.area.width.saturating_sub(bar.x)) as well as the logical bar width.
Preserve the existing logical source_x bounds while ensuring every (bar.x + dx,
bar.y) index is in range.
In `@cmux-tui/crates/cmux-tui/src/ui/scrollbar.rs`:
- Around line 191-209: Update horizontal_offset_at to map positions across the
thumb’s travel range, using the same thumb width and track geometry produced by
horizontal_thumb_geometry rather than the full track width. Keep clamping and
zero-content behavior intact, update horizontal_track_positions_map_to_offsets
expected values, and add a round-trip assertion verifying geometry-derived thumb
positions map back consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 6d0aa175-cb1a-4371-a2ac-108360e32618
📒 Files selected for processing (25)
cmux-tui/README.mdcmux-tui/crates/cmux-tui-core/src/mux.rscmux-tui/crates/cmux-tui-core/src/server.rscmux-tui/crates/cmux-tui/src/app.rscmux-tui/crates/cmux-tui/src/cli.rscmux-tui/crates/cmux-tui/src/config.rscmux-tui/crates/cmux-tui/src/localization.rscmux-tui/crates/cmux-tui/src/main.rscmux-tui/crates/cmux-tui/src/session/mod.rscmux-tui/crates/cmux-tui/src/session/tree.rscmux-tui/crates/cmux-tui/src/ui/graphics_writer.rscmux-tui/crates/cmux-tui/src/ui/mod.rscmux-tui/crates/cmux-tui/src/ui/pane.rscmux-tui/crates/cmux-tui/src/ui/scrollbar.rscmux-tui/crates/cmux-tui/src/ui/terminal_grid.rscmux-tui/crates/cmux-tui/tests/cli.rscmux-tui/docs/configuration.mdcmux-tui/docs/keyboard.mdcmux-tui/docs/mouse.mdcmux-tui/docs/protocol.mdcmux-tui/spec/README.mdcmux-tui/spec/bindings.mdcmux-tui/spec/cli.mdcmux-tui/spec/commands.mdcmux-tui/spec/transports.md
…tal-scroll # Conflicts: # cmux-tui/crates/cmux-tui/src/app.rs
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cmux-tui/crates/cmux-tui/src/localization.rs (1)
759-773: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover every new provider-action mapping in both locales.
This test checks only one action label and one field mapping through
catalog(), so it can miss regressions in the other mappings or Japanese catalog. Assert all action IDs and port-field mappings against bothENGLISHandJAPANESE, preferably with a small table-driven test.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmux-tui/crates/cmux-tui/src/localization.rs` around lines 759 - 773, Expand workspace_port_provider_actions_use_localized_labels into a table-driven test covering every provider-action label and port-field mapping, including the expected values from both ENGLISH and JAPANESE catalogs. Invoke the mapping helpers on each locale directly rather than only through catalog(), while preserving the assertion that an unknown action returns None.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@cmux-tui/crates/cmux-tui/src/localization.rs`:
- Around line 759-773: Expand
workspace_port_provider_actions_use_localized_labels into a table-driven test
covering every provider-action label and port-field mapping, including the
expected values from both ENGLISH and JAPANESE catalogs. Invoke the mapping
helpers on each locale directly rather than only through catalog(), while
preserving the assertion that an unknown action returns None.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: cf7087c2-a546-4a94-bd9c-ce4a1bbf2ae4
📒 Files selected for processing (2)
cmux-tui/crates/cmux-tui/src/app.rscmux-tui/crates/cmux-tui/src/localization.rs
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e1196f5e75
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
Alt-nbehavior unchanged until a horizontal column is created.Ctrl-b ginsert a stable terminal column immediately after the focused column at two thirds of the viewport width.Alt-nonly inside the focused horizontal column.Alt-=andAlt--, or drag a visible column edge. Keep splits inside each column independently resizable.{"viewport":{"animation":false}}for immediate movement.Ctrl-b U. Resize samples coalesce, non-destructive actions restore immediately, and pane-creation undo requires exactCONFIRM.undo-layoutbehindlayout-undo-v1and keepset-viewport-pane-widthbehindviewport-column-resize-v1.Verification
cargo +1.97.1 fmt --all -- --checkZIG=/opt/homebrew/Cellar/zig/0.15.2_1/bin/zig cargo +1.97.1 clippy --workspace --all-targets -- -D warningsZIG=/opt/homebrew/Cellar/zig/0.15.2_1/bin/zig cargo +1.97.1 test --workspace -- --test-threads=1ZIG=/opt/homebrew/Cellar/zig/0.15.2_1/bin/zig cargo +1.97.1 build -p cmux-tuiniri8856: unchanged startup,Ctrl-b g, animated reveal, per-columnAlt-n, keyboard resize, pointer drag, immediate resize undo, confirmed pane-creation undo, ordinary-layout collapse, clean detach, and session cleanup.ping.Summary by CodeRabbit
viewport.animation) and horizontal-column viewport-width resizing, plus structural layout undo via Ctrl-b U with confirmation when closing panes.new-pane-right,set-viewport-pane-width, andundo-layout(with capability gating).