diff --git a/ROADMAP.md b/ROADMAP.md index 53571eb3..14f0fa44 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -245,7 +245,8 @@ ADR-147:Terminal正常实际提交“你”及wq前缀确认后的failure/INT/ - [ ] **2026-10-27 MVP 正式发布(目标 `1.0.0`,ADR-298)**:阶段 A 在 0.1.16/26 上演练 IT-22(`docs/tasks/T-ITER-22.md`)→ 修复入库 → 阶段 B 递增 1.0.0(build 27)并双机装同一包(同时闭环「更新器自更新」)→ 阶段 C 只在 1.0.0 上做正式 IT-22、IT-15 独立重建、IT-23 五工作日 → 阶段 D `tag v1.0.0` 打在验收候选提交 → Release → Pages。 - [x] 2026-10-28 **锁定候选 1.0.0 / build 29**(报告217):提交 `11abece3`、ZIP `aca4ed5c…`、宿主执行 `4ad949e6…`,air 已装同包。装机定向复验:2.1 多词拼接 PASS、9.1 编码播报 PASS、11.1 候选跟随(6 张截图:下方/镜像/底部翻上,无压字)PASS。**IT-22 限定范围通过**(必查 11 + 抽查 8 全 PASS,其余沿用报告216 基线)。 - [x] 2026-10-28 **IT-15 独立离线重建通过(报告218)**:用户在 air 上从候选自带源码包离线重建 1.0.0/build 29,身份链与逐架构网络导入 PASS、**默认数据 4/4 逐字节一致**、空闲 0 外联;可执行文件因本机 SDK 27.0 vs 发布 26.5 不同(ADR-033 边界)。顺带修掉 `run-repro.sh` 的缺陷:原来 `cmp` 可执行文件失败会中断,导致数据表比对根本没跑,且漏比 `variant-s2t.tsv`。 -- [ ] 2026-10-29 IT-23 五工作日试用(**1.0.0 / build 32**,air 与 pro 执行 SHA 均为 `ddd33b7a…`):两台设备已装同一包(报告217 §8)。29→30 修「候选窗跟随鼠标」,30→31 加 HUD 诊断,31→32 改「组合态切换不丢字」(ADR-302);IT-23 尚未起算。 +- [ ] 2026-10-29 IT-23 五工作日试用(**1.0.0 / build 33**,air 与 pro 执行 SHA 均为 `8a94ca33…`):两台设备已装同一包(报告217 §8)。31→32 改核心语义,32→33 补宿主两条路径(Shift/⌥M);IT-23 尚未起算。 +- [x] 2026-10-29 **组合态切换三条路径全部通过(报告222,build 33)**:Shift(`flagsChanged` 分支原样上屏编码)、⌥M(去掉 `applyInputMode` 里的取消,保留缓冲并重算)、⌥F(保留组合);教训是同一动作有多个入口,离线探针覆盖不到,必须装机按键复验。 - [x] 2026-10-29 **组合态切换不再丢字(ADR-302,报告221,build 32)**:`toggle_width`/`set_mode` 去掉 `cancel()`(保留组合、按新模式重算且不自动上屏),Shift 切英文改为**原样上屏编码**;core 新增 3 个单测,`ime-ffi` 旧用例改为先 Esc;两台设备已装 build 32。 - [x] 2026-10-29 **「HUD 不显示」结案(报告220)**:三次报告分别是诊断开关未生效无法取证、候选窗跟随鼠标(真缺陷,build 30 修)、**换包后旧进程仍在运行**。build 31 把诊断改为文件开关并给 `showStateFeedback`/`hudCaretRect` 各分支打点;`iterate-macos-ime` 收尾清单新增「`lsof … | grep -c deleted` 必须为 0」。 - [x] 2026-10-29 **候选窗跟着鼠标而不是插入点(报告219,build 30)**:`caretRect` 给解析器传了 `allowsEmptyCaret: false`,`length()==0` 时解析直接返回 nil → 落到鼠标兜底;改为 `true`,并把回退链收敛为「本轮 → 上次成功位置 → 鼠标」,新增 3 条断言。两台设备已装 build 30。 diff --git a/docs/reviews/217-1.0.0-freeze.md b/docs/reviews/217-1.0.0-freeze.md index d1dcdbee..bd8b0d91 100644 --- a/docs/reviews/217-1.0.0-freeze.md +++ b/docs/reviews/217-1.0.0-freeze.md @@ -123,13 +123,13 @@ platforms/macos/tests/run-repro.sh \ - **静态零外联**:`./scripts/verify-no-network.sh`(或 `make verify-no-network`)通过。 - **运行时零外联**:一边打字一边 `lsof -i -a -p "$(pgrep -x Lampyris)"`,预期**无输出**。 -## 8. IT-23 试用基线:两台设备装同一个包(2026-10-29 更新为 build 32) +## 8. IT-23 试用基线:两台设备装同一个包(2026-10-29 更新为 build 33) | 项 | air(本机,arm64 / macOS 27.0.1) | pro(x86_64 / macOS 13.7.8) | |---|---|---| -| 版本 / 构建 | **1.0.0 / 32** | **1.0.0 / 32** | -| 宿主执行 SHA-256 | `ddd33b7aa2962a6b4e5cc3f662624931b67f713c6428201d61979edec17dd66e` | **同值**(同一个二进制) | -| 更新程序构建号 | 32 | 32 | +| 版本 / 构建 | **1.0.0 / 33** | **1.0.0 / 33** | +| 宿主执行 SHA-256 | `8a94ca339c1c02d98b9472be1fcd17e7ebecd30a2f99ee799ed6430364e587e2` | **同值**(同一个二进制) | +| 更新程序构建号 | 33 | 33 | | 签名 / 公证 | Developer ID + `spctl` Notarized | 同(`codesign --strict`、`stapler validate` 均 PASS) | | 用户数据 | config `cfc86cff…`、词库 800+ 行 | config `cb8e7d05…`、词库 **727 行**(build 32 装前装后一致) | | 旧版本备份 | `updates/`、`uninstalled/` 历史项 | `uninstalled/bundle.aPZKev`(0.1.16) | @@ -147,3 +147,5 @@ pro 的安装记录:`ev-95-pro-stage.log`(ZIP 校验 → 解包 → 停宿 > 实为**旧进程仍在运行**(报告 220),不是产品缺陷。诊断文件已删除,无文件时零开销;两台设备均已在 31。 > **31 → 32 的原因**:组合态下按 Shift/⌥M/⌥F 会丢字(报告 221 / ADR-302),改为「Shift 原样上屏编码、⌥M/⌥F 保留组合」。 > IT-23 仍未起算,基线跟随最终行为。 +> **32 → 33 的原因**:build 32 只修到核心层,Shift(`flagsChanged` 路径)与 ⌥M(`applyInputMode` 先取消组合) +> 都走宿主分支,装机复验只有 ⌥F 通过(报告 222)。33 把这两条也改到「保留/原样上屏」,两台设备均已安装。 diff --git a/docs/reviews/221-switch-keeps-composition.md b/docs/reviews/221-switch-keeps-composition.md index 99b16808..da176ffa 100644 --- a/docs/reviews/221-switch-keeps-composition.md +++ b/docs/reviews/221-switch-keeps-composition.md @@ -32,7 +32,7 @@ - core 新增 3 个单测(全角保留组合与候选、切模式保留缓冲区并重算、新模式无候选时保留编码且 Esc 仍可取消)。 - `ime-ffi` 的 `candidates_expose_source_codes` 原先依赖"切模式会清空缓冲",改为先 Esc 再切模式。 - 离线回归 56 文件 / 303 例、`make verify` 全绿;实机复验见 §5。 -- 装机:air 与 pro 均为 1.0.0/build 32(执行 `ddd33b7a…`),待用户按 §5 复验三条快捷键。 +- 装机:build 32 只有 ⌥F 通过,Shift/⌥M 未生效(详见报告 222);build 33 修好后三条全部通过。 ## 5. 遗留 diff --git a/docs/reviews/222-switch-paths-in-host.md b/docs/reviews/222-switch-paths-in-host.md new file mode 100644 index 00000000..2706d67e --- /dev/null +++ b/docs/reviews/222-switch-paths-in-host.md @@ -0,0 +1,52 @@ +# 222 组合态切换:核心改对了,但宿主两条路径没走到(build 32 → 33) + +> 承接报告 [221](221-switch-keeps-composition.md)。build 32 装机复验:**⌥F 通过,Shift 与 ⌥M 仍丢字**。 +> 本报告记录这两条为什么没被上一版修到,以及修法与最终复验。 + +## 1. 为什么 build 32 只修好了 ⌥F + +| 快捷键 | 实际入口 | build 32 改在哪 | 结果 | +|---|---|---|---| +| ⌥F | `toggleWidth()` → `session.toggleWidth()` → `refreshAfterStateChange()` | **核心** `Session::toggle_width`(去掉 `cancel()`) | ✅ 生效 | +| Shift | `handle(_:)` 的 `.flagsChanged` 分支 → `session.shiftTransition(...)` → `clearMarked` + `hide()` | 宿主的 `toggleEnglish(_:)`(**菜单/快捷键**入口) | ❌ 键盘走不到 | +| ⌥M | `applyInputMode()` → **先** `cancelClientComposition()` **再** `setMode()` | 核心 `Session::set_mode`(保留组合) | ❌ 取消发生在调用核心之前 | + +两条都不是「改错了」,而是**改在了另一条等价入口上**——截图/探针都看不出来,只有真机按键能暴露。 + +## 2. 修法(build 33) + +**Shift**:在 `shiftTransition` 之前把编码取出来(它内部会 `cancel()`),切换后 `clearMarked` + `insertText(raw)`: + +```swift +let pendingRaw = session.isComposing && !session.isEnglish ? session.buffer : nil +let toggled = session.shiftTransition(isDown: flags.contains(.shift), otherModifier: other) +if toggled { + if let client { clearMarked(client) } + if let raw = pendingRaw, !raw.isEmpty, let client { client.insertText(raw, ...) } + candidateWindow?.hide() + showStateFeedback(StateFeedback.language(session.isEnglish)) +} +``` + +**⌥M**:去掉 `applyInputMode()` 里的 `cancelClientComposition()`,改为 + +```swift +session?.setMode(next) // 核心保留缓冲区并按新模式重算 +showStateFeedback(StateFeedback.mode(next)) +refreshAfterStateChange() // 预编辑与候选跟上新模式 +``` + +## 3. 验证 + +| 项 | 结果 | +|---|---| +| `test-controller-menu`(真实 IMK 派发探针) | PASS | +| `make verify` | PASS | +| `make macos-offline-tests` | 56 文件 / 303 例 PASS | +| **实机(build 33,用户)** | ① 打字出候选 → Shift:文档落下 `nihao` 字母并切英文 **PASS**;② 打字出候选 → ⌥M:候选框不消失、候选按新模式刷新 **PASS**;③ ⌥F 保持 PASS | + +## 4. 教训 + +1. **同一个动作常有多个入口**(键盘 / 菜单 / 快捷键 / 探针),改行为时要先把入口列全再动手;本次 `toggleEnglish` 有两条,`setMode` 有三个调用点。 +2 这两条路径属 AppKit 事件处理,**离线探针覆盖不到**,必须装机按键复验——build 32 的"已改完"结论下得太早。 +3. 已在 `iterate-macos-ime` 的收尾清单里强调:换包后先确认跑的是新二进制(报告 220),再做行为判断。 diff --git a/docs/reviews/223-drop-language-chip.md b/docs/reviews/223-drop-language-chip.md new file mode 100644 index 00000000..b02bdda4 --- /dev/null +++ b/docs/reviews/223-drop-language-chip.md @@ -0,0 +1,32 @@ +# 223 候选窗去掉「中文/英文」芯片(ADR-303) + +> 用户观察:候选框出现时中英状态始终显示「中文」,而按 Shift 切英文时候选框直接消失—— +> 那么这枚芯片就恒为「中文」,属于多余信息。要求确认后取消,以节省候选框空间。 + +## 1. 确认:这是结构性的,不是显示 bug + +| 证据 | 结论 | +|---|---| +| `Session::handle_key` 首行 `if self.english { commit; return }` | 英文模式每键立即上屏,**不建缓冲区** | +| `Session::composing()` 仅在 `handle_key` 的非英文分支置真 | 英文模式下永远 false | +| `InputController.showCandidates` 只在 `isComposing` 分支被调用 | 候选窗**不可能**在英文态出现 | +| ADR-302 后 Shift 切英文会先提交编码再切 | 切换瞬间组合即结束,窗口随之隐藏 | + +即:**候选窗可见 ⇒ 一定处于中文输入**,芯片恒为「中文」。 + +## 2. 改动 + +- `CandidateStatus.chips`:5 枚 → 4 枚(模式 / 全半角 / 简繁 / 标点) +- `CandidateStatus.english` 字段删除;`accessibilityLabel` 去掉「语言:」分支 +- 构造点同步:`InputController.candidateStatus()`、`Preview/main.swift` +- 断言同步:`candidate-presentation`(两次芯片列表断言 + 文案)、`ui-snapshots` 4 处 + +## 3. 验证 + +- `make macos-offline-tests`:56 文件 / 303 例 PASS +- 实机(build 34):待用户确认外观 + +## 4. 不丢的信息 + +- 中英切换时弹 HUD(约 1.15 秒),VoiceOver 仍通过 `StateFeedback.language` 播报「语言:中文/英文」 +- 模式 / 全半角 / 简繁 / 标点仍有芯片内联反馈 diff --git "a/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" "b/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" index c8bdab9e..9bf148f5 100644 --- "a/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" +++ "b/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" @@ -2747,6 +2747,15 @@ - **验证**:`crates/ime-core` 新增 3 个单测(`toggle_width_keeps_the_composition`、`set_mode_keeps_the_buffer_and_recomputes`、`set_mode_without_candidates_keeps_the_buffer_for_escape`);`crates/ime-ffi` 的 `candidates_expose_source_codes` 改为先显式 Esc 再切模式(旧用例依赖了已删除的取消语义);`test-controller-menu`、`test-composition-navigation`、`make verify`、`make macos-offline-tests`(56 文件/303 例)全绿;实机复验见报告 221。 - **关联**:ADR-062(模式/限长)、ADR-211(状态反馈)、`crates/ime-core/src/lib.rs`、`platforms/macos/Sources/InputController.swift`、报告 221。 +## ADR-303:候选窗不再显示「中文/英文」芯片 + +- **编号**:303 +- **决策**:`CandidateStatus.chips` 移除中英芯片(原 5 枚降为 4 枚:模式 / 全半角 / 简繁 / 标点),`CandidateStatus.english` 字段一并删除。 +- **理由**:用户观察「候选框出现时中英状态永远是中文,切英文候选框直接消失」。代码确认这是结构性的:英文模式下 `handle_key` 每键立即 `commit`,`composing` 永远为 false,候选窗不可能出现。因此这枚芯片恒为「中文」,只是占宽度(约 36pt)与一行视觉噪音。 +- **边界**:中英切换的反馈不丢——候选窗不可见时本来就走 HUD(ADR-211),屏幕阅读器仍有 `StateFeedback.language` 的播报;不新增配置项;不改变其它三枚芯片与标点符号芯片。 +- **验证**:`candidate-presentation` 芯片断言改为 4 枚(不含中英)、`ui-snapshots` / `Preview` 构造点同步;`make macos-offline-tests` 56 文件 / 303 例全绿;实机外观见报告 223。 +- **关联**:ADR-211(内联芯片与 HUD 分工)、ADR-291/300(播报)、报告 223、`platforms/macos/Sources/CandidateWindow.swift`。 + ## 待定项 | 编号 | 议题 | 说明 | diff --git "a/docs/\345\217\221\345\270\203\350\257\264\346\230\216.md" "b/docs/\345\217\221\345\270\203\350\257\264\346\230\216.md" index 46a03f0e..7b3a21ed 100644 --- "a/docs/\345\217\221\345\270\203\350\257\264\346\230\216.md" +++ "b/docs/\345\217\221\345\270\203\350\257\264\346\230\216.md" @@ -83,7 +83,7 @@ | **`⌥A`** | 关于 | `hotkey.open_about`;— | | **`,` / `.`**(组合态) | 上一页 / 下一页候选 | `candidate.page_with_comma`;否 | -> 每次状态变化(中英 / 全角半角 / 简体繁体 / 标点 / 模式 / 学习区)都会即时反馈:候选框可见时在顶部右侧(翻页区左边)更新两字状态芯片(混输/中文/半角/简体 + 标点);候选框未显示时在光标上方弹出约 1.15 秒的提示(仅在聚焦文本输入框时)。两者都不抢焦点、不写配置。 +> 每次状态变化(中英 / 全角半角 / 简体繁体 / 标点 / 模式 / 学习区)都会即时反馈:候选框可见时在顶部右侧(翻页区左边)更新两字状态芯片(混输/五笔/拼音、全角/半角、简体/繁体 + 标点;中英不显示,见 ADR-303);候选框未显示时在光标上方弹出约 1.15 秒的提示(仅在聚焦文本输入框时)。两者都不抢焦点、不写配置。 > 各组快捷键都可在 `config.toml` 改:组合键写法 `ctrl|shift|alt|cmd + 键`(空格写 `space`);`hotkey.toggle_english = "shift"` 表示“单独按 Shift”;任一项设为 `"none"` 即关闭。输入法菜单的状态项(混输/五笔/拼音、中文/英文、全角/半角、简体/繁体、中文标点/英文标点)**直接显示当前值**并在右侧列出快捷键(单按 Shift 切中英时在快捷键位显示 `⇧`);菜单「偏好设置」打开设置面板(设置项即列出全部可调项与快捷键);「版本信息」窗口含诊断,可「复制信息」或点「反馈问题」/「反馈漏洞」跳转。 diff --git a/packaging/build-number b/packaging/build-number index bb95160c..a7873645 100644 --- a/packaging/build-number +++ b/packaging/build-number @@ -1 +1 @@ -33 +34 diff --git a/platforms/macos/Preview/main.swift b/platforms/macos/Preview/main.swift index 4adb3a7c..b30e15ba 100644 --- a/platforms/macos/Preview/main.swift +++ b/platforms/macos/Preview/main.swift @@ -147,11 +147,11 @@ final class PreviewInput: NSTextView { let summary = values.map { "\(CandidateTextPresentation.display($0.text))[\($0.source.label)]" }.joined(separator: " · ") status?("\(session.variantErrorMessage.map { $0 + " " } ?? "")词库:\(session.dictionaryError == IME_OK ? "正常" : "读写失败") 页:\(session.pageIndex + 1)/\(session.pageCount) 组合:\(session.buffer.isEmpty ? "(空)" : session.buffer) 候选:\(summary)") let status = CandidateStatus( - mode: session.mode, english: session.isEnglish, fullWidth: session.isFullWidth, + mode: session.mode, fullWidth: session.isFullWidth, traditional: session.isTraditional, chinesePunctuation: (ImeConfig.string("input.punctuation") ?? "chinese") == "chinese") let caret = firstRect(forCharacterRange: NSRange(location: content.length, length: 0), actualRange: nil) - let feedback = (status.mode, status.english, status.fullWidth, status.traditional, + let feedback = (status.mode, session.isEnglish, status.fullWidth, status.traditional, status.chinesePunctuation, ImeConfig.bool("candidate.show_wubi_learning")) if let last = lastFeedback, last != feedback { if session.isComposing { @@ -161,7 +161,7 @@ final class PreviewInput: NSTextView { if last.0 != feedback.0 { message = StateFeedback.mode(status.mode) } else if last.1 != feedback.1 { - message = StateFeedback.language(status.english) + message = StateFeedback.language(session.isEnglish) } else if last.2 != feedback.2 { message = StateFeedback.width(status.fullWidth) } else if last.3 != feedback.3 { diff --git a/platforms/macos/Sources/CandidateWindow.swift b/platforms/macos/Sources/CandidateWindow.swift index 057954ed..77bc3ddc 100644 --- a/platforms/macos/Sources/CandidateWindow.swift +++ b/platforms/macos/Sources/CandidateWindow.swift @@ -509,16 +509,18 @@ private final class LearningDetailsView: NSView { /// 候选窗顶部右侧的状态摘要;单字芯片,压缩到不抢候选与翻页的注意力。 struct CandidateStatus: Equatable { var mode: String - var english: Bool var fullWidth: Bool var traditional: Bool var chinesePunctuation: Bool /// 两字状态 + 标点符号;学习区不在这里显示(下方学习区本身就是状态)。 + /// + /// 不显示中英芯片(ADR-303):候选窗只在组合态出现,而组合只可能在中文输入下产生 + /// (英文模式每键立即上屏、不建缓冲区),所以这枚芯片永远是「中文」,纯占位置。 + /// 中英切换的反馈由 HUD 承担,屏幕阅读器仍能听到「语言:中文/英文」。 var chips: [(text: String, active: Bool)] { [ (mode == "wubi" ? "五笔" : mode == "pinyin" ? "拼音" : "混输", mode != "mixed"), - (english ? "英文" : "中文", english), (fullWidth ? "全角" : "半角", fullWidth), (traditional ? "繁体" : "简体", traditional), (chinesePunctuation ? "。" : ".", !chinesePunctuation), @@ -528,7 +530,6 @@ struct CandidateStatus: Equatable { func accessibilityLabel(for text: String) -> String { switch text { case "混输", "五笔", "拼音": return "输入模式:" + text - case "中文", "英文": return "语言:" + text case "全角", "半角": return "宽度:" + text case "简体", "繁体": return "字形:" + text case "。": return "标点:中文标点" diff --git a/platforms/macos/Sources/InputController.swift b/platforms/macos/Sources/InputController.swift index 89ce2114..343935b4 100644 --- a/platforms/macos/Sources/InputController.swift +++ b/platforms/macos/Sources/InputController.swift @@ -424,7 +424,6 @@ final class LampyrisInputController: IMKInputController { private func candidateStatus() -> CandidateStatus { CandidateStatus( mode: session?.mode ?? ImeConfig.string("mode") ?? "mixed", - english: session?.isEnglish ?? false, fullWidth: session?.isFullWidth ?? false, traditional: session?.isTraditional ?? false, chinesePunctuation: (ImeConfig.string("input.punctuation") ?? "chinese") == "chinese") diff --git a/platforms/macos/tests/candidate-presentation.swift b/platforms/macos/tests/candidate-presentation.swift index bd3b313f..06d79580 100644 --- a/platforms/macos/tests/candidate-presentation.swift +++ b/platforms/macos/tests/candidate-presentation.swift @@ -256,32 +256,32 @@ guard !window.accessiblePressForTesting(at: 0), !window.pagePressForTesting(1), else { fail("hidden stale actions") } LocalAcceptanceEvidence.record("candidate.stale", expected: "隐藏后旧选词和翻页动作失效", actual: ["selected": selected, "input": window.displayedInput, "page_visible": window.pageStateForTesting.visible]) // 头部状态芯片:右对齐到翻页区左侧、与翻页按钮同中心线;学习区开启时追加“学”。 -window.updateStatus(CandidateStatus(mode: "mixed", english: true, fullWidth: true, +window.updateStatus(CandidateStatus(mode: "mixed", fullWidth: true, traditional: false, chinesePunctuation: false)) window.update(candidates: values, pageIndex: 0, pageCount: 30, input: "tr") window.layout(at: caret, within: NSRect(x: 0, y: 0, width: 1000, height: 400)) let chipTexts = window.stateChipsForTesting let stripFrame = window.stateStripFrameForTesting let pagerFrame = window.pageFramesForTesting[0] -guard chipTexts == ["混输", "英文", "全角", "简体", "."] else { fail("state chips " + chipTexts.joined()) } +guard chipTexts == ["混输", "全角", "简体", "."] else { fail("state chips " + chipTexts.joined()) } let inputFrame = window.inputFrameForTesting // 翻页区为光学对齐整体上提 1.5pt:允许比芯片中心高 0–2pt,而不是要求严格相等。 let pagerLift = pagerFrame.midY - stripFrame.midY guard stripFrame.maxX <= pagerFrame.minX, stripFrame.minX >= 16, pagerLift >= 0.5, pagerLift <= 2.5, abs(inputFrame.midY - stripFrame.midY) < 0.5 else { fail("header items not aligned") } -window.updateStatus(CandidateStatus(mode: "pinyin", english: false, fullWidth: false, +window.updateStatus(CandidateStatus(mode: "pinyin", fullWidth: false, traditional: true, chinesePunctuation: true)) -guard window.stateChipsForTesting == ["拼音", "中文", "半角", "繁体", "。"] else { fail("state chips value") } +guard window.stateChipsForTesting == ["拼音", "半角", "繁体", "。"] else { fail("state chips value") } LocalAcceptanceEvidence.record("candidate.status", - expected: "两字状态芯片 5 枚(学习区不占芯片)右对齐到翻页左侧且同中心线", + expected: "两字状态芯片 4 枚(不含中英,学习区不占芯片)右对齐到翻页左侧且同中心线", actual: ["chips": chipTexts, "gap": pagerFrame.minX - stripFrame.maxX, "center_delta": abs(stripFrame.midY - pagerFrame.midY)]) // Batched status/content refresh must retain the standalone layout contract. let batchedWindow = CandidateWindow() let referenceWindow = CandidateWindow() for (index, mode) in ["mixed", "wubi", "pinyin", "mixed"].enumerated() { - let status = CandidateStatus(mode: mode, english: index % 2 == 1, + let status = CandidateStatus(mode: mode, fullWidth: index % 2 == 0, traditional: index == 2, chinesePunctuation: index != 1) let selected = index % values.count diff --git a/platforms/macos/tests/ui-snapshots.swift b/platforms/macos/tests/ui-snapshots.swift index 73a9e72c..c77371ac 100644 --- a/platforms/macos/tests/ui-snapshots.swift +++ b/platforms/macos/tests/ui-snapshots.swift @@ -114,13 +114,13 @@ for (theme, appearance) in themes { guard ImeConfig.setString("appearance.theme", theme) else { exit(1) } let window = CandidateWindow() window.setAppearanceForTesting(NSAppearance(named: appearance)!) - window.updateStatus(CandidateStatus(mode: "mixed", english: false, fullWidth: false, + window.updateStatus(CandidateStatus(mode: "mixed", fullWidth: false, traditional: false, chinesePunctuation: true)) window.update(candidates: short, input: "wq") window.layout(at: caret, within: area) save(window.renderSnapshotForTesting(), "candidate-single-\(theme)") reportCandidate(window, theme, "single") - window.updateStatus(CandidateStatus(mode: "mixed", english: true, fullWidth: true, + window.updateStatus(CandidateStatus(mode: "mixed", fullWidth: true, traditional: false, chinesePunctuation: false)) window.update(candidates: short, pageIndex: 0, pageCount: 55, input: "wq") window.layout(at: caret, within: area) @@ -128,13 +128,13 @@ for (theme, appearance) in themes { save(window.renderSnapshotForTesting(), "candidate-pager-\(theme)") window.simulateHover(at: 1, false) reportCandidate(window, theme, "pager") - window.updateStatus(CandidateStatus(mode: "wubi", english: false, fullWidth: false, + window.updateStatus(CandidateStatus(mode: "wubi", fullWidth: false, traditional: true, chinesePunctuation: true)) window.update(candidates: longWords, pageIndex: 0, pageCount: 2, input: "kwwl") window.layout(at: caret, within: area) save(window.renderSnapshotForTesting(), "candidate-long-\(theme)") reportCandidate(window, theme, "long") - window.updateStatus(CandidateStatus(mode: "pinyin", english: true, fullWidth: false, + window.updateStatus(CandidateStatus(mode: "pinyin", fullWidth: false, traditional: false, chinesePunctuation: false)) window.update(candidates: short, pageIndex: 0, pageCount: 55, input: "wq", hint: "键位提示:W 人 · Q 金") window.layout(at: caret, within: area)