Repository navigation
Development
A Swift package (Package.swift, swift-tools-version 6.0, macOS 14 or later). The tree below shows the main files; there are more (providers, plugins, the menu bar panel, the installer).
Sources/
AllInOneIMECore/ pure logic, no AppKit
Composer.swift two-level input state machine: pinyin, draft, @ commands and the command list, ⌃V and ⌘V, voice gestures, action key
Command.swift @ command definitions and parsing
ActionKey.swift action key
Config.swift config.json
Prompt.swift prompts
Converter.swift one request: reads config and credentials, calls Bedrock, parses the stream, caches
CandidateParser.swift parses the lines of the model's output
BedrockClient.swift ConverseStream client
EventStream.swift AWS event-stream decoding
SigV4.swift request signing
AWSSharedConfig.swift reads ~/.aws/credentials and ~/.aws/config
RewriteStyle.swift rewrite styles and their examples
JargonLibrary.swift the jargon list
InputSourceList.swift adds to / removes from the user's input source list (AppleEnabledInputSources)
LegacyData.swift migrates data from AIPinyin's folders
AppVersion.swift version number
Engine.swift, KeyMapping.swift, Language.swift
AllInOneIMERime/ Swift wrapper for librime (Rime.swift)
CRime/ module map for the librime C API
AllInOneIME/ the input method process (InputMethodKit)
main.swift entry point, plus --register / --disable / --status / --settings / --selftest
InputController.swift performs the effects Composer returns: text field, candidate panel, Bedrock, Terminal, clipboard, voice
CandidatePanel.swift candidate panel
SettingsWindow.swift settings window (SwiftUI)
UIText.swift interface text (Chinese / English)
VoiceInput.swift microphone and SpeechAnalyzer
SecureInput.swift secure input detection
FileSearch.swift search for @open
TerminalLauncher.swift @claude
InputSourceRegistrar.swift registers the input source, edits the input source list
SelfTest.swift make selftest
AllInOneIMESettings/ "AllInOneIME Settings" launcher: opens the input method's settings window with --settings
allinoneime-cli/ dev tool that runs @improve in Terminal
Tests/
AllInOneIMECoreTests/ unit tests for Core; Fixtures/ holds event-stream test data
AllInOneIMERimeTests/ tests with the real librime and ThirdParty/rime-data
Resources/ the two Info.plist files, localized strings, icons, entitlements, rime/default.custom.yaml
Scripts/ screenshots, icons, real-app test, fixture generation
ThirdParty/ librime and rime-ice, downloaded by make deps (not in the repo)
For the input method's own development options, see ~/Library/Input Methods/AllInOneIME.app/Contents/MacOS/AllInOneIME --help.
| Target | What it does |
|---|---|
make / make app
|
Builds and packages build/AllInOneIME.app
|
make deps |
Downloads and verifies librime 1.16.1 and rime-ice 2026.06.30, precompiles the dictionaries (into ThirdParty/) |
make build |
Builds the input method only (swift build) |
make settings-app |
Packages build/AllInOneIME Settings.app
|
make install |
Packages both apps, installs them in ~/Library/Input Methods and ~/Applications, registers the input method and adds it to the input source list |
make uninstall |
Disables it, removes it from the input source list, deletes both apps |
make status |
Status of the installed input method; see Installation and Troubleshooting |
make test |
Unit tests and Rime tests (swift test) |
make selftest |
Drives the input method with a simulated text field, with real Rime and real Bedrock |
make screenshots |
Runs make selftest, then generates the screenshots in docs/ and docs/en/
|
make panel-images |
Captures the menu bar panel on screen (frosted glass, a row swiped open): docs/panel-*.png, docs/en/panel-*.png
|
make dmg |
The release installer, build/AllInOneIME-<version>.dmg (universal) |
make realtest |
Typing test through the installed input method, in a real text field of another app |
make realtest-build / make realtest-run
|
Only builds / only runs the real-app test program |
make realtest-when-unlocked |
Runs realtest-run once, automatically, after the screen is unlocked (a temporary launchd job) |
make realtest-cancel |
Cancels that job |
make cli |
Builds allinoneime-cli
|
make icon |
Regenerates Resources/AppIcon.icns and the menu bar icon Resources/icon.tiff from Resources/AppIcon.png
|
make clean |
Deletes .build and build
|
make distclean |
Also deletes ThirdParty
|
Variables: CONFIG (default release), SIGN_IDENTITY (default Apple Development; ad-hoc signing if it isn't found), OUT (the selftest's output folder, default /tmp/allinoneime-selftest), REALTEST_OUT (default ~/Library/Logs/AllInOneIME/realtest).
make, make app, make selftest and make screenshots all leave build/AllInOneIME.app behind. It has the same bundle ID as the installed copy, so macOS may launch it instead of the installed one; delete it when you're done (make install moves it away).
make test: swift test, two sets of tests.
-
AllInOneIMECoreTests: pure logic, with a fake pinyin engine and a stubbed network (URLProtocol); no network access, no AWS needed. Among them,AppVersionTestschecks that the versions in the two Info.plist files matchAppVersion.string. -
AllInOneIMERimeTests: uses the real librime andThirdParty/rime-data(make testrunsmake depsfirst).
make selftest: packages build/AllInOneIME.app, then runs AllInOneIME --selftest, which drives the real input controller with a simulated text field: real Rime, real Bedrock requests (with your config.json and AWS configuration; this costs a little), Spotlight search; the voice part tests on-device recognition with speech synthesized by say (skipped without SpeechAnalyzer). It doesn't touch the clipboard, the microphone or the sentence mode setting, and doesn't actually open files or Terminal; the settings window is tested on a temporary copy of the config, leaving your config.json unchanged. At the end it prints SELFTEST PASSED or SELFTEST FAILED (n), and writes the screenshots to OUT.
make realtest: tests the installed input method, so make install first. It starts a separate app with a real NSTextView and types through the system's text input path; it switches input sources for the test and back afterwards, and restores the sentence mode switch too. The screen must be unlocked; the test window holds the foreground for about a minute, so don't type meanwhile. Results are in ~/Library/Logs/AllInOneIME/realtest/output.txt, with REALTEST PASSED when it passes. When the screen is locked, use make realtest-when-unlocked; its log is ~/Library/Logs/AllInOneIME/realtest-watch.log.
allinoneime-cli: runs @improve in Terminal with the same Core code as the input method, reading the same config.json; options override it:
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 # built-in sentences, reports latencyOther options: --profile, --region, --model, --jargon FILE, --raw (prints the model's raw output), --dump FILE (saves the raw event-stream response, for test data), --version.
make screenshots is make selftest followed by Scripts/make-readme-images.swift, once for docs/ (Chinese) and
once for docs/en/ (English). The self-test renders the candidate panel and the settings window; the script puts each
panel under a text line with the inline text. The English images come from their own scenes, not the Chinese ones
with an English interface: English typed, @translate into Spanish, French and German, @question asked in English.
| Image |
docs/ (Chinese) |
docs/en/ (English) |
|---|---|---|
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
|
the same, -en
|
panel-dark.png |
4-final-dark |
en-improve-dark |
settings.png |
6-settings |
6-settings-en (English input, translating into Spanish, French, German) |
dashboard.png |
14-dashboard |
14-dashboard-en |
The menu bar panel's frosted glass can't be rendered offscreen (nothing is behind it), so make panel-images shows
the real panel with sample data over a colorful window and captures it with screencapture (AllInOneIME --showcase).
The content comes from real AI answers and differs each time, so look it over before committing. Delete
build/AllInOneIME.app afterwards.
- The bundle ID and input source ID stay
com.aipinyin.inputmethod.AIPinyin: macOS uses it to remember the added input method, microphone access and preferences, so changing it would make users add and authorize it again. It is also the log subsystem. - When you change the wording of a prompt, increment
Prompt.version(@improve) orPrompt.commandVersion(@question) as the comments inPrompt.swiftsay; they are part of the cache key.
- Change the version in all four places together:
CFBundleShortVersionString(andCFBundleVersion) inResources/Info.plist,Resources/Settings-Info.plistandResources/Installer-Info.plist, andAppVersion.stringinSources/AllInOneIMECore/AppVersion.swift.AppVersionTestschecks that they match. - Update
CHANGELOG.md. - Update
README.mdandCHANGELOG.md(English) together with the ChineseREADME.zh-CN.mdandCHANGELOG.zh-CN.md. - Update the English wiki pages along with the Chinese ones.
-
make screenshots(andmake panel-imagesif the panel changed), then check the images indocs/anddocs/en/: the English ones should have no Chinese in them. - Delete
build/AllInOneIME.app:rm -rf build/AllInOneIME.app. -
make dmg, then a release with the changelog in Chinese and English and, for each change that shows, its screenshot (docs/in the Chinese half,docs/en/in the English half), linked at the commit so they never change.