Skip to content

fix(editor): 关闭内置远程编辑器改为隐藏复用,规避 macOS Touch Bar 崩溃 (#262) - #268

Merged
feigeCode merged 1 commit into
devfrom
fix/issue-262-editor-window-reuse
Sep 21, 2026
Merged

feigeCode merged 1 commit into
devfrom
fix/issue-262-editor-window-reuse

Conversation

@feigeCode

Copy link
Copy Markdown
Owner

背景

Closes #262(关联诊断见 issue 内维护者分析)。

Intel Touch Bar 机型(MacBookPro16,1,macOS 15.7.9)上,关闭内置远程文件编辑器弹窗必现整进程 SIGILL 退出(Illegal instruction: 4),无任何报错。用户上传的崩溃报告把致命点钉在 AppKit:

exception  : EXC_BAD_INSTRUCTION / SIGILL
0  CoreFoundation  __exceptionPreprocess
1  libobjc         objc_exception_throw
2  Foundation      -[NSObject _removeObserver:forProperty:]
3  Foundation      removeObserver:forKeyPath:
5  AppKit          -[_NSTouchBarFinderObservation invalidate]
6  AppKit          ___NSTouchBarFinderSetNeedsUpdateOnMain_block_invoke_2
8  AppKit          NSDisplayCycleFlush
9  QuartzCore      CA::Transaction::run_commit_handlers

即:NSWindow 被销毁后,AppKit 的 Touch Bar 查找器在下一个渲染周期注销其 KVO 观察时抛出未捕获 NSException-[NSApplication _crashOnException:]ud2 终止进程。与 Rust panic 无关(release 为 panic="abort",日志 editor_view_dropped 先于死亡 18ms,窗口本身是干净关掉的);Apple Silicon 无 Touch Bar 故本地不可复现。同签名崩溃在无关项目亦有报告(eero-lehtinen/oklch-color-picker#3),属 AppKit 侧老问题。

修复

macOS 上关闭编辑器弹窗不再销毁原生窗口,改为 orderOut: 隐藏 + 下次打开复用,从根上移除触发点:

  • prepare_window_close 统一收口全部窗口关闭路径(红按钮 / ⌘W / 保存后关闭 / 末标签关闭);隐藏成功即保留 GPUI 窗口与单例注册表,仅释放全部标签与文件内容
  • editor_window_visibility::hide_for_reuse 仅 macOS 实现(raw-window-handle 取 NSView → orderOut:),非 macOS 平台与隐藏失败场景回退原有 remove_window() 行为
  • 复用安全性:
    • client 下沉到每个 tab,标签按 (remote_path, Arc::ptr_eq) 匹配——顺带修复了旧实现中跨 SSH 会话复用窗口时走错连接的问题
    • PendingCloseAction::Tab 改用稳定 tab id(而非会因关闭而漂移的下标)
    • 未保存确认 prompt 引入代际计数,隐藏复用后旧 prompt 的应答不得作用于新会话
    • 隐藏时 next_tab_id 不回退,旧连接的迟到 I/O 结果(load/save 错误)不会落到复用窗口的新标签上

安全性依据:gpui-pre 的可见性回调经 executor.spawn 异步投递,GPUI 借用内调用 orderOut: 不会同步重入(与已上线的托盘主窗口隐藏同一手法,main/src/window_visibility.rs);隐藏后 occlusion state 变化会 stop_display_link(),隐藏期间无渲染开销。会话期内保留 1 个空壳 NSWindow(GPU 资源已在 Drop 时释放),代价可忽略。

验证

  • cargo test -p remote_file_editor70 passed / 0 failed(新增 5 个状态级用例:隐藏释放与状态复位、迟到 I/O 隔离、prompt 代际、跨连接标签匹配、prompt 取消保留;另 3 个源码契约测试钉住关闭路径收口与平台门控)
  • cargo clippy -p remote_file_editor --all-targets:本 crate 无新增警告;rustfmt --check 通过
  • 限制:原生 orderOut:/复用路径需 Touch Bar 真机回归,本机(Apple Silicon)无法复现原崩溃,已请 [Bug]: 关闭编辑文件弹窗会导致应用直接崩溃退出 #262 报障人协助验证测试包

备注

  • 并行的 feat/panic-crash-report(panic 落盘)不覆盖本类崩溃(非 Rust panic),两者互补
  • 若真机验证仍崩,备选方案是 gpui-pre fork 层不销毁 NSWindow(MacWindow Drop 的 close()+autorelease() 改为长期持有),届时另行评估

issue #262:Intel Touch Bar 机型(MacBookPro16,1)上关闭内置文件编辑器弹窗
必现 SIGILL。用户崩溃报告显示致命点在 AppKit:NSWindow 销毁后
-_NSTouchBarFinderObservation invalidate 在 NSDisplayCycleFlush 里注销 KVO
观察时抛出未捕获 NSException,-[NSApplication _crashOnException:] 以 ud2
终止进程。与 Rust panic 无关(release 为 panic=abort),Apple Silicon 无
Touch Bar 故不可复现。

修复:macOS 上关闭不再销毁原生窗口,改为 orderOut: 隐藏 + 复用:
- prepare_window_close 统一收口全部关闭路径(红按钮/⌘W/保存后关闭/
  末标签关闭),隐藏成功即保留 GPUI 窗口与注册表,下次打开复用
- editor_window_visibility::hide_for_reuse 仅 macOS 实现,其余平台/失败
  回退原 remove_window 行为
- client 下沉到每个 tab(修跨会话复用会走错连接的问题);同一窗口按
  (remote_path, Arc::ptr_eq) 匹配标签
- PendingCloseAction::Tab 改用稳定 tab id;prompt 引入代际计数,旧确认
  不得作用于复用后的新会话;隐藏时 next_tab_id 不回退,杜绝旧 I/O 落到
  新标签
- apply_load/save_error 返回是否命中标签,未命中的迟到错误不再弹通知

验证:cargo test -p remote_file_editor 70 passed(新增 5 个状态级复用/
代际/跨连接用例 + 3 个源码契约测试);原生隐藏/复用仍需 Touch Bar 真机
回归(报障人协助)。
@feigeCode
feigeCode merged commit ddd36f9 into dev Sep 21, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant