Files
msime-windows/ui-html
e56bfabdf2 feat(server,ui-html): AI 联想候选徽标支持切换 🤖 / 🐳 (#948)
* feat(server,ui-html): AI 联想候选徽标支持切换 🤖 / 🐳

AI 联想候选的来源角标此前硬编码为 🤖,用户无法更改。按固定排位徽标
(#463)的既有做法把它做成可配置项 appearance.candidate_ai_badge_style,
取值 "robot"(🤖,出厂默认)或 "whale"(🐳)。

- 默认值保持 🤖 不变,升级不改变默认观感
- 与固定排位徽标一致,配置里存枚举名而不是字面 emoji,TOML/日志/diff
  里不出现图形字符;新增样式只改白名单与展示层映射
- 非法取值一律回退到出厂 🤖,手改 TOML 写错不会让 AI 候选失去来源标识
- 展示层新增纯函数 AiSuggestionBadge(style),沿用既有 badge 字段通道,
  D2D 与 WebView2 两个后端同时生效,不新增渲染路径
- 配置改动经既有 ConfigChanged → WM_APPLY_IME_CONFIG 链路即时生效,
  无需重启输入法进程
- 出厂模板 config.default.toml 与开发配置 config.toml 同步补齐,
  避免升级时用户选择被 MergeConfigIntoTemplate 静默丢弃

验证:
- server/tests/portable(Linux,g++,无 vcpkg):57 test(s), 0 failure(s)
- ui-html settings:vitest 167 passed,tsc --noEmit 通过,vite build 通过
- clang-format 18.1.8 --dry-run --Werror --style=file:改动文件全部通过
- scripts/ci/check-developer-paths.sh 通过;sync-contracts.py --check 通过

* fix(server): 补齐 IsValidCandidateAiBadgeStyle 的跨编译单元声明

ime_config_appearance.cpp 是独立编译单元,无法看到定义在 ime_config.cpp
里的 IsValidCandidateAiBadgeStyle,MSVC 报 C3861。补上 ime_config_internal.h
里的声明——IsValidCandidateFixedBadgeStyle 等同类校验函数都声明在那里。

* refactor(server,ui-html): AI 徽标样式改为单一映射表并精简测试

- AiSuggestionBadgeGlyph 作为样式到字形的唯一映射,配置层白名单
  IsValidCandidateAiBadgeStyle 直接查它,新增样式不会两边漂移
- 测试去掉与首条断言重复的一行和恒真的 cloud 断言,改为检查映射表
  对已知/未知样式的判定
- 设置页描述写明两种样式对应的 emoji

---------

Co-authored-by: Caiyi Liao <216114941+cxk1993@users.noreply.github.com>
Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-15 02:44:27 +08:00
..
2025-12-08 13:29:47 +08:00
2025-11-10 21:13:13 +08:00

Metasequoia IME UI HTML

水杉输入法 Windows 端的界面资源。Server 加载这里的页面来渲染候选窗、悬浮工具栏、托盘菜单和设置窗口。

webview2/shared/ 是引擎 web 契约的副本,由 scripts/sync-contracts.py 从 ../engine/contracts/webview/ 生成,CI 用 --check 验证两者一致。要改契约请改那边,再在同一个提交里重新生成,不要直接改这个目录。

同仓的相关组件:../windows/(TSF 前端)、../server/(后端与窗口宿主)、../engine/(输入引擎与契约)。

目录

路径 内容
webview2/candwnd/ 候选窗,含 skins/ 下的皮肤
webview2/ftb/ 悬浮工具栏
webview2/menu/ 托盘菜单
webview2/settings/ime-settings/ 设置页,唯一需要构建的部分,Vite + TypeScript
webview2/default-themes/、webview2/other-themes/ 主题

除设置页外都是直接分发的静态资源,改完即生效。

构建设置页

设置页是发布安装包的必要输入之一,pnpm build 的产物 dist/ 会被打包脚本收集。

cd webview2/settings/ime-settings
corepack enable
pnpm install --frozen-lockfile
pnpm build

pnpm 版本由 package.json 的 packageManager 字段固定,corepack enable 之后不用自己装。开发时用 pnpm dev 起本地服务。

本地调试

把本仓链接到 Server 的数据目录,改页面就不用重新打包:

$target = Join-Path $env:LOCALAPPDATA 'metasequoiaime\html'
if (Test-Path -LiteralPath $target) {
    Remove-Item -LiteralPath $target -Recurse -Force
}
New-Item -ItemType SymbolicLink -Path $target -Target (Resolve-Path .).Path

必须用绝对路径,Resolve-Path 就是用来把当前目录转成绝对路径的。设置页走这条路时链接的仍是仓库目录,页面读的是 webview2/settings/ime-settings/dist/,所以改完设置页要重新 pnpm build。

与 C++ 侧的边界

窗口归 Server,页面归本目录。HWND、尺寸、位置、DPI、Z-order 和 WebView2 controller 的生命周期都在 ../server/src/window/ 与 ../server/src/webview2/;页面结构、样式和浏览器端交互在这里。

C++ → 页面主要经 WebView2 导航和脚本执行,页面 → C++ 经 window.chrome.webview.postMessage(...)。改消息 type、JSON 字段、页面导出的 JS 函数或 DOM 标识时,必须同步检查 Server 的消息解析与拼接代码,两边没有编译期约束。

候选内容和输入状态的权威在 Server 和引擎,页面只负责展示与发出用户动作;不要在页面侧复制候选选择、翻页、输入模式或配置持久化的状态机。

完整的组件边界约定见仓库根 AGENTS.md。