[Bug]: interactive TUI fullscreen: mouse-wheel scroll is a no-op while the transcript is following the tail
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 2/5
- 预计耗时
- 1-3 小时
- 新手友好度
- 72/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- typescript
调研方向
阅读 packages/tui/src/tui/engine/components/scroll-view.ts,并追踪 followingEnd 为 true 时的 scrollBy;然后检查 packages/tui/src/tui/engine/tui-alt-screen.ts 中 routeWheel 附近的滚轮路由。使用一段较长的转录内容在全屏模式下重现此问题,先在固定于末尾时操作,再在向上滚动后操作。完成标准是:向下滚动能让转录内容脱离固定状态,并且在流式传输期间仍能正常工作。
由索引模型根据 Issue 内容生成。
描述
Product or interface
CLI - interactive TUI
Version
0.6.5
Platform
Linux
OS version and architecture
Debian 12
Issue area
UI / UX
Desktop log upload ID (optional)
No response
Steps to reproduce
-
Run the interactive TUI in fullscreen mode:
mcode --tui-mode fullscreen
(or switch into fullscreen at runtime, if already running in regular mode). -
Run inside a terminal that reports mouse input — e.g. Termius, Windows
Terminal, iTerm2. Do NOT disable mouse reporting. -
Produce a transcript taller than the viewport. Either send a few messages,
or start a turn and let the assistant stream output until the transcript
overflows. -
Leave the viewport pinned to the bottom. This is the default state: the
transcript is created withfollow: 'end', so as long as you have NOT
scrolled up,followingEndis true. -
Scroll DOWN with the mouse wheel. Repeat several notches.
-
For contrast, scroll UP once (this works), then scroll DOWN again
(this also works). -
For contrast again, start a streaming turn and try scrolling down while
tokens are arriving.
Expected and actual behavior
EXPECTED
Scrolling down with the mouse wheel moves the transcript viewport toward the
tail, and scrolling up moves it back through the history — at the same
granularity the terminal is configured for, with acceleration.
ACTUAL
While the transcript is in the follow-tail state (the default), downward
mouse-wheel input produces no movement at all. No error, no partial repaint,
no visual feedback whatsoever — the wheel simply appears dead.
Upward wheel input works, and downward wheel input also works once the
viewport has been scrolled up at least once. So the failure is specific to
the follow-tail state, not to the wheel in general.
While output is streaming, the dead state reappears, because the viewport is
re-pinned to the tail on every layout pass.
WHY IT LOOKS INTERMITTENT
The wheel is only ignored when followingEnd happens to be true. Any upward
scroll clears it; any layout pass during streaming sets it again. So the same
gesture works or does nothing depending on invisible state the user cannot
observe.
ROOT-CAUSE HYPOTHESIS (from reading the source, not yet instrumented)
packages/tui/src/tui/engine/components/scroll-view.ts:150
scrollBy(lines: number): number {
...
const start = this.followingEnd ? maxScrollTop : this.currentScrollTop;
const next = Math.max(0, Math.min(maxScrollTop, start + requested));
const moved = next - start;
...
return requested - moved;
}
When followingEnd is true the scroll start position is forced to
maxScrollTop, so a downward wheel yields moved === 0, and the function
returns the full requested amount as "unconsumed".
packages/tui/src/tui/engine/tui-alt-screen.ts:731-743 (routeWheel) then
discards that remainder:
for (const scrollView of getScrollViewsAt(layout, x, y)) {
remaining = scrollView.scrollBy(remaining);
if (remaining === 0 || scrollView.overscroll === "contain") break;
}
The transcript viewport is created with follow: 'end' and
overscroll: 'contain':
packages/tui/src/tui/features/transcript/panel.ts:125-129
packages/tui/src/tui/shell/chat-layout.ts:152-158
followingEnd is only ever cleared by an upward scroll
(scroll-view.ts:155). Downward wheel input is never treated as a user
override of the follow-tail state — so it can never move the viewport.
In other words, the sticky/follow state is modelled as authoritative over
user input, rather than as a render default that user input overrides.
SECONDARY OBSERVATIONS (separate from the dead-scroll bug)
a) Wheel granularity is hardcoded to one line.
packages/tui/src/tui/engine/tui-alt-screen.ts:249
this.wheelScrollLines = Math.max(1, Math.floor(options.wheelScrollLines ?? 1));
`wheelScrollLines` is declared in `TuiAltScreenOptions` but no caller in
this repository ever passes it, and there is no CLI flag or environment
variable for it. xterm.js-derived terminals (Termius, Windows Terminal,
iTerm2) emit one wheel event per notch, so the wheel moves exactly one
line per notch with no acceleration. Even when the wheel does work, a
transcript of several hundred lines is effectively unscrollable by wheel.
b) There is no escape hatch to disable mouse reporting.
Once the fullscreen renderer enables mouse tracking, the terminal stops
doing its own scrollback and every wheel event is delivered to the TUI.
`TuiAltScreenOptions.mouse` exists
(packages/tui/src/tui/engine/tui-alt-screen.ts:173) but is not wired to
any CLI flag or environment variable. For comparison, Claude Code exposes
`CLAUDE_CODE_DISABLE_MOUSE` and additionally auto-disables fullscreen
under `tmux -CC` because "mouse wheel is dead" there.
SUGGESTED FIX DIRECTION (no patch attached)
-
Treat wheel input as a user override. Clear the follow-tail flag before
applying a wheel delta, instead of using it to choose the scroll start
position. This is the minimal change and removes the dead state entirely. -
Longer term, separate the two concepts the way ink's
ScrollBoxdoes:
keepscrollTopas the real position andstickyToEndas a render-time
default. Any explicit user scroll clearsstickyToEnd
(el.stickyScroll = false; el.scrollAnchor = undefined;) before moving. -
Wire
wheelScrollLinesto a setting, and add momentum/accumulation so
fast flicks produce intermediate frames instead of 1:1 line stepping. -
Expose an environment variable or flag to disable mouse reporting, and
consider auto-disabling it under multiplexers, so users can fall back to
native terminal scrollback.
Redacted error summary
None. No error is emitted; the input is consumed and the resulting scroll
delta is discarded internally.
Screenshots
A short screen recording is more useful than a still here, since the failure
is "nothing happens":
- Start in fullscreen TUI with a transcript taller than the viewport.
- Scroll DOWN without scrolling up first -> no movement.
- Scroll UP once, then scroll DOWN -> movement resumes.
Attach the recording to this field (not to the code-formatted field above).
Before submitting
- I have searched existing issues.
- I have included my version and removed sensitive information.
- 主要语言
- TypeScript
- 星标
- 2k
- 派生
- 254
- 平均合并
- 8 小时 12 分钟
- 30 天内合并 PR
- 149
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
MiniMax-AI/minimax-code 的其他 Issue
-
bug cli documentation needs-triage
难度 2/5 1-3 小时 新手友好度 84/100
MiniMax-AI/minimax-code#299 · 3 条评论 ·
维护者通常 1 天内回复
-
bug cli needs-triage
难度 2/5 1-3 小时 新手友好度 78/100
MiniMax-AI/minimax-code#128 · 2 条评论 ·
维护者通常 1 天内回复
-
bug desktop
难度 2/5 1-3 小时 新手友好度 82/100
MiniMax-AI/minimax-code#87 · 2 条评论 · 2 个 reaction ·
维护者通常 1 天内回复
-
bug desktop needs-triage
难度 2/5 1-3 小时 新手友好度 68/100
MiniMax-AI/minimax-code#80 ·
维护者通常 1 天内回复
-
bug desktop needs-triage
难度 2/5 1-3 小时 新手友好度 78/100
MiniMax-AI/minimax-code#66 ·
维护者通常 1 天内回复
查看 MiniMax-AI/minimax-code 的全部 Issue
相似的 Issue
-
难度 1/5 1 小时以内 新手友好度 83/100
维护者通常 1 天内回复
-
Feil lovtekst i bekreftelsen når leder melder unntak fra oppfølgingsplan可能已有人在做 @AudunSorheim 今天认领。 未关闭
难度 1/5 1 小时以内 新手友好度 92/100
navikt/syfo-oppfolgingsplan-frontend#1110 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
db-ux-design-system/core-web#8461 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复
-
Cannot run an integration on windows when power shell is selected as the default profile terminal未关闭Priority/Blocker Type/Bug
难度 2/5 1-3 小时 新手友好度 76/100
wso2/product-integrator#2767 ·
维护者通常 1 天内回复