Skip to content
weijianz edited this page Oct 14, 2026 · 7 revisions

English

代码结构

Swift Package(Package.swift,swift-tools-version 6.0,最低 macOS 14)。下面列的是主要文件,还有别的(AI 服务、插件、菜单栏面板、安装程序)。

Sources/
  AllInOneIMECore/        纯逻辑,不依赖 AppKit
    Composer.swift          两级输入状态机:拼音、韩文和印地语、草稿、@ 命令和命令列表、⌃V 和 ⌘V、语音手势、执行键
    Command.swift           @ 命令的定义和解析
    ActionKey.swift         执行键
    Config.swift            config.json
    Prompt.swift            提示词
    Converter.swift         一次请求:读配置和凭证、调 Bedrock、解析流、缓存
    CandidateParser.swift   解析模型输出的各行
    BedrockClient.swift     ConverseStream 客户端
    EventStream.swift       AWS event-stream 解码
    SigV4.swift             请求签名
    AWSSharedConfig.swift   读 ~/.aws/credentials 和 ~/.aws/config
    RewriteStyle.swift      改写风格和示例
    JargonLibrary.swift     黑话词表
    InputSourceList.swift   在用户的输入法列表(AppleEnabledInputSources)里增删
    LegacyData.swift        从 AIPinyin 的目录迁移数据
    LanguagePack.swift      语言包:目录、已安装的语言包、校验;LanguagePackLibrary.swift:签名的索引
    LatinEngine.swift       英文输入,按键盘布局组合死键
    FuzzyPinyin.swift       模糊音,写成 rime_ice.custom.yaml
    AppVersion.swift        版本号
    Hangul.swift            韩语:两套式键位表(来自 ko-hangul 语言包)和组成音节
    Hindi.swift             印地语:拉丁字母 → 天城文(来自 hi-phonetic 语言包),它的输入引擎
    Language.swift          输入语言,以及一句话是用哪种语言写的
    ScriptCommand.swift     脚本扩展:协议的键、Raycast 的键怎么对应过来、参数、环境变量
    ScriptOutput.swift      脚本的输出:文字、summary/detail、Alfred Script Filter 列表和它们的动作
    ExtensionStore.swift    扩展的文件夹、扩展包(extension.json)和偏好设置、文件缓存、用聚焦查找
    ScriptScheduling.swift  状态轮流刷新、后台的名额、命令列表只在变化时重建
    Engine.swift、KeyMapping.swift
  AllInOneIMERime/        librime 的 Swift 封装(Rime.swift)
  CRime/                  librime C API 的 module map
  AllInOneIME/            输入法进程(InputMethodKit)
    main.swift              入口,以及 --register / --disable / --status / --settings / --selftest / --install-pack
    InputController.swift   执行 Composer 返回的效果:文本框、候选框、Bedrock、终端、剪贴板、语音
    CandidatePanel.swift    候选框
    SettingsWindow.swift    设置窗口(SwiftUI)
    LanguagePacks.swift     下载和安装语言包
    UIText.swift            界面文字(中文 / 英文)
    VoiceInput.swift        麦克风和 SpeechAnalyzer
    SecureInput.swift       安全输入的判断
    LiveExtensions.swift    脚本扩展:在后台重建索引、状态
    ScriptTasks.swift       脚本扩展的运行、后台运行、通知
    FileSearch.swift        @open 的搜索
    TerminalLauncher.swift  @claude
    InputSourceRegistrar.swift  注册输入源、改输入法列表
    SelfTest.swift          make selftest
  AllInOneIMESettings/    「AllInOneIME 设置」启动器:用 --settings 打开输入法的设置窗口
  allinoneime-cli/        在终端里跑 @improve 的开发工具
Tests/
  AllInOneIMECoreTests/   Core 的单元测试;Fixtures/ 里是 event-stream 测试数据
  AllInOneIMERimeTests/   用真实 librime 和 ThirdParty/rime-data 的测试
Resources/                三个 Info.plist(输入法、设置、安装程序)、本地化字符串、图标、entitlements、rime/default.custom.yaml
Scripts/                  截图、图标、磁盘映像、语言包和它的索引、wiki 翻译、real-app 测试、fixture
ThirdParty/               make deps 下载的 librime 和雾凇拼音(不在仓库里)

输入法本身的开发参数见 ~/Library/Input Methods/AllInOneIME.app/Contents/MacOS/AllInOneIME --help。

make 目标

目标 作用
make / make app 编译并打包 build/AllInOneIME.app
make deps 下载并校验 librime 1.16.1 和雾凇拼音 2026.06.30,预编译词库(到 ThirdParty/)
make build 只编译输入法(swift build)
make settings-app 打包 build/AllInOneIME Settings.app
make installer-app 打包 build/Install AllInOneIME.app,磁盘映像里的安装程序
make install 打包两个 App,装到 ~/Library/Input Methods 和 ~/Applications,注册输入法并加进输入法列表
make uninstall 停用、移出输入法列表、删掉两个 App
make pack 中文语言包:build/packs/zh-pinyin-<版本>.tar.xz、它的 SHA-256 和 packs.json 条目
make packs 所有语言包:中文,以及 LanguagePacks/ 里的韩语和印地语(ko-hangul、hi-phonetic)
make install-pack 用源码目录里的词库把中文语言包装进已安装的输入法,不用下载
make status 已安装输入法的状态,见 安装与排查
make test 单元测试和 Rime 测试(swift test)
make selftest 用模拟文本框驱动输入法,真实 Rime、真实 Bedrock
make screenshots 先 make selftest,再生成 docs/ 和 docs/en/ 里的截图
make panel-images 在屏幕上截菜单栏面板(毛玻璃、一行向左滑开):docs/panel-*.png、docs/en/panel-*.png
make dmg 发布用的安装包 build/AllInOneIME-<版本>.dmg(通用版)
make realtest 在另一个 App 的真实文本框里,通过已安装的输入法打字测试
make realtest-build / make realtest-run 只编译 / 只运行 real-app 测试程序
make realtest-when-unlocked 屏幕解锁后自动跑一次 realtest-run(临时的 launchd 任务)
make realtest-cancel 取消这个任务
make cli 编译 allinoneime-cli
make icon 从 Resources/AppIcon.png 重新生成 Resources/AppIcon.icns 和菜单栏图标 Resources/icon.tiff
make clean 删掉 .build 和 build
make distclean 再删掉 ThirdParty

变量:CONFIG(默认 release)、SIGN_IDENTITY(默认 Apple Development,找不到就 ad-hoc 签名)、OUT(selftest 的输出目录,默认 /tmp/allinoneime-selftest)、REALTEST_OUT(默认 ~/Library/Logs/AllInOneIME/realtest)。

make、make app、make selftest 和 make screenshots 都会留下 build/AllInOneIME.app。它和装好的那份 bundle ID 相同,macOS 可能启动它而不是装好的那份;用完就删掉(make install 会把它移走)。

测试

make test:swift test,两组测试。

  • AllInOneIMECoreTests:纯逻辑,用假的拼音引擎和桩网络(URLProtocol),不联网,不需要 AWS。其中 AppVersionTests 检查三个 Info.plist 的版本号和 AppVersion.string 一致。
  • AllInOneIMERimeTests:用真实的 librime 和 ThirdParty/rime-data(make test 会先 make deps)。

make selftest:先打包 build/AllInOneIME.app,再运行 AllInOneIME --selftest,用模拟的文本框驱动真实的输入控制器:真实 Rime、真实 Bedrock 请求(用你的 config.json 和 AWS 配置,会产生少量费用)、聚焦搜索;语音部分用 say 合成的语音测本机识别(没有 SpeechAnalyzer 时跳过)。它不碰剪贴板和麦克风,也不会真的打开文件或终端;设置窗口在临时的配置副本上测,不改你的 config.json。最后打印 SELFTEST PASSED 或 SELFTEST FAILED (n),截图写到 OUT。

make realtest:测的是已安装的输入法,所以先 make install。它另起一个带真实 NSTextView 的 App,走系统的文字输入路径打字;测试时临时切换输入法,结束后切回来。屏幕要已解锁;测试窗口会占用前台约 1 分钟,期间不要打字。结果在 ~/Library/Logs/AllInOneIME/realtest/output.txt,通过时有 REALTEST PASSED。锁屏时用 make realtest-when-unlocked,日志在 ~/Library/Logs/AllInOneIME/realtest-watch.log。

allinoneime-cli:用和输入法相同的 Core 代码在终端里跑 @improve,读同一个 config.json;参数可以覆盖它:

make cli
.build/release/allinoneime-cli --mode improve --styles concise,jargon "this is a blocker bug your team need fix it asap"
.build/release/allinoneime-cli --output es,fr,de "running 10 minutes late, start without me"
.build/release/allinoneime-cli --bench     # 内置的句子,报告延迟

其他参数:--provider(bedrock、anthropic、gemini 或 openai)、--profile、--region、--model、--jargon FILE、--raw(打印模型的原始输出)、--dump FILE(保存原始的 event-stream 响应,做测试数据)、--version。

截图

make screenshots 就是先 make selftest,再运行 Scripts/make-readme-images.swift,docs/(中文)和 docs/en/(英文)各一次。selftest 渲染候选框和设置窗口,脚本在每个候选框上面加一行文本,显示行内正在输入的文字。英文图来自它们自己的场景,不是中文场景换成英文界面:打的是英文,@translate 翻译成西班牙语、法语和德语,@question 用英文提问。

图 docs/(中文) docs/en/(英文)
demo.png 2-translate-pinyin + 3-translate en-translate-draft + en-translate
improve.png 1b-sentence-pinyin + 4-final-light en-improve-draft + en-improve
english.png 7-english-light + 7b-chinese-output —
voice.png 8-voice 8-voice-english-en
commands.png 10-palette + 11-question en-palette + en-question
open.png 12-open + 12b-open-path 同左,加 -en
panel-dark.png 4-final-dark en-improve-dark
settings.png 6-settings 6-settings-en(英文输入,翻译成西班牙语、法语、德语)
dashboard.png 14-dashboard 14-dashboard-en

菜单栏面板的毛玻璃没法离屏渲染(后面什么都没有),所以 make panel-images 把带示例数据的真实面板显示在一个色彩丰富的窗口上面,再用 screencapture 截下来(AllInOneIME --showcase)。

内容来自真实的 AI 回答,每次都会有出入,提交前看一眼。之后删掉 build/AllInOneIME.app。

约定

  • Bundle ID 和输入源 ID 一直是 com.aipinyin.inputmethod.AIPinyin:macOS 按它记住已添加的输入法、麦克风权限和偏好设置,改了用户就要重新添加和授权。日志的 subsystem 也是它。
  • 改了提示词的措辞,按 Prompt.swift 里注释说的,把 Prompt.version(@improve)或 Prompt.commandVersion(@question)加一;它们是缓存键的一部分。

发布清单

  1. 改版本号,四处一起改:Resources/Info.plist、Resources/Settings-Info.plist 和 Resources/Installer-Info.plist 里的 CFBundleShortVersionString(和 CFBundleVersion),以及 Sources/AllInOneIMECore/AppVersion.swift 里的 AppVersion.string。AppVersionTests 会检查它们是否一致。
  2. 英文的 README.md、CHANGELOG.md 和中文的 README.zh-CN.md、CHANGELOG.zh-CN.md 一起更新。
  3. 更新英文 wiki 页面;中文页面由 wiki-zh workflow(Scripts/translate-wiki.py)从英文翻译过来。
  4. make screenshots(面板有变化时再 make panel-images),然后检查 docs/ 和 docs/en/ 里的图:英文图里不能有中文。
  5. 删掉 build/AllInOneIME.app:rm -rf build/AllInOneIME.app。
  6. make dmg,然后发布(标为 Latest):更新日志英文在前、中文在后,每个看得见的变化配上它的截图(英文部分用 docs/en/,中文部分用 docs/),链接到具体的 commit,这样截图永远不会变。

Clone this wiki locally