Files
OSGKeyboard/OSGKeyboardShared/Typing/PersonalDictionaryRimeSync.swift
T
Rocky 717902716a feat(typing): wire PersonalDictionary into Chinese Pinyin via Rime sidecar
Redeploy an osg_personal import table on dictionary add/delete/sync so
Chinese, English typing, and ASR share one curated lexicon (next keyboard open).
2026-08-05 22:12:30 +08:00

73 lines
2.5 KiB
Swift

// PersonalDictionaryRimeSync.swift
// OSGKeyboard · Shared
//
// Debounces PersonalDictionary mutations on the iOS host and redeploys
// Rime so the osg_personal sidecar matches. The keyboard extension only
// picks this up the next time it opens a typing session.
import Foundation
@MainActor
public enum PersonalDictionaryRimeSync {
private static var pending: Task<Void, Never>?
private static let debounceNanoseconds: UInt64 = 750_000_000
private static let retryNanoseconds: UInt64 = 5_000_000_000
/// Call after App Group personal-dictionary writes (add / delete / sync).
/// Safe from any executor — work is hoppped onto the main actor.
public nonisolated static func scheduleAfterDictionaryChange() {
Task { @MainActor in
scheduleOnMainActor()
}
}
public static func deployNow() async {
pending?.cancel()
pending = nil
await deploy(retryOnMemoryPressure: false)
}
private static func scheduleOnMainActor() {
pending?.cancel()
pending = Task {
try? await Task.sleep(nanoseconds: debounceNanoseconds)
guard !Task.isCancelled else { return }
await deploy(retryOnMemoryPressure: true)
}
}
private static func deploy(retryOnMemoryPressure: Bool) async {
guard HostMemoryBudget.gate("rime.personalDictionary") else {
OSGDiag.log("rime.personalDictionary deferred by memory gate", category: "boot")
if retryOnMemoryPressure {
pending?.cancel()
pending = Task {
try? await Task.sleep(nanoseconds: retryNanoseconds)
guard !Task.isCancelled else { return }
await deploy(retryOnMemoryPressure: true)
}
}
return
}
FlowSessionBridge.setHostHeavy(true)
defer { FlowSessionBridge.setHostHeavy(false) }
let typingConfig = TypingInputConfiguration.shared.snapshot
let dictionary = AppGroupStore().personalDictionary
do {
try await RimeResourceInstaller.shared.installIfNeeded(
configuration: typingConfig,
personalDictionary: dictionary,
force: false
)
OSGDiag.log("rime.personalDictionary deploy done", category: "boot")
} catch {
OSGDiag.log(
"rime.personalDictionary deploy failed error=\(error.localizedDescription)",
category: "boot"
)
}
}
}