Skip to content

feat(selection-polish): 选中润色移植到 macOS(前台应用+选区指纹校验、默认右 Option 热键) - #926

Merged
appergb merged 1 commit into
betafrom
feat/selection-polish-macos
Aug 5, 2026
Merged

feat(selection-polish): 选中润色移植到 macOS(前台应用+选区指纹校验、默认右 Option 热键)#926
appergb merged 1 commit into
betafrom
feat/selection-polish-macos

Conversation

@appergb

@appergb appergb commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

目标

把 Windows 已上线的「选中润色」(#851)移植到 macOS:选中任意文字 → 触发热键 → LLM 润色 → 安全替换原选区文本,与 Windows 行为一致。

改动

  • src-tauri/src/selection.rsSelectionInsertionTarget 增加 macOS 指纹(前台应用名 + pid):
    • capture_selection_insertion_target / selection_insertion_target_is_captured:macOS 分支,打开原 fail-closed
    • validate_selection_insertion_target:前台应用一致性 + 选区重读(AX 直读,失败退化为模拟 Cmd+C + 剪贴板快照恢复)文本比较 → 拒绝误粘贴
    • reactivate_selection_insertion_target:NSRunningApplication activateWithOptions 把焦点交还原应用(预览确认模式)
  • src-tauri/src/types.rs:macOS 默认热键 = RightAlt(右 Option;CGEventTap keycode 61 可区分左右,不占 Cmd/Ctrl 常用组合)
  • capabilities/default.jsonselection-polish-preview 窗口加入默认能力列表(修复预览窗 selection-polish-preview:shown 事件 listen 被 ACL 拒绝)
  • SelectionPolishSection.tsx:设置入口去掉 os === 'win' 门控(保留桌面热键能力检查)

兼容性

  • Windows 行为零改动(cfg 隔离);macOS 机制全部复用既有跨平台原语(AX 选区读取、CGEvent Cmd+C/V、CGEventTap modifier 热键、预览窗)
  • 无新增权限:macOS 依赖既有「辅助功能」权限(AX + 事件 tap),权限页已有管理入口

测试

  • cargo test:940 passed / 0 failed(selection_text_matches 等随 cfg 扩展在 macOS 编译)
  • npm run build + npm test:16 项契约全过
  • 手动 macOS 待 DMG 构建后执行(设置页入口 → 选中文字按右 Option → 直接覆盖;预览确认模式替换回原位;无选区提示;润色期间切应用拒绝粘贴)

证据路径

DMG 构建后附截图/录屏。

- selection.rs:SelectionInsertionTarget 增加 macos 字段(前台应用名 + pid);
  capture/is_captured/validate/reactivate 四函数实现 macOS 分支:
  * validate = 前台应用一致性 + 选区重读(AX 直读,失败退化为模拟 Cmd+C)比较
  * reactivate = NSRunningApplication activateWithOptions 交还焦点
- types.rs:macOS 默认选中润色热键 = RightAlt(右 Option,CGEventTap keycode
  61 可区分左右,不占用 Cmd/Ctrl 常用组合),与 Windows 保持一致
- capabilities:selection-polish-preview 窗口加入默认能力列表(预览窗事件
  listen 之前会被 ACL 拒绝)
- SelectionPolishSection:设置入口去掉 os==='win' 门控,macOS 可见
- 单测:selection_text_matches 随 cfg 扩展在 macOS 编译,940 pass
@appergb
appergb merged commit b62e232 into beta Aug 5, 2026
4 checks passed
bigsongeth added a commit to bigsongeth/openless that referenced this pull request Aug 5, 2026
beta 一次进了 13 个提交,其中三条正是本地 daily 上那批私货合上游了
(Open-Less#910 历史落点+重试、Open-Less#908 翻译、Open-Less#909 概览),daily 的 patch queue 相应缩小。

冲突只有 selection.rs 一处,而且 HEAD 侧是空的:beta 的选区润色 macOS 移植
(Open-Less#926)在同一位置加了 current_front_app_pid 与 Windows/其他平台的
current_front_app,本分支在附近加了 bundle_id_for_pid(闸门按元素归属判定用)。
两者互不相干,取 beta 侧即可。

解完核对:bundle_id_for_pid 仍在(1 处),current_front_app 三个定义分属
macOS / Windows / 其他平台且 cfg 互斥,current_front_app_pid 无重复。

验证:cargo check 干净、cargo test --lib 1032 passed(beta 带来 30 个新用例)、
tsc --noEmit 干净、npm test 通过。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bigsongeth added a commit to bigsongeth/openless that referenced this pull request Aug 5, 2026
…重复定义

上一个合并 commit 解 selection.rs 冲突时,我看到 HEAD 侧是空的,就当成「beta 纯
新增」取了 theirs。判断错了:**空的 HEAD 侧也可能意味着「这一侧删掉了它」**。

本分支在里程碑 1 把 current_front_app 重构成了 current_front_app_parts 之上的通用
包装(无 cfg,一份顶所有平台);beta 没有这个重构,那边仍是按平台各写一份。git 看
到的是「我删了平台版本、beta 改了平台版本」,取 theirs 等于把被重构掉的两份又请了
回来:

  1017  pub(crate) fn current_front_app()          无 cfg,所有平台
  1066  #[cfg(windows)] fn current_front_app()     ← 重新带回来的
  1094  #[cfg(not(macos),not(windows))] fn ...     ← 重新带回来的

macOS 上恰好不冲突(那两个 cfg 都不成立),所以本地全绿;Linux 上 1017 与 1094 撞
成 E0428,Windows 会以同样方式撞 1017 与 1066——CI 先报了 Linux,Windows 当时还在
排队。

删掉重新带回来的那两份,保留通用包装。beta 真正新增的 current_front_app_pid(选区
润色 macOS 移植 Open-Less#926 要用)留下。

核对平台覆盖:current_front_app_parts 三个实现互斥且全覆盖;current_front_app_pid
是 macOS 专属,唯一调用点也在 macOS 分支内。

cargo check 干净、cargo test --lib 1032 passed(macOS)。Linux / Windows 交给 CI。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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