fix: 补全会话建立时的终端尺寸同步,修复内嵌终端画面错位 - #8
Open
LeaFluorine wants to merge 2 commits into
Open
Conversation
Author
|
本地验证结果(首次向本仓库提交,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 @ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
现象
开启「使用应用内终端」时,终端会出现光标跳到中间某一行、随后把下面的内容覆盖掉的画面错乱,
在服务启动阶段(依赖检查、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 的范围,如需要我可以另开一个。