Repository navigation
fix: 补全会话建立时的终端尺寸同步,修复内嵌终端画面错位 - #8
LeaFluorine wants to merge 2 commits into
Conversation
|
本地验证结果(首次向本仓库提交,CI 需要维护者批准后才会执行,先附上本地跑的结果): $ bun install --frozen-lockfile
424 packages installed [299.64s]
$ bun run typecheck
$ tsc --noEmit -p tsconfig.json
(无输出,退出码 0)
$ bun run build
$ tsc --noEmit -p tsconfig.json && electron-vite build
out/main/index.cjs 597.16 kB
out/preload/index.cjs 12.78 kB
out/renderer/assets/index-*.js 2,044.96 kB
✓ built in 3.94s(退出码 0)环境:Windows 11 Pro(build 26200)、bun 1.4.2、基点 main @ |
7a95cd7 to
acd80db
Compare
acd80db to
bc63798
Compare
|
已针对上游 0.6.1(2026-10-11 发布)重新验证:分支已 rebase 到 0.6.1,无冲突。 本地验证结果: $ bun install --frozen-lockfile
Checked 455 installs across 541 packages (no changes) [3.98s]
$ bun run typecheck
$ tsc --noEmit -p tsconfig.json
(无输出,退出码 0)
$ bun run build
out/main/index.cjs 619.02 kB
out/preload/index.cjs 13.27 kB
out/renderer/assets/index-*.js 1,958.51 kB
✓ built in 4.35s(退出码 0)环境:Windows 11 Pro(build 26200)、bun 1.4.3、基点 main @ 补充复现范围:该问题在 v0.5.0 / v0.5.1 / v0.6.0 / v0.6.1 上均可复现。0.6.1 里这两处相关代码与 0.5.x 逐字一致,说明后续版本都没触及这条路径。 |
|
补两条 review 可能用得上的信息。 一、为什么只写
|
现象
开启「使用应用内终端」时,终端会出现光标跳到中间某一行、随后把下面的内容覆盖掉的画面错乱,
在服务启动阶段(依赖检查、pip / uv 进度条)尤其明显。
把「使用应用内终端」关掉、让服务跑独立的 cmd 窗口后完全正常 —— 因为外部终端模式走
startExternalTerminal(),用child_process.spawn开真正的控制台窗口,完全不经过 node-pty。这个对照把范围锁定在 node-pty + xterm 这条链上。
根因
174a871038 fix: 稳定终端尺寸同步(2026-05-20)给terminal.onResize加了缓存比对后提前返回:这个改动本身是对的,但漏掉了一条关键路径:
onResize只在 xterm 自身尺寸发生变化时才触发,而 PTY 是主进程按固定尺寸创建的 —— 创建 PTY 并不会改变 xterm 的尺寸。于是:
SERVICE_TERMINAL_COLS = 260/SERVICE_TERMINAL_ROWS = 36(
src/main/services/service-manager.ts)创建 PTY;onResize不触发 →pty.resize从不发出;bridge.pty.onSnapshot的处理函数只记录快照并加载缓冲区,没有任何尺寸回传。结果 PTY 长期停留在 260×36:子进程按 260 列排版,而 xterm 按约 110 列渲染,一条 200 字符的行会被
折成 2 个视觉行。凡是按行数做相对光标移动的输出(tqdm / uv / rich 等的多行进度条,
ESC[nA上移 +
\r重绘)都会算错行 —— 子进程以为上移 3 行,视觉上是 7 行,于是覆盖了中间的内容。只有用户手动拉窗口 / 改字号(真的让 xterm 尺寸变了)时
onResize才触发、尺寸才被纠正。这也解释了为什么这个 bug 表现为「时好时坏、和窗口操作有关」。
修复
1. 会话建立时把渲染层真实尺寸推给 PTY(
TerminalPanel.tsx)sessionsRef.current.set(snapshot.id, snapshot); upsertUserTerminal(snapshot); void loadSessionBuffer(snapshot.id); + + // PTY 由主进程按固定尺寸创建(service-manager 的 SERVICE_TERMINAL_COLS/ROWS)。 + // 此时 xterm 通常已按面板尺寸 fit 完毕,尺寸不会再变化,terminal.onResize + // 也就不会触发,PTY 会长期停留在主进程的默认尺寸上:子进程按错误宽度排版, + // 依赖行数的相对光标移动(tqdm/rich 等进度条重绘)会算错行,画面被覆盖。 + // 快照是在 spawn 之后、子进程尚未输出时发出的,在这里同步一次真实尺寸最干净。 + const snapshotInstance = terminalsRef.current.get(snapshot.id); + if (snapshotInstance?.opened) { + const { cols, rows } = snapshotInstance.terminal; + if (cols > 0 && rows > 0 && (snapshot.cols !== cols || snapshot.rows !== rows)) { + void bridge.pty.resize({ sessionId: snapshot.id, cols, rows }).catch(() => undefined); + } + } + notifySessionsChanged(); }),快照是在
spawn()之后、子进程尚未产生任何输出时发出的(pty-session-manager.ts的emitSnapshot()),因此这次 resize 是干净的重排,不会触发 reflow 损坏。主进程
PtySession.resize()之后会回发快照,届时尺寸已一致、条件不成立,所以不会形成循环。
附带的收益:
SERVICE_TERMINAL_COLS的取值不再影响正确性,不需要改动它。2. 为 xterm 声明 ConPTY 后端(
TerminalPanel.tsx+ 导出platform.ts的detectPlatformSync)主进程是无条件
useConpty: true(src/main/pty/pty-session-manager.ts),但 xterm 没有被告知这一点,windowsPty默认为{},导致Buffer.resize在行数增长时走「消耗 scrollback 上移整屏」分支而不是 Windows 的「底部追加」,与 ConPTY 的语义不一致:
已按平台条件化设置,macOS / Linux 行为不变。
验证
bun run typecheck、bun run build通过影响面
(
PtyResizeRequest已有sessionId / cols / rows),不新增依赖,不改bun.lockSERVICE_TERMINAL_COLS / ROWSwindowsPty仅在 Windows 设置)后续(可选,未包含在本 PR)
xterm 的
_isReflowEnabled只有在同时提供buildNumber时才会按 ConPTY 版本决定是否允许自身 reflow(
>= 21376才开启)。若希望 Windows 10(build < 21376,旧 ConPTY 有 rewrap 问题)也走到「关闭 xterm reflow + 开启 wrapping heuristics」这个组合,需要把系统构建号透出到渲染层
(例如给
DesktopSnapshot加一个osRelease)。这超出本 PR 的范围,如需要我可以另开一个。对应问题记录:Fixes #10