Repo // Refactor APIs related to LM access and configs.

This commit is contained in:
ShikiSuen 2024-01-27 22:25:49 +08:00
parent 23ef3124d4
commit 586822c981
14 changed files with 159 additions and 186 deletions

View File

@ -30,26 +30,36 @@ public extension vChewingLM {
/// LMI LMI
///
class LMInstantiator: LangModelProtocol {
public struct Config {
public var isCassetteEnabled = false
public var isPhraseReplacementEnabled = false
public var isCNSEnabled = false
public var isSymbolEnabled = false
public var isSCPCEnabled = false
public var deltaOfCalendarYears: Int = -2000
}
// SQLite
static var ptrSQL: OpaquePointer?
// SQLite
public private(set) static var isSQLDBConnected: Bool = false
//
public let isCHS: Bool
//
public var isCassetteEnabled = false
public var isPhraseReplacementEnabled = false
public var isCNSEnabled = false
public var isSymbolEnabled = false
public var isSCPCEnabled = false
public var isCHS = false
public var deltaOfCalendarYears: Int = -2000
public var config = Config()
// package
public init(isCHS: Bool = false) {
self.isCHS = isCHS
}
public func setOptions(handler: (inout Config) -> Void) {
handler(&config)
}
@discardableResult public static func connectSQLDB(dbPath: String, dropPreviousConnection: Bool = true) -> Bool {
if dropPreviousConnection { disconnectSQLDB() }
vCLog("Establishing SQLite connection to: \(dbPath)")
@ -315,10 +325,10 @@ public extension vChewingLM {
///
var rawAllUnigrams: [Megrez.Unigram] = []
if isCassetteEnabled { rawAllUnigrams += Self.lmCassette.unigramsFor(key: keyChain) }
if config.isCassetteEnabled { rawAllUnigrams += Self.lmCassette.unigramsFor(key: keyChain) }
// 使
if isSCPCEnabled {
if config.isSCPCEnabled {
rawAllUnigrams += lmPlainBopomofo.valuesFor(key: keyChain).map { Megrez.Unigram(value: $0, score: 0) }
}
@ -327,18 +337,18 @@ public extension vChewingLM {
// rawUserUnigrams
rawAllUnigrams += lmUserPhrases.unigramsFor(key: keyChain).reversed()
if !isCassetteEnabled || isCassetteEnabled && keyChain.map(\.description)[0] == "_" {
if !config.isCassetteEnabled || config.isCassetteEnabled && keyChain.map(\.description)[0] == "_" {
// LMMisc LMCore score (-10.0, 0.0)
rawAllUnigrams += factoryUnigramsFor(key: keyChain, column: .theDataCHEW)
rawAllUnigrams += factoryCoreUnigramsFor(key: keyChain)
if isCNSEnabled {
if config.isCNSEnabled {
rawAllUnigrams += factoryUnigramsFor(key: keyChain, column: .theDataCNS)
}
}
if isSymbolEnabled {
if config.isSymbolEnabled {
rawAllUnigrams += lmUserSymbols.unigramsFor(key: keyChain)
if !isCassetteEnabled {
if !config.isCassetteEnabled {
rawAllUnigrams += factoryUnigramsFor(key: keyChain, column: .theDataSYMB)
}
}
@ -363,7 +373,7 @@ public extension vChewingLM {
}
//
if isPhraseReplacementEnabled {
if config.isPhraseReplacementEnabled {
for i in 0 ..< rawAllUnigrams.count {
let newValue = lmReplacements.valuesFor(key: rawAllUnigrams[i].value)
guard !newValue.isEmpty else { continue }

View File

@ -19,14 +19,14 @@ extension vChewingLM.LMInstantiator {
func processDateWithDayDelta(_ delta: Int) {
tokens = ["MACRO@DATE_DAYDELTA:\(delta)"]
if deltaOfCalendarYears != 0 { tokens.append("MACRO@DATE_DAYDELTA:\(delta)_YEARDELTA:\(deltaOfCalendarYears)") }
if config.deltaOfCalendarYears != 0 { tokens.append("MACRO@DATE_DAYDELTA:\(delta)_YEARDELTA:\(config.deltaOfCalendarYears)") }
tokens.append("MACRO@DATE_DAYDELTA:\(delta)_SHORTENED")
tokens.append("MACRO@DATE_DAYDELTA:\(delta)_LUNA")
}
func processYearWithYearDelta(_ delta: Int) {
tokens = ["MACRO@YEAR_YEARDELTA:\(delta)"]
if deltaOfCalendarYears != 0 { tokens.append("MACRO@YEAR_YEARDELTA:\(delta + deltaOfCalendarYears)") }
if config.deltaOfCalendarYears != 0 { tokens.append("MACRO@YEAR_YEARDELTA:\(delta + config.deltaOfCalendarYears)") }
tokens.append("MACRO@YEAR_GANZHI_YEARDELTA:\(delta)")
tokens.append("MACRO@YEAR_ZODIAC_YEARDELTA:\(delta)")
}

View File

@ -59,8 +59,10 @@ final class InputTokenTests: XCTestCase {
func testGeneratedResultsFromLMInstantiator() throws {
let instance = vChewingLM.LMInstantiator(isCHS: true)
XCTAssertTrue(vChewingLM.LMInstantiator.connectToTestSQLDB())
instance.isCNSEnabled = false
instance.isSymbolEnabled = false
instance.setOptions { config in
config.isCNSEnabled = false
config.isSymbolEnabled = false
}
instance.insertTemporaryData(
keyArray: ["ㄐㄧㄣ", "ㄊㄧㄢ", "ㄖˋ", "ㄑㄧˊ"],
unigram: .init(value: "MACRO@DATE_YEARDELTA:-1945", score: -97.5),

View File

@ -24,14 +24,18 @@ final class LMInstantiatorSQLTests: XCTestCase {
func testSQL() throws {
let instance = vChewingLM.LMInstantiator(isCHS: true)
XCTAssertTrue(vChewingLM.LMInstantiator.connectToTestSQLDB())
instance.isCNSEnabled = false
instance.isSymbolEnabled = false
instance.setOptions { config in
config.isCNSEnabled = false
config.isSymbolEnabled = false
}
XCTAssertEqual(instance.unigramsFor(keyArray: strBloatingKey).description, "[(吹牛逼,-7.375), (吹牛屄,-7.399)]")
XCTAssertEqual(instance.unigramsFor(keyArray: strHaninSymbolMenuKey)[1].description, "(,-9.9)")
XCTAssertEqual(instance.unigramsFor(keyArray: strRefutationKey).description, "[(㨃,-9.544)]")
XCTAssertEqual(instance.unigramsFor(keyArray: strBoobsKey).description, "[(ㄋㄟㄋㄟ,-1.0)]")
instance.isCNSEnabled = true
instance.isSymbolEnabled = true
instance.setOptions { config in
config.isCNSEnabled = true
config.isSymbolEnabled = true
}
XCTAssertEqual(instance.unigramsFor(keyArray: strBloatingKey).last?.description, "(🌳🆕🐝,-13.0)")
XCTAssertEqual(instance.unigramsFor(keyArray: strHaninSymbolMenuKey)[1].description, "(,-9.9)")
XCTAssertEqual(instance.unigramsFor(keyArray: strRefutationKey).count, 10)

View File

@ -12,50 +12,42 @@ import NotifierUI
import Shared
import SwiftExtension
// MARK: - Input Mode Extension for Language Models
public extension Shared.InputMode {
private static let lmCHS = vChewingLM.LMInstantiator(isCHS: true)
private static let lmCHT = vChewingLM.LMInstantiator(isCHS: false)
private static let uomCHS = vChewingLM.LMUserOverride(dataURL: LMMgr.userOverrideModelDataURL(.imeModeCHS))
private static let uomCHT = vChewingLM.LMUserOverride(dataURL: LMMgr.userOverrideModelDataURL(.imeModeCHT))
var langModel: vChewingLM.LMInstantiator {
switch self {
case .imeModeCHS: return Self.lmCHS
case .imeModeCHT: return Self.lmCHT
case .imeModeNULL: return .init()
}
}
var uom: vChewingLM.LMUserOverride {
switch self {
case .imeModeCHS: return Self.uomCHS
case .imeModeCHT: return Self.uomCHT
case .imeModeNULL: return .init(dataURL: LMMgr.userOverrideModelDataURL(IMEApp.currentInputMode))
}
}
}
// MARK: - Language Model Manager.
public class LMMgr {
public static var shared = LMMgr()
public private(set) static var lmCHS = vChewingLM.LMInstantiator(isCHS: true)
public private(set) static var lmCHT = vChewingLM.LMInstantiator(isCHS: false)
public private(set) static var uomCHS = vChewingLM.LMUserOverride(
dataURL: LMMgr.userOverrideModelDataURL(.imeModeCHS))
public private(set) static var uomCHT = vChewingLM.LMUserOverride(
dataURL: LMMgr.userOverrideModelDataURL(.imeModeCHT))
public static var currentLM: vChewingLM.LMInstantiator {
Self.getLM(mode: IMEApp.currentInputMode)
}
public static var currentUOM: vChewingLM.LMUserOverride {
Self.getUOM(mode: IMEApp.currentInputMode)
}
public static func getLM(mode: Shared.InputMode) -> vChewingLM.LMInstantiator {
switch mode {
case .imeModeCHS:
return Self.lmCHS
case .imeModeCHT:
return Self.lmCHT
case .imeModeNULL:
return .init()
}
}
public static func getUOM(mode: Shared.InputMode) -> vChewingLM.LMUserOverride {
switch mode {
case .imeModeCHS:
return Self.uomCHS
case .imeModeCHT:
return Self.uomCHT
case .imeModeNULL:
return .init(dataURL: Self.userOverrideModelDataURL(IMEApp.currentInputMode))
}
}
// MARK: - Functions reacting directly with language models.
public static func initUserLangModels() {
Self.chkUserLMFilesExist(.imeModeCHT)
Self.chkUserLMFilesExist(.imeModeCHS)
Shared.InputMode.validCases.forEach { mode in
Self.chkUserLMFilesExist(mode)
}
// LMMgr loadUserPhrases dataFolderPath
//
//
@ -84,83 +76,69 @@ public class LMMgr {
public static func loadUserPhrasesData(type: vChewingLM.ReplacableUserDataType? = nil) {
guard let type = type else {
Self.lmCHT.loadUserPhrasesData(
path: userDictDataURL(mode: .imeModeCHT, type: .thePhrases).path,
filterPath: userDictDataURL(mode: .imeModeCHT, type: .theFilter).path
)
Self.lmCHS.loadUserPhrasesData(
path: userDictDataURL(mode: .imeModeCHS, type: .thePhrases).path,
filterPath: userDictDataURL(mode: .imeModeCHS, type: .theFilter).path
)
Self.lmCHT.loadUserSymbolData(path: userDictDataURL(mode: .imeModeCHT, type: .theSymbols).path)
Self.lmCHS.loadUserSymbolData(path: userDictDataURL(mode: .imeModeCHS, type: .theSymbols).path)
Shared.InputMode.validCases.forEach { mode in
mode.langModel.loadUserPhrasesData(
path: userDictDataURL(mode: mode, type: .thePhrases).path,
filterPath: userDictDataURL(mode: mode, type: .theFilter).path
)
mode.langModel.loadUserSymbolData(path: userDictDataURL(mode: mode, type: .theSymbols).path)
mode.uom.loadData(fromURL: userOverrideModelDataURL(mode))
}
if PrefMgr.shared.associatedPhrasesEnabled { Self.loadUserAssociatesData() }
if PrefMgr.shared.phraseReplacementEnabled { Self.loadUserPhraseReplacement() }
if PrefMgr.shared.useSCPCTypingMode { Self.loadSCPCSequencesData() }
Self.uomCHT.loadData(fromURL: userOverrideModelDataURL(.imeModeCHT))
Self.uomCHS.loadData(fromURL: userOverrideModelDataURL(.imeModeCHS))
CandidateNode.load(url: Self.userSymbolMenuDataURL())
return
}
switch type {
case .thePhrases:
Self.lmCHT.loadUserPhrasesData(
path: userDictDataURL(mode: .imeModeCHT, type: .thePhrases).path,
filterPath: nil
)
Self.lmCHS.loadUserPhrasesData(
path: userDictDataURL(mode: .imeModeCHS, type: .thePhrases).path,
filterPath: nil
)
case .theFilter:
DispatchQueue.main.async {
Self.reloadUserFilterDirectly(mode: IMEApp.currentInputMode)
Shared.InputMode.validCases.forEach { mode in
switch type {
case .thePhrases:
mode.langModel.loadUserPhrasesData(
path: userDictDataURL(mode: mode, type: .thePhrases).path,
filterPath: nil
)
case .theFilter:
DispatchQueue.main.async {
Self.reloadUserFilterDirectly(mode: mode)
}
case .theReplacements:
if PrefMgr.shared.phraseReplacementEnabled { Self.loadUserPhraseReplacement() }
case .theAssociates:
if PrefMgr.shared.associatedPhrasesEnabled { Self.loadUserAssociatesData() }
case .theSymbols:
mode.langModel.loadUserSymbolData(
path: Self.userDictDataURL(mode: mode, type: .theSymbols).path
)
}
DispatchQueue.main.async {
Self.reloadUserFilterDirectly(mode: IMEApp.currentInputMode.reversed)
}
case .theReplacements:
if PrefMgr.shared.phraseReplacementEnabled { Self.loadUserPhraseReplacement() }
case .theAssociates:
if PrefMgr.shared.associatedPhrasesEnabled { Self.loadUserAssociatesData() }
case .theSymbols:
Self.lmCHT.loadUserSymbolData(
path: Self.userDictDataURL(mode: .imeModeCHT, type: .theSymbols).path
)
Self.lmCHS.loadUserSymbolData(
path: Self.userDictDataURL(mode: .imeModeCHS, type: .theSymbols).path
)
}
}
public static func loadUserAssociatesData() {
Self.lmCHT.loadUserAssociatesData(
path: Self.userDictDataURL(mode: .imeModeCHT, type: .theAssociates).path
)
Self.lmCHS.loadUserAssociatesData(
path: Self.userDictDataURL(mode: .imeModeCHS, type: .theAssociates).path
)
Shared.InputMode.validCases.forEach { mode in
mode.langModel.loadUserAssociatesData(
path: Self.userDictDataURL(mode: mode, type: .theAssociates).path
)
}
}
public static func loadUserPhraseReplacement() {
Self.lmCHT.loadReplacementsData(
path: Self.userDictDataURL(mode: .imeModeCHT, type: .theReplacements).path
)
Self.lmCHS.loadReplacementsData(
path: Self.userDictDataURL(mode: .imeModeCHS, type: .theReplacements).path
)
Shared.InputMode.validCases.forEach { mode in
mode.langModel.loadReplacementsData(
path: Self.userDictDataURL(mode: mode, type: .theReplacements).path
)
}
}
public static func loadSCPCSequencesData() {
Self.lmCHT.loadSCPCSequencesData()
Self.lmCHS.loadSCPCSequencesData()
Shared.InputMode.validCases.forEach { mode in
mode.langModel.loadSCPCSequencesData()
}
}
public static func reloadUserFilterDirectly(mode: Shared.InputMode) {
Self.getLM(mode: mode).reloadUserFilterDirectly(path: userDictDataURL(mode: mode, type: .theFilter).path)
mode.langModel.reloadUserFilterDirectly(path: userDictDataURL(mode: mode, type: .theFilter).path)
}
public static func checkIfPhrasePairExists(
@ -169,7 +147,7 @@ public class LMMgr {
keyArray: [String],
factoryDictionaryOnly: Bool = false
) -> Bool {
Self.getLM(mode: mode).hasKeyValuePairFor(
mode.langModel.hasKeyValuePairFor(
keyArray: keyArray, value: userPhrase, factoryDictionaryOnly: factoryDictionaryOnly
)
}
@ -179,7 +157,7 @@ public class LMMgr {
mode: Shared.InputMode,
keyArray: [String]
) -> Bool {
Self.getLM(mode: mode).isPairFiltered(pair: .init(keyArray: keyArray, value: userPhrase))
mode.langModel.isPairFiltered(pair: .init(keyArray: keyArray, value: userPhrase))
}
public static func countPhrasePairs(
@ -187,39 +165,22 @@ public class LMMgr {
mode: Shared.InputMode,
factoryDictionaryOnly: Bool = false
) -> Int {
Self.getLM(mode: mode).countKeyValuePairs(
mode.langModel.countKeyValuePairs(
keyArray: keyArray, factoryDictionaryOnly: factoryDictionaryOnly
)
}
public static func setPhraseReplacementEnabled(_ state: Bool) {
Self.lmCHT.isPhraseReplacementEnabled = state
Self.lmCHS.isPhraseReplacementEnabled = state
}
public static func setCNSEnabled(_ state: Bool) {
Self.lmCHT.isCNSEnabled = state
Self.lmCHS.isCNSEnabled = state
}
public static func setSymbolEnabled(_ state: Bool) {
Self.lmCHT.isSymbolEnabled = state
Self.lmCHS.isSymbolEnabled = state
}
public static func setSCPCEnabled(_ state: Bool) {
Self.lmCHT.isSCPCEnabled = state
Self.lmCHS.isSCPCEnabled = state
}
public static func setCassetteEnabled(_ state: Bool) {
Self.lmCHT.isCassetteEnabled = state
Self.lmCHS.isCassetteEnabled = state
}
public static func setDeltaOfCalendarYears(_ delta: Int) {
Self.lmCHT.deltaOfCalendarYears = delta
Self.lmCHS.deltaOfCalendarYears = delta
public static func syncLMPrefs() {
Shared.InputMode.validCases.forEach { mode in
mode.langModel.setOptions { config in
config.isPhraseReplacementEnabled = PrefMgr.shared.phraseReplacementEnabled
config.isCNSEnabled = PrefMgr.shared.cns11643Enabled
config.isSymbolEnabled = PrefMgr.shared.symbolInputEnabled
config.isSCPCEnabled = PrefMgr.shared.useSCPCTypingMode
config.isCassetteEnabled = PrefMgr.shared.cassetteEnabled
config.deltaOfCalendarYears = PrefMgr.shared.deltaOfCalendarYears
}
}
}
// MARK: UOM
@ -227,26 +188,23 @@ public class LMMgr {
public static func saveUserOverrideModelData() {
let globalQueue = DispatchQueue(label: "vChewingLM_UOM", qos: .unspecified, attributes: .concurrent)
let group = DispatchGroup()
group.enter()
globalQueue.async {
Self.uomCHT.saveData(toURL: userOverrideModelDataURL(.imeModeCHT))
group.leave()
}
group.enter()
globalQueue.async {
Self.uomCHS.saveData(toURL: userOverrideModelDataURL(.imeModeCHS))
group.leave()
Shared.InputMode.validCases.forEach { mode in
group.enter()
globalQueue.async {
mode.uom.saveData(toURL: userOverrideModelDataURL(mode))
group.leave()
}
}
_ = group.wait(timeout: .distantFuture)
group.notify(queue: DispatchQueue.main) {}
}
public static func bleachSpecifiedSuggestions(targets: [String], mode: Shared.InputMode) {
Self.getUOM(mode: mode).bleachSpecifiedSuggestions(targets: targets, saveCallback: { Self.getUOM(mode: mode).saveData() })
mode.uom.bleachSpecifiedSuggestions(targets: targets, saveCallback: { mode.uom.saveData() })
}
public static func removeUnigramsFromUserOverrideModel(_ mode: Shared.InputMode) {
Self.getUOM(mode: mode).bleachUnigrams(saveCallback: { Self.getUOM(mode: mode).saveData() })
mode.uom.bleachUnigrams(saveCallback: { mode.uom.saveData() })
}
public static func relocateWreckedUOMData() {
@ -268,6 +226,6 @@ public class LMMgr {
}
public static func clearUserOverrideModelData(_ mode: Shared.InputMode = .imeModeNULL) {
Self.getUOM(mode: mode).clearData(withURL: userOverrideModelDataURL(mode))
mode.uom.clearData(withURL: userOverrideModelDataURL(mode))
}
}

View File

@ -62,7 +62,7 @@ public extension LMMgr {
}
public var isAlreadyFiltered: Bool {
LMMgr.getLM(mode: inputMode).isPairFiltered(pair: .init(keyArray: keyArray, value: value))
inputMode.langModel.isPairFiltered(pair: .init(keyArray: keyArray, value: value))
}
public func write(toFilter: Bool) -> Bool {

View File

@ -230,21 +230,21 @@ import SwiftExtension
@AppProperty(key: UserDef.kCNS11643Enabled.rawValue, defaultValue: false)
public dynamic var cns11643Enabled: Bool {
didSet {
LMMgr.setCNSEnabled(cns11643Enabled) //
LMMgr.syncLMPrefs()
}
}
@AppProperty(key: UserDef.kSymbolInputEnabled.rawValue, defaultValue: true)
public dynamic var symbolInputEnabled: Bool {
didSet {
LMMgr.setSymbolEnabled(symbolInputEnabled) //
LMMgr.syncLMPrefs()
}
}
@AppProperty(key: UserDef.kCassetteEnabled.rawValue, defaultValue: false)
public dynamic var cassetteEnabled: Bool {
didSet {
LMMgr.setCassetteEnabled(cassetteEnabled) //
LMMgr.syncLMPrefs()
}
}
@ -325,7 +325,7 @@ import SwiftExtension
willSet {
if newValue {
LMMgr.loadSCPCSequencesData()
LMMgr.setSCPCEnabled(true)
LMMgr.syncLMPrefs()
}
}
}
@ -333,7 +333,7 @@ import SwiftExtension
@AppProperty(key: UserDef.kPhraseReplacementEnabled.rawValue, defaultValue: false)
public dynamic var phraseReplacementEnabled: Bool {
willSet {
LMMgr.setPhraseReplacementEnabled(newValue)
LMMgr.syncLMPrefs()
if newValue {
LMMgr.loadUserPhraseReplacement()
}

View File

@ -177,8 +177,8 @@ public class SessionCtl: IMKInputController {
resetInputHandler()
// ----------------------------
///
inputHandler?.currentLM = LMMgr.currentLM //
inputHandler?.currentUOM = LMMgr.currentUOM
inputHandler?.currentLM = inputMode.langModel //
inputHandler?.currentUOM = inputMode.uom
///
inputHandler?.ensureKeyboardParser()
///
@ -215,7 +215,7 @@ public class SessionCtl: IMKInputController {
Self.current?.hidePalettes()
Self.current = self
self.inputHandler = InputHandler(
lm: LMMgr.currentLM, uom: LMMgr.currentUOM, pref: PrefMgr.shared
lm: self.inputMode.langModel, uom: self.inputMode.uom, pref: PrefMgr.shared
)
self.inputHandler?.delegate = self
self.syncBaseLMPrefs()
@ -314,7 +314,7 @@ public extension SessionCtl {
// setValue() IMK activateServer() setValue()
self.inputHandler = InputHandler(
lm: LMMgr.currentLM, uom: LMMgr.currentUOM, pref: PrefMgr.shared
lm: self.inputMode.langModel, uom: self.inputMode.uom, pref: PrefMgr.shared
)
self.inputHandler?.delegate = self
self.syncBaseLMPrefs()
@ -408,12 +408,7 @@ public extension SessionCtl {
///
func syncBaseLMPrefs() {
LMMgr.currentLM.isPhraseReplacementEnabled = PrefMgr.shared.phraseReplacementEnabled
LMMgr.currentLM.isCNSEnabled = PrefMgr.shared.cns11643Enabled
LMMgr.currentLM.isSymbolEnabled = PrefMgr.shared.symbolInputEnabled
LMMgr.currentLM.isSCPCEnabled = PrefMgr.shared.useSCPCTypingMode
LMMgr.currentLM.isCassetteEnabled = PrefMgr.shared.cassetteEnabled
LMMgr.currentLM.deltaOfCalendarYears = PrefMgr.shared.deltaOfCalendarYears
LMMgr.syncLMPrefs()
}
}

View File

@ -63,7 +63,7 @@ extension SessionCtl: InputHandlerDelegate {
//
//
LMMgr.currentLM.insertTemporaryData(
inputMode.langModel.insertTemporaryData(
keyArray: userPhrase.keyArray,
unigram: .init(value: userPhrase.value, score: userPhrase.weight ?? 0),
isFiltering: addToFilter
@ -119,7 +119,7 @@ extension SessionCtl: CtlCandidateDelegate {
if state.type == .ofAssociates {
return shortened ? "" : NSLocalizedString("Hold ⇧ to choose associates.", comment: "")
} else if state.type == .ofInputting, state.isCandidateContainer {
let useShift = LMMgr.currentLM.areCassetteCandidateKeysShiftHeld
let useShift = inputMode.langModel.areCassetteCandidateKeysShiftHeld
let theEmoji = useShift ? "⬆️" : "⚡️"
return shortened ? theEmoji : "\(theEmoji) " + NSLocalizedString("Quick Candidates", comment: "")
} else if PrefMgr.shared.cassetteEnabled {
@ -141,14 +141,14 @@ extension SessionCtl: CtlCandidateDelegate {
if value.isEmpty { return blankResult } // 西
if value.contains("_") { return blankResult }
// LMInstantiator
return LMMgr.currentLM.cassetteReverseLookup(for: value)
return inputMode.langModel.cassetteReverseLookup(for: value)
}
public var selectionKeys: String {
// `%quick` 使 1234567890
cassetteQuick: if state.type == .ofInputting, state.isCandidateContainer {
guard PrefMgr.shared.cassetteEnabled else { break cassetteQuick }
guard let cinCandidateKey = LMMgr.currentLM.cassetteSelectionKey,
guard let cinCandidateKey = inputMode.langModel.cassetteSelectionKey,
CandidateKey.validate(keys: cinCandidateKey) == nil
else {
return "1234567890"
@ -267,7 +267,7 @@ extension SessionCtl: CtlCandidateDelegate {
//
//
LMMgr.currentLM.insertTemporaryData(
inputMode.langModel.insertTemporaryData(
keyArray: userPhrase.keyArray,
unigram: .init(value: userPhrase.value, score: userPhrase.weight ?? 0),
isFiltering: action == .toFilter

View File

@ -140,7 +140,7 @@ public struct VwrSettingsPaneCassette: View {
} else {
LMMgr.loadCassetteData()
}
LMMgr.setCassetteEnabled(cassetteEnabled)
LMMgr.syncLMPrefs()
}
)
}

View File

@ -177,13 +177,13 @@ public struct VwrSettingsPaneDictionary: View {
Toggle(
LocalizedStringKey("Enable CNS11643 Support (2023-11-06)"),
isOn: $cns11643Enabled.onChange {
LMMgr.setCNSEnabled(cns11643Enabled)
LMMgr.syncLMPrefs()
}
)
Toggle(
LocalizedStringKey("Enable symbol input support (incl. certain emoji symbols)"),
isOn: $symbolInputEnabled.onChange {
LMMgr.setSymbolEnabled(symbolInputEnabled)
LMMgr.syncLMPrefs()
}
)
VStack(alignment: .leading) {
@ -200,7 +200,7 @@ public struct VwrSettingsPaneDictionary: View {
Toggle(
LocalizedStringKey("Enable phrase replacement table"),
isOn: $phraseReplacementEnabled.onChange {
LMMgr.setPhraseReplacementEnabled(phraseReplacementEnabled)
LMMgr.syncLMPrefs()
if phraseReplacementEnabled {
LMMgr.loadUserPhraseReplacement()
}

View File

@ -226,6 +226,10 @@ public enum Shared {
}
}
public static var validCases: [InputMode] {
[.imeModeCHS, .imeModeCHT]
}
public var localizedDescription: String { NSLocalizedString(description, comment: "") }
public var description: String {
switch self {

View File

@ -272,7 +272,7 @@ public extension SessionCtl {
? "NotificationSwitchON".localized
: "NotificationSwitchOFF".localized)
)
if !LMMgr.currentLM.isCassetteDataLoaded {
if !inputMode.langModel.isCassetteDataLoaded {
LMMgr.loadCassetteData()
}
}

View File

@ -233,11 +233,11 @@ class CtlPrefWindow: NSWindowController, NSWindowDelegate {
// CNS
//
@IBAction func toggleCNSSupport(_: Any) {
LMMgr.setCNSEnabled(PrefMgr.shared.cns11643Enabled)
LMMgr.syncLMPrefs()
}
@IBAction func toggleSymbolInputEnabled(_: Any) {
LMMgr.setSymbolEnabled(PrefMgr.shared.symbolInputEnabled)
LMMgr.syncLMPrefs()
}
@IBAction func toggleTrad2KangXiAction(_: Any) {