mecatui: converge bounded scrolling and selection controls
@jbeda is already working on this.
Since Sep 15, 2026.
- Dominant language
- Go
- Stars
- 152
- Forks
- 16
- Avg merge
- 14h 48m
- Merged PRs (30d)
- 536
Description
Goal
Introduce a package-private, reusable bounded scrolling and cursor-selection system for mecatui, then migrate the TUI incrementally while targeted fixes continue.
This is an umbrella issue. It does not authorize a single repository-wide rewrite or replacement of the specialized conversation viewport.
Why
Mecatui currently has several independent implementations of list windowing, rendered-line scrolling, cursor movement, overflow indicators, selection styling, and mouse routing. PR #1488 added the strongest multiline selectable-row implementation for the unified Agents overlay, but it remains Agents-specific and keyboard-only.
Current inconsistencies include:
- selectable rows use different markers and styles (
›,▶,>, button-active, spinner, accent); - wheel events scroll some surfaces, do nothing on others, and can reach the hidden conversation beneath legacy overlays;
- several lists render without a viewport bound;
- multiline logical items are sometimes selected as items and sometimes split into independently scrolled physical lines;
- browsing, cursor selection, keyboard focus, current/default state, hover, and text selection do not have a shared vocabulary.
Proposal sketch
Build two package-private layers under cmd/mecatui/ui rather than one monolithic widget.
1. Bounded window
- explicit width and height;
- physical-line accounting;
- bounded vertical offset, line/page movement, top/end, and wheel input;
- explicit wrap-or-clip width policy;
- overflow/range metadata;
- browsing without a cursor.
2. Selectable list over the bounded window
- optional cursor;
- logical items spanning one or more physical lines;
- keep the entire cursor item visible when possible;
- item movement plus physical-height paging;
- mouse hit regions spanning all physical lines of an item;
- click-to-cursor with activation remaining an explicit surface callback;
- filtering, actions, fetching, confirmation, and server pagination remain surface-owned.
Use distinct semantics and styles for text selection, list cursor, keyboard focus, current/active value, default value, hover, and activation. Width bounds are required; horizontal panning is not part of the initial contract without a concrete diff/table use case.
The main conversation viewport remains specialized because it owns streaming-tail following, logical text selection, reflow anchors, ANSI/grapheme handling, and drag autoscroll.
Incremental migration
Slice 1 — establish and prove the control
Create a Bounded acceptance plan and implementation PR that extracts the multiline physical-window behavior from #1488, defines the interaction/style contract, and proves it against representative consumers:
- unified Agents overlay — multiline cursor rows plus browsing-only detail panes;
/models— simple fixed-height cursor rows.
The Agents overlay proves both control modes without coupling the first slice to another surface's mixed domain behavior. Other browsing-only surfaces remain follow-ups.
Slice 2 — mechanical list adoption
After Slice 1 establishes the contract, classify each batch independently. Mechanical adoption can be Routine; behavioral changes remain Bounded.
Candidate batches:
- command palette +
@mentions; /sessionsroster +/worktrees;/schedule+ MCP lists +/connect.
Slice 3 — complex and legacy surfaces
Handle /user model, reflections, dream, help, skills, agent inventory, detail panes, and previews in focused follow-ups. Any decision about migrating legacy overlays onto the formal surface lifecycle should get its own Bounded contract rather than being hidden in a mechanical migration.
Interaction principles
- Wheel input belongs to the visible surface and never silently scrolls hidden content.
- A multiline row is one logical cursor and pointer target.
- Hover is visual only and does not move the keyboard cursor.
- Cursor movement and activation are distinct.
- Current/default status markers remain orthogonal to cursor and focus.
- Existing frame-scoped hit regions remain the pointer-dispatch mechanism.
- Existing remappable navigation actions remain authoritative where already supported.
Process
Track this issue with non-closing Relates to links from partial Plan / Interface and implementation PRs. Only the final PR that completes the umbrella should close it. Each independently shippable slice is classified separately under docs/development-process.md.
References
- #1488
- #1446
docs/acceptance/mecatui-unified-agents-overlay-fit.mdcmd/mecatui/ui/agents_overlay.gocmd/mecatui/ui/window.gocmd/mecatui/ui/surface.gocmd/mecatui/ui/hit_regions.go
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.