Conversation
圈選潤色的「確認並替換」偶爾沒反應,根因鏈有四個,分別處理: 1. 预览窗 show 抢焦点:show_selection_polish_preview 走 window.show() + set_focus()(tao 层 makeKeyAndOrderFront + NSApp.activate),把 OpenLess 推成 frontmost;原 app 丢前台后编辑器的选区被清,之后 confirm 的 reactivate/validate 就「有时」失败。预览窗改成与胶囊/QA 同手法的 Nonactivating NSPanel(to_panel + styleMask 先读再 OR NonactivatingPanel 位——set_style_mask 是全量替换;level 3 + FullScreenAuxiliary/CanJoinAllSpaces 叠全屏 app),show 走主线程 orderFrontRegardless,不 makeKey、不激活 app。 2. 失败即杀 session:confirm 任何 Err 都 fail_if_active → Failed + 隐藏预览, 用户刚编辑的内容直接丢,只剩「点确认没反应」。分流:session 失效 (Cancelled/InvalidState/InvalidArgument/Busy)才结算失败并隐藏; 瞬时平台错误(焦点恢复/目标复核抖动)回退 Preview 保持可重试。 fail_if_active 加相位保护:只结算 Capturing/Preview/Applying,已 Completed 的不再被误标 Failed(complete 与 fail 之间的窄窗口)。 3. reactivate 固定 120ms:部分 app(Electron、自绘窗口)恢复 key window 需要更久,固定 sleep 一次就核 pid 会偶发误判「恢复失败」。改成 80ms x 4 轮询,每轮补一次 activate(幂等),pid 稳定立刻返回。 4. 前端 busy 卡死:预览窗复用(hide 不卸载组件),上一轮 confirm/cancel 后 busy 停留 true,下一轮两个按钮全 disabled。「shown」事件到达时 复位 busy/error。 验证:cargo check/test openless-core(含契约测试 transient_platform_failure_keeps_the_preview_retryable)全绿; src-tauri 本机因缺 Metal 工具链(qwen3-asr-rs 需要完整 Xcode)无法整树 check,新窗口代码已用同版本依赖(tauri 2.11.5 / tauri-nspanel v2 / objc2 0.5.2)的独立 crate 编译验证通过;前端 tsc + 71 个前端测试全绿。 macOS 实机行为(预览不抢焦点、confirm 重试)需要 CI(submodules: recursive) 或本机装完整 Xcode 后验证。
Collaborator
|
抱歉,我们写得很清楚:目前正在进行 2.0 的优化,所以暂不接受任何 PR。如果你希望 PR 能继续推进并成功完成,可能需要等我们完全迁移到 2.0 的新后端、新前端之后,再针对这个问题进行解决。 |
Collaborator
我先合你的,再合ta的,就这么简单 |
- First-click guard for the non-activating selection-polish preview
NSPanel: a local left-mouse-down monitor makes the panel key before
the first click lands, so the confirm button responds on the first
press instead of swallowing it.
- Targets the preview via windowNumber + fixed window title
(never a raw panel pointer), retargeted on every preview show so
registration retries survive an early failure and stale window
numbers cannot redirect the make-key to another window.
- Every AppKit call in the monitor callback is double-wrapped
(catch_unwind + objc2::exception::catch); the closure moves all
captured state (fixes a dangling stack reference that crashed
the main runloop under Tao).
- Apply path: resign the preview panel key synchronously before
reactivating the original target, so the simulated Cmd+C used by
selection revalidation hits the original app's focused window
instead of our own preview panel (root cause of false
SelectionChanged rejections / empty-clipboard misses).
Main-thread fast path, dispatch only from worker threads; no
timeout (a timed-out AppKit call could still fire late).
- Re-validate the captured frontmost app (pid + name) immediately
before the insert keystroke; the 200 ms simulate-copy retry inside
validation could otherwise let focus move to a window exposing the
same selected text and paste into the wrong target.
- Scaffolding echo stripping now requires the complete canonical
prompt template (Simplified + OpenCC Traditional variants, derived
from prompts.rs so it cannot drift) to match before any content is
removed; any extra prose or legitimate XML output is returned
unchanged (9 tests, including legitimate-XML-not-touched).
leonoxo
marked this pull request as ready for review
September 13, 2026 00:05
The window title (and the first-click guard identity constant that must match it) was Simplified while the app UI defaults to zh-TW. Title and guard constant are changed together to keep identity validation intact.
Author
|
Superseded by #1073 (rebased to UI 2.0 base, Seg-1 only). Seg-2 UE chain remains FROZEN. |
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.
問題
選區潤色(Selection Polish)預覽窗的「確認替換」按鈕有兩類偶發失敗:
NonactivatingNSPanel,點「確認替換」的第一下只讓面板取得 key,不會觸發按鈕;要點第二下才生效。根因(build22/23 實機 log 坐實)
acceptFirstMouse,正解是點擊派發前把面板扶成 key。focused_pid=<self:preview-window>而front=Hermes已過——reactivate()只查 NSWorkspace 前台 pid,不對預覽窗resignKey,Cmd+C 的 HID 事件打給「握鍵盤焦點的視窗」。move,以引用捕捉區域panel→ 函數返回後 dangling stack reference → ObjC foreign exception 越 FFI → Tao runloop abort(SIGABRT)。修法(本 PR 13 檔)
1. First-click guard(
src-tauri/src/lib.rs,僅 selection-polish 預覽窗)makeKeyWindow再原樣放行事件(additive、不合成/重播點擊)。catch_unwind(Rust panic)+objc2::exception::catch(ObjC exception);closure 以move捕捉全部狀態(修崩潰)。2. Apply 前同步 resignKey(
core_adapters.rs+lib.rs)resignKeyWindow(logapply: preview resigned key before reactivate was_key=true),再reactivate()原 app、校驗、貼上。3. 貼上前最後防線(
selection.rs+core_adapters.rs)validate_selection_insertion_target的模擬 Cmd+C 兜底含 200ms 重試,期間焦點可能跳走;而「另一個視窗恰好暴露相同選區文本」時文本比對會放行。因此在insert()前一刻重讀前台 app 的 pid + name,與捕獲時不符即拒絕(selectionPolishTargetChanged)。純增量,不改既有校驗。4. 選區潤色預覽窗標題改用繁體(
src-tauri/src/lib.rs,commit4f1772ce)選區潤色預覽窗標題原先是簡體「OpenLess 选区润色预览」,與預設 zh-TW UI 不一致。改為繁體「OpenLess 選區潤色預覽」,並同步更新 first-click guard 的視窗標題身份常數(guard 靠 windowNumber + 標題雙重驗證,兩者必須一致)。
5. 腳手架回顯剝離保守化(
crates/openless-core/src/streaming_insert.rs)prompts.rs的user_prompt/selection_user_prompt衍生,含 OpenCC 繁體變體,不會與 prompt 漂移)整段吻合、且 close 後只允許已知結尾,才剝離;任何額外前後文字、多信封、合法 XML 一律原樣保留。9 項測試含「合法 XML 不被觸碰」。驗證
靜態
openless-core全套:763 passed / 1 ignored(含 9 項 scaffolding 契約、selection-envelope prompt 契約)tsc --noEmit通過src-tauri cargo check通過;git diff --check通過passed=true(前四輪 12 項問題全數修復:monitor 錯置/佔用 flag/stale pointer/主執行緒死鎖/timeout race/panic 邊界/session 跨取消 race/導語錯字與歧義裁切 等)實機(macOS,build22/23/25)
move,已修)first-click guard: panel made key before first mouse-down(第一擊生效)、resigned key was_key=true、post_copy: post_ok=true;0 SelectionChanged / 0 TargetChanged / 0 ClipboardEmpty / 0 崩潰已知限制(reviewer 4 項 non-blocking 建議,留待後續)
selection_target_still_front通過到實際貼上 key stroke 之間仍有極小 check-then-act 窗口(遠小於舊 200ms 窗口,且新增 pid 比對嚴於舊版)。resign_selection_polish_preview_key_for_apply的rx.recv()無 timeout:今日安全(isMainThread fast-path 避免自死鎖,apply 確認在 tokio worker 線程),但可加防禦性 timeout。assemble_polish_system_prompt(settings 頁診斷)硬編UserEnvelope::RawTranscript:現行無影響,若未來加 selection 型 style-pack 預覽需同步。