fix(terminal): 锁定用户滚动位置防止 AI 输出时内容跳动#418
Conversation
当用户向上滚动查看历史内容时,AI 持续输出的 TUI 控制序列 (如清屏 \x1b[2J、清滚动缓冲区 \x1b[3J)会改变 viewport 位置, 导致正在阅读的文字跳动或重叠。 修复方案:在 terminal.write() 前后锁定用户距离底部的滚动偏移量, 写入完成后用 scrollLines() 恢复 viewport 位置。
|
Claude finished @lwt-sadais's task in 3m 33s —— View job 🔍 代码审查报告
📊 审查概览 · 一目了然
🏆 代码质量评分📋 问题分布🎯 关键发现
💡 总体评价本次 PR 精准解决了 TUI 控制序列导致的滚动跳动问题,思路清晰——在 🎯 问题详细分析 · 📊 点击展开查看📊 **👆 点击此处展开详细统计和图表分析**📈 问题趋势分析
🐛 问题清单与修复指南 · 📋 点击展开查看📋 **👆 点击此处展开详细问题列表 (共 3 个问题) · 一键复制追踪 📌**
|
| 🎯 优先级 | 🚨 严重 | ⚡ 轻微 | 📈 总计 | |
|---|---|---|---|---|
| 🔴 P0 | 0 个 | - | - | 0 个 |
| 🟡 P1 | - | 1 个 | - | 1 个 |
| 🔵 P2 | - | - | 2 个 | 2 个 |
| 📊 合计 | 0 | 1 | 2 | 3 个 |
🎯 合并决策建议
📋 合并评估结果
| 📊 评估维度 | ⭐ 得分 | 🎯 状态 | 💭 说明 |
|---|---|---|---|
| 🔐 安全性 | 10/10 | ✅ 通过 | 无安全风险,仅涉及 viewport 滚动 |
| 📊 代码质量 | 7/10 | 异步时序依赖内部实现,建议用回调加固 | |
| ⚡ 性能影响 | 10/10 | ✅ 无影响 | 仅增加轻量的偏移量计算,无额外开销 |
| 🛠️ 功能完整性 | 8/10 | ✅ 完整 | 核心场景覆盖良好,边界条件可优化 |
| 🧪 测试覆盖 | 6/10 | TypeScript 编译通过,依赖手动测试验证 |
📈 综合评分: 41/50 分 · 等级: 良好
🚦 最终建议
⚠️ 条件合并
📝 详细理由:
- 🟢 修复思路正确,精准定位了 TUI 控制序列导致滚动跳变的根因
- 🟢 变更范围小且集中,风险可控
- 🟢 代码注释清晰规范
- 🟡
terminal.write()的异步特性可能导致恢复逻辑在部分场景下失效- 🟡 建议在合并前修复
#1(使用回调形式),确保修复的可靠性
🎯 具体行动建议:
-
立即可执行的改进:
- 将 scroll 恢复逻辑移入
terminal.write()的回调函数中(#1) - 在回调中增加 buffer type 检查(
#2)
- 将 scroll 恢复逻辑移入
-
后续版本改进:
- 观察实际使用中是否存在闪烁,必要时引入 rAF 优化(
#3) - 考虑为 exit handler 中的
terminal.write()也加上 scroll lock(一致性)
- 观察实际使用中是否存在闪烁,必要时引入 rAF 优化(
- 收集上下文信息,分析变更内容
- 深入代码审查
- 生成审查报告
Summary
terminal.write()前后锁定用户距离底部的滚动偏移量,写入完成后用scrollLines()恢复 viewport 位置\x1b[2J、\x1b[3J等清屏操作)无视isUserScrolling状态导致的渲染错乱Root Cause
Claude Code 等 agent CLI 使用 TUI 框架,会周期性地发送清屏/刷新序列来重绘界面。xterm 的
isUserScrolling保护仅阻止普通换行时的自动滚动,但eraseInDisplay(清屏)等控制序列会直接修改 viewport 内容,导致用户正在阅读的内容位置跳变。Changes
src/renderer/hooks/useXterm.ts— 在 PTY 数据写入时检测用户是否已向上滚动,如果是则记录offsetFromBottom并在写入后恢复Test plan