fix(startup): 打开一个 md,屏幕上就该是那一篇——启动时不再有两段代码抢焦点 - #258
Open
oratis wants to merge 1 commit into
Open
Conversation
双击一个 .md,Markup 起来了、标签页也在,屏幕上却还是上次那篇。 根因是 App.tsx 里两段互不相识的启动 effect 在抢 activeTabId: A 恢复会话 readSession() → 并发读 N 个文件 → 无条件 setActiveTab(sess.active) B OS 打开 takePendingFiles() → 读 1 个文件 → openLoadedFile()(顺带设焦点) 谁后落地谁赢。B 是「取 + 读」两跳 IPC,A 是一跳并发读——文件都小的时候 B 后落地,看起来正常;只要会话里有一篇大文件(这仓库一本书动辄几百 KB), A 就慢到最后才落地,那句无条件的 setActiveTab 把焦点拽回上一次的文档。 所以它对轻用户偶发,对天天开着一本书的人「总是」发生。 useStartupTabs 把这两段合成一条有序流程:先注册监听(启动期间来的 live open 不丢),再打开 OS 交给我们的文件并带焦点(用户在等这一篇),最后在 后台恢复会话(openLoadedFile 的新 activate: false),且只有在没人认领焦点 时才去 setActiveTab(sess.active)。「没人认领」在开标签页之前取快照判定: activeTabId 还是启动时的 welcome 草稿才算。 同源的三个问题一并修掉: - setActiveTab 不校验 id。会话里记的文件被删/改名后 activeTabId 指向一个 不存在的标签页,getActiveTab() 返回 null,编辑器直接白屏。现在忽略。 - RunEvent::Opened 既 emit 又缓冲。应用已在跑时那份缓冲没人取,直到下一个 窗口(⌘N)挂载才被 take_pending_files 取走——新窗口莫名打开十分钟前双击 过的文件。新增 FrontendReady:前端就绪后只 emit,不再缓冲。顺带 unminimize + show + set_focus,最小化的窗口也会被端到用户面前。 - 标签条 overflow-x-auto 但从不滚到激活项。标签一多,新开的那页在可视区外。 把修好的代码临时改回旧逻辑,新测试如实报出用户的原话: expected '/v/old.md' to be '/v/new.md'。 设计与两处取舍的辩论见 docs/design/11-open-file-focus.md。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
双击一个
.md,Markup 起来了、标签页也在,屏幕上却还是上次那篇。根因:两个 effect 在抢
activeTabIdApp.tsx里有两段互不相识的启动 effect:readSession()→ 并发读 N 个文件 → 无条件setActiveTab(sess.active)takePendingFiles()→ 读 1 个文件 →openLoadedFile()(顺带设焦点)谁后落地谁赢。B 是「取 + 读」两跳 IPC,A 是一跳并发读——文件都小的时候 B 后落地,看起来一切正常;只要会话里有一篇大文件(这仓库里一本书动辄几百 KB),A 就慢到最后才落地,那句无条件的
setActiveTab把焦点拽回上一次的文档。所以它对轻用户偶发,对天天开着一本书的人「总是」发生。方案:把「谁该在屏幕上」变成一条有序流程
新的
useStartupTabs接管这两段 effect:open-files监听——启动期间来的 live open 不会漏;openLoadedFile(loaded, { activate: false })),并且只有在没人认领焦点时才setActiveTab(sess.active)。「没人认领」在开标签页之前取快照判定:
activeTabId还是启动时那个 welcome 草稿才算;已经是别的东西(第 2 步开的文件、侧边栏点开的、拖进来的、⌘N 新建的)→ 恢复流程闭嘴。同源的三个问题一并修掉
setActiveTab不校验 id —— 会话里记的文件被删/改名后,activeTabId指向一个不存在的标签页,getActiveTab()返回 null,编辑器直接白屏。现在忽略这种 id。RunEvent::Opened既 emit 又缓冲 —— 应用已在跑时那份缓冲没人取,直到下一个窗口(⌘N)挂载才被take_pending_files取走,新窗口莫名打开十分钟前双击过的文件。新增FrontendReady:前端就绪后只 emit,不再缓冲。顺带unminimize + show + set_focus——「切换到最新打开的」也包括把窗口本身端到用户面前。overflow-x-auto但没有 scroll-into-view,标签一多,新开的那页在可视区外。怎么知道它真的修好了
把修好的代码临时改回旧逻辑跑新测试,失败信息就是用户的原话:
改回修复版后 3 条全绿。
验证
pnpm lintpnpm tsc --noEmitpnpm testpnpm test:coveragecargo check+cargo test取舍与不在本轮
两处取舍(恢复会话该不该完全不设焦点;被双击的文件排标签条左边还是右边)的正反方辩论,以及三条「不在本轮」(重开已开文件不刷新内容、
.canvas/.html不能从 Finder 打开、会话恢复失败无提示),见docs/design/11-open-file-focus.md。一处已知的行为变化:只有「冷启动 + 双击文件」这一种情况下标签顺序会变(被双击的那篇在最左,恢复的标签排它右边)——换来的是不必等整个会话读完才看到自己点的文件。普通启动的顺序不变。
🤖 Generated with Claude Code