cmux NEXT sidebar: multi-view prototype (navigate on release, drag without switching, on-screen rows lit)
Leo's sidebar item D (2026-10-21) asked to "do the Claude Code desktop multi-view better". This PR is a prototype behind the Debug Settings toggle sidebar.multiView (Sidebar section, "Navigate on release (multi-view prototype)"), off by default. With the toggle off, nothing changes.
With it on:
- A press doesn't navigate. Mouse-down on a workspace row changes nothing: no selection, no fill, no workspace switch. The release on the same row is the click that navigates. A press released over another row navigates nowhere.
- Hold-then-drag keeps your place. Dragging a row moves it in the list, and the shown workspace and the selection stay as they were, in every frame and after the drop. Today a drag first selects and shows the row it lifts. A sideways drag out of the sidebar still hands off to the window drag, which already drops a workspace into a pane edge with a drop indicator (
WorkspaceMerge). - Every workspace on screen is lit.
SidebarModel.onScreenlists the workspaces the window has on screen. Their rows draw the multi-selection's soft fill (Palette.secondarySelectionFill), and the focused row keeps the selection's fill. A change to the set repaints only the row fills (syncRowStates), without a reload.
The Chrome, Claude desktop and Codex comparison is in cmuxterm-hq#2746 (knowledge/inspiration/sidebars.md).
Not built yet:
- A window can show only one workspace's panes today, and no window view holds panes of several workspaces. So nothing sets
onScreenin the App yet; the model and the drawing are here and tested. - A drop on a pane edge still merges the dragged workspace's tabs into the shown one, instead of placing the workspace beside it.
- The view doesn't remember its workspaces yet (the implicit group).
These need the multi-workspace content view first; that is the next step.
SidebarModel's selection methods moved unchanged to SidebarModel+Selection.swift so the file shrinks instead of growing.
Changelog
none (Debug-only prototype, off by default)
Tests
SidebarMultiViewPressTests is the per-frame test. After each mouse event it lays the list out and draws a frame, then checks the selection, the shown workspace and the filled rows. The red commit has the toggle, the model field and the row state with no behavior.
- Command:
cmux-ci run --class light --script scripts/ci/package-test-lane.sh --arg=suite --arg=Packages/macOS/CmuxNext --arg=SidebarMultiViewPressTests --env CMUX_CI_XCODE_APP=/Applications/Xcode_26.6.app --ref <sha> - Red on c2b846862142 (step 9d244e3f3d9d57461a0596a1): 4 of 6 failed, 21 issues. Frame 0 (mouse-down) showed
active=ywhereactive=xwas expected; the drag switched to the lifted row; no on-screen fills were drawn. The two toggle-off tests passed. - Green on 371e4d249870 (step for key smv-press5-after): 6 of 6 passed.
SidebarPointerGestureTests(the existing click, drag and stale-drag behavior, toggle off) on the same head: 9 of 9 passed.
The base's CmuxNext test target doesn't compile right now (#23363 isReadOnly, #23386 PaletteMenuVocabularyTests). Both fleet runs had those two one-line fixes on top, on scratch refs (scratch/smv-before, scratch/smv-after). This branch itself carries neither.
No capture: nothing visible changes with the Debug toggle off, which is the default. With it on, the App doesn't fill the on-screen set yet, so the press and drag behavior is proven by the per-frame test above.
Observed / Not run
- Observed: the suites above on the fleet;
scripts/cmux-next/prepush-gate.py(no new violations); the god-file check against base (SidebarModel.swiftshrank from 615 to 564 lines). - Not run: a live app capture. The App doesn't set
onScreenyet, so a capture would only show the press and drag behavior. No full CmuxNext suite.
🤖 Generated with Claude Code
Agent session: cosmic-gray