From a29d1635e9badab12d0c1be8cbcc5216052d31f3 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 27 Apr 2022 00:10:47 +0800 Subject: [PATCH] mgrLM // Complete Swiftification. --- .../Modules/LangModelRelated/mgrLangModel.h | 52 ----- .../Modules/LangModelRelated/mgrLangModel.mm | 188 ------------------ .../LangModelRelated/mgrLangModel.swift | 154 +++++++++++++- .../LangModelRelated/mgrLangModel_Privates.h | 39 ---- 4 files changed, 153 insertions(+), 280 deletions(-) diff --git a/Source/Modules/LangModelRelated/mgrLangModel.h b/Source/Modules/LangModelRelated/mgrLangModel.h index f76fcbec..8b137891 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel.h +++ b/Source/Modules/LangModelRelated/mgrLangModel.h @@ -1,53 +1 @@ -// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License). -// All possible vChewing-specific modifications are of: -// (c) 2021 and onwards The vChewing Project (MIT-NTL License). -/* -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: -1. The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -2. No trademark license is granted to use the trade names, trademarks, service -marks, or product names of Contributor, except as required to fulfill notice -requirements above. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#import "KeyHandler.h" -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface mgrLangModel : NSObject - -+ (void)loadDataModel:(InputMode)mode; -+ (void)loadUserPhrases; -+ (void)loadUserAssociatedPhrases; -+ (void)loadUserPhraseReplacement; - -+ (BOOL)checkIfUserPhraseExist:(NSString *)userPhrase - inputMode:(InputMode)mode - key:(NSString *)key NS_SWIFT_NAME(checkIfUserPhraseExist(userPhrase:mode:key:)); -+ (void)setPhraseReplacementEnabled:(BOOL)phraseReplacementEnabled; -+ (void)setCNSEnabled:(BOOL)cnsEnabled; -+ (void)setSymbolEnabled:(BOOL)symbolEnabled; - -@end - -/// The following methods are merely for testing. -@interface mgrLangModel () -+ (void)loadDataModels; -@end - -NS_ASSUME_NONNULL_END diff --git a/Source/Modules/LangModelRelated/mgrLangModel.mm b/Source/Modules/LangModelRelated/mgrLangModel.mm index 7c3fae20..8b137891 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel.mm +++ b/Source/Modules/LangModelRelated/mgrLangModel.mm @@ -1,189 +1 @@ -// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License). -// All possible vChewing-specific modifications are of: -// (c) 2021 and onwards The vChewing Project (MIT-NTL License). -/* -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: -1. The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -2. No trademark license is granted to use the trade names, trademarks, service -marks, or product names of Contributor, except as required to fulfill notice -requirements above. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#import "mgrLangModel.h" -#import "LMConsolidator.h" -#import "mgrLangModel_Privates.h" -#import "vChewing-Swift.h" - -static const int kUserOverrideModelCapacity = 500; -static const double kObservedOverrideHalflife = 5400.0; - -static vChewing::LMInstantiator gLangModelCHT; -static vChewing::LMInstantiator gLangModelCHS; -static vChewing::UserOverrideModel gUserOverrideModelCHT(kUserOverrideModelCapacity, kObservedOverrideHalflife); -static vChewing::UserOverrideModel gUserOverrideModelCHS(kUserOverrideModelCapacity, kObservedOverrideHalflife); - -@implementation mgrLangModel - -// 這個函數無法遷移至 Swift -static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing::LMInstantiator &lm) -{ - NSString *dataPath = [mgrLangModel getBundleDataPath:filenameWithoutExtension]; - lm.loadLanguageModel([dataPath UTF8String]); -} - -// 這個函數無法遷移至 Swift -+ (void)loadDataModels -{ - if (!gLangModelCHT.isDataModelLoaded()) - LTLoadLanguageModelFile(@"data-cht", gLangModelCHT); - if (!gLangModelCHT.isMiscDataLoaded()) - gLangModelCHT.loadMiscData([[self getBundleDataPath:@"data-zhuyinwen"] UTF8String]); - if (!gLangModelCHT.isSymbolDataLoaded()) - gLangModelCHT.loadSymbolData([[self getBundleDataPath:@"data-symbols"] UTF8String]); - if (!gLangModelCHT.isCNSDataLoaded()) - gLangModelCHT.loadCNSData([[self getBundleDataPath:@"char-kanji-cns"] UTF8String]); - - // ----------------- - if (!gLangModelCHS.isDataModelLoaded()) - LTLoadLanguageModelFile(@"data-chs", gLangModelCHS); - if (!gLangModelCHS.isMiscDataLoaded()) - gLangModelCHS.loadMiscData([[self getBundleDataPath:@"data-zhuyinwen"] UTF8String]); - if (!gLangModelCHS.isSymbolDataLoaded()) - gLangModelCHS.loadSymbolData([[self getBundleDataPath:@"data-symbols"] UTF8String]); - if (!gLangModelCHS.isCNSDataLoaded()) - gLangModelCHS.loadCNSData([[self getBundleDataPath:@"char-kanji-cns"] UTF8String]); -} - -// 這個函數無法遷移至 Swift -+ (void)loadDataModel:(InputMode)mode -{ - if ([mode isEqualToString:imeModeCHT]) - { - if (!gLangModelCHT.isDataModelLoaded()) - LTLoadLanguageModelFile(@"data-cht", gLangModelCHT); - if (!gLangModelCHT.isMiscDataLoaded()) - gLangModelCHT.loadMiscData([[self getBundleDataPath:@"data-zhuyinwen"] UTF8String]); - if (!gLangModelCHT.isSymbolDataLoaded()) - gLangModelCHT.loadSymbolData([[self getBundleDataPath:@"data-symbols"] UTF8String]); - if (!gLangModelCHT.isCNSDataLoaded()) - gLangModelCHT.loadCNSData([[self getBundleDataPath:@"char-kanji-cns"] UTF8String]); - } - - if ([mode isEqualToString:imeModeCHS]) - { - if (!gLangModelCHS.isDataModelLoaded()) - LTLoadLanguageModelFile(@"data-chs", gLangModelCHS); - if (!gLangModelCHS.isMiscDataLoaded()) - gLangModelCHS.loadMiscData([[self getBundleDataPath:@"data-zhuyinwen"] UTF8String]); - if (!gLangModelCHS.isSymbolDataLoaded()) - gLangModelCHS.loadSymbolData([[self getBundleDataPath:@"data-symbols"] UTF8String]); - if (!gLangModelCHS.isCNSDataLoaded()) - gLangModelCHS.loadCNSData([[self getBundleDataPath:@"char-kanji-cns"] UTF8String]); - } -} - -// 這個函數無法遷移至 Swift -+ (void)loadUserPhrases -{ - gLangModelCHT.loadUserPhrases([[self userPhrasesDataPath:imeModeCHT] UTF8String], - [[self excludedPhrasesDataPath:imeModeCHT] UTF8String]); - gLangModelCHS.loadUserPhrases([[self userPhrasesDataPath:imeModeCHS] UTF8String], - [[self excludedPhrasesDataPath:imeModeCHS] UTF8String]); - gLangModelCHT.loadUserSymbolData([[self userSymbolDataPath:imeModeCHT] UTF8String]); - gLangModelCHS.loadUserSymbolData([[self userSymbolDataPath:imeModeCHS] UTF8String]); -} - -// 這個函數無法遷移至 Swift -+ (void)loadUserAssociatedPhrases -{ - gLangModelCHT.loadUserAssociatedPhrases([[self userAssociatedPhrasesDataPath:imeModeCHT] UTF8String]); - gLangModelCHS.loadUserAssociatedPhrases([[self userAssociatedPhrasesDataPath:imeModeCHS] UTF8String]); -} - -// 這個函數無法遷移至 Swift -+ (void)loadUserPhraseReplacement -{ - gLangModelCHT.loadPhraseReplacementMap([[self phraseReplacementDataPath:imeModeCHT] UTF8String]); - gLangModelCHS.loadPhraseReplacementMap([[self phraseReplacementDataPath:imeModeCHS] UTF8String]); -} - -// 這個函數無法遷移至 Swift -+ (BOOL)checkIfUserPhraseExist:(NSString *)userPhrase - inputMode:(InputMode)mode - key:(NSString *)key NS_SWIFT_NAME(checkIfUserPhraseExist(userPhrase:mode:key:)) -{ - string unigramKey = string(key.UTF8String); - vector unigrams = [mode isEqualToString:imeModeCHT] ? gLangModelCHT.unigramsForKey(unigramKey) - : gLangModelCHS.unigramsForKey(unigramKey); - string userPhraseString = string(userPhrase.UTF8String); - for (auto unigram : unigrams) - { - if (unigram.keyValue.value == userPhraseString) - { - return YES; - } - } - return NO; -} - -// 這個函數無法遷移至 Swift -+ (vChewing::LMInstantiator *)lmCHT -{ - return &gLangModelCHT; -} - -// 這個函數無法遷移至 Swift -+ (vChewing::LMInstantiator *)lmCHS -{ - return &gLangModelCHS; -} - -// 這個函數無法遷移至 Swift -+ (vChewing::UserOverrideModel *)userOverrideModelCHT -{ - return &gUserOverrideModelCHT; -} - -// 這個函數無法遷移至 Swift -+ (vChewing::UserOverrideModel *)userOverrideModelCHS -{ - return &gUserOverrideModelCHS; -} - -// 這個函數無法遷移至 Swift -+ (void)setPhraseReplacementEnabled:(BOOL)phraseReplacementEnabled -{ - gLangModelCHT.setPhraseReplacementEnabled(phraseReplacementEnabled); - gLangModelCHS.setPhraseReplacementEnabled(phraseReplacementEnabled); -} - -// 這個函數無法遷移至 Swift -+ (void)setCNSEnabled:(BOOL)cnsEnabled -{ - gLangModelCHT.setCNSEnabled(cnsEnabled); - gLangModelCHS.setCNSEnabled(cnsEnabled); -} - -// 這個函數無法遷移至 Swift -+ (void)setSymbolEnabled:(BOOL)symbolEnabled -{ - gLangModelCHT.setSymbolEnabled(symbolEnabled); - gLangModelCHS.setSymbolEnabled(symbolEnabled); -} - -@end diff --git a/Source/Modules/LangModelRelated/mgrLangModel.swift b/Source/Modules/LangModelRelated/mgrLangModel.swift index 1c916902..c768853a 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel.swift +++ b/Source/Modules/LangModelRelated/mgrLangModel.swift @@ -25,8 +25,160 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import Cocoa +import Megrez + +/// 我們不能讓 mgrLangModel 這個靜態管理器來承載下面這些副本變數。 +/// 所以,這些副本變數只能放在 mgrLangModel 的外部。 +/// 同時,這些變數不對外開放任意存取權限。 +/// 我們只在 mgrLangModel 內部寫幾個回傳函數、供其餘控制模組來讀取。 + +private let kUserOverrideModelCapacity: Int = 500 +private let kObservedOverrideHalflife: Double = 5400.0 + +private var gLangModelCHS = vChewing.LMInstantiator() +private var gLangModelCHT = vChewing.LMInstantiator() +private var gUserOverrideModelCHS = vChewing.LMUserOverride( + capacity: kUserOverrideModelCapacity, decayExponent: kObservedOverrideHalflife +) +private var gUserOverrideModelCHT = vChewing.LMUserOverride( + capacity: kUserOverrideModelCapacity, decayExponent: kObservedOverrideHalflife +) + +@objc class mgrLangModel: NSObject { + /// 寫幾個回傳函數、供其餘控制模組來讀取那些被設為 fileprivate 的器外變數。 + public static var lmCHS: vChewing.LMInstantiator { gLangModelCHS } + public static var lmCHT: vChewing.LMInstantiator { gLangModelCHT } + public static var uomCHS: vChewing.LMUserOverride { gUserOverrideModelCHS } + public static var uomCHT: vChewing.LMUserOverride { gUserOverrideModelCHT } + + // MARK: - Functions reacting directly with language models. + + static func loadCoreLanguageModelFile(filenameSansExtension: String, langModel lm: inout vChewing.LMInstantiator) { + let dataPath: String = mgrLangModel.getBundleDataPath(filenameSansExtension) + lm.loadLanguageModel(path: dataPath) + } + + public static func loadDataModels() { + if !gLangModelCHT.isDataModelLoaded() { + loadCoreLanguageModelFile(filenameSansExtension: "data-cht", langModel: &gLangModelCHT) + } + if !gLangModelCHT.isMiscDataLoaded() { + gLangModelCHT.loadMiscData(path: getBundleDataPath("data-zhuyinwen")) + } + if !gLangModelCHT.isSymbolDataLoaded() { + gLangModelCHT.loadSymbolData(path: getBundleDataPath("data-symbols")) + } + if !gLangModelCHT.isCNSDataLoaded() { + gLangModelCHT.loadCNSData(path: getBundleDataPath("char-kanji-cns")) + } + + // ----------------- + if !gLangModelCHS.isDataModelLoaded() { + loadCoreLanguageModelFile(filenameSansExtension: "data-chs", langModel: &gLangModelCHS) + } + if !gLangModelCHS.isMiscDataLoaded() { + gLangModelCHS.loadMiscData(path: getBundleDataPath("data-zhuyinwen")) + } + if !gLangModelCHS.isSymbolDataLoaded() { + gLangModelCHS.loadSymbolData(path: getBundleDataPath("data-symbols")) + } + if !gLangModelCHS.isCNSDataLoaded() { + gLangModelCHS.loadCNSData(path: getBundleDataPath("char-kanji-cns")) + } + } + + public static func loadDataModel(_ mode: InputMode) { + if mode == InputMode.imeModeCHS { + if !gLangModelCHS.isDataModelLoaded() { + loadCoreLanguageModelFile(filenameSansExtension: "data-chs", langModel: &gLangModelCHS) + } + if !gLangModelCHS.isMiscDataLoaded() { + gLangModelCHS.loadMiscData(path: getBundleDataPath("data-zhuyinwen")) + } + if !gLangModelCHS.isSymbolDataLoaded() { + gLangModelCHS.loadSymbolData(path: getBundleDataPath("data-symbols")) + } + if !gLangModelCHS.isCNSDataLoaded() { + gLangModelCHS.loadCNSData(path: getBundleDataPath("char-kanji-cns")) + } + } else if mode == InputMode.imeModeCHT { + if !gLangModelCHT.isDataModelLoaded() { + loadCoreLanguageModelFile(filenameSansExtension: "data-cht", langModel: &gLangModelCHT) + } + if !gLangModelCHT.isMiscDataLoaded() { + gLangModelCHT.loadMiscData(path: getBundleDataPath("data-zhuyinwen")) + } + if !gLangModelCHT.isSymbolDataLoaded() { + gLangModelCHT.loadSymbolData(path: getBundleDataPath("data-symbols")) + } + if !gLangModelCHT.isCNSDataLoaded() { + gLangModelCHT.loadCNSData(path: getBundleDataPath("char-kanji-cns")) + } + } + } + + public static func loadUserPhrases() { + gLangModelCHT.loadUserPhrases( + path: userSymbolDataPath(InputMode.imeModeCHT), + filterPath: excludedPhrasesDataPath(InputMode.imeModeCHT) + ) + gLangModelCHS.loadUserPhrases( + path: userPhrasesDataPath(InputMode.imeModeCHS), + filterPath: excludedPhrasesDataPath(InputMode.imeModeCHS) + ) + gLangModelCHT.loadUserSymbolData(path: userSymbolDataPath(InputMode.imeModeCHT)) + gLangModelCHS.loadUserSymbolData(path: userSymbolDataPath(InputMode.imeModeCHS)) + } + + public static func loadUserAssociatedPhrases() { + gLangModelCHT.loadUserAssociatedPhrases( + path: mgrLangModel.userAssociatedPhrasesDataPath(InputMode.imeModeCHT) + ) + gLangModelCHT.loadUserAssociatedPhrases( + path: mgrLangModel.userAssociatedPhrasesDataPath(InputMode.imeModeCHS) + ) + } + + public static func loadUserPhraseReplacement() { + gLangModelCHT.loadPhraseReplacementMap( + path: mgrLangModel.phraseReplacementDataPath(InputMode.imeModeCHT) + ) + gLangModelCHT.loadPhraseReplacementMap( + path: mgrLangModel.phraseReplacementDataPath(InputMode.imeModeCHS) + ) + } + + public static func checkIfUserPhraseExist( + userPhrase: String, + mode: InputMode, + key unigramKey: String + ) -> Bool { + let unigrams: [Megrez.Unigram] = + (mode == InputMode.imeModeCHT) + ? gLangModelCHT.unigramsFor(key: unigramKey) : gLangModelCHS.unigramsFor(key: unigramKey) + for unigram in unigrams { + if unigram.keyValue.value == userPhrase { + return true + } + } + return false + } + + public static func setPhraseReplacementEnabled(_ state: Bool) { + gLangModelCHT.isPhraseReplacementEnabled = state + gLangModelCHS.isPhraseReplacementEnabled = state + } + + public static func setCNSEnabled(_ state: Bool) { + gLangModelCHT.isCNSEnabled = state + gLangModelCHS.isCNSEnabled = state + } + + public static func setSymbolEnabled(_ state: Bool) { + gLangModelCHT.isSymbolEnabled = state + gLangModelCHS.isSymbolEnabled = state + } -@objc extension mgrLangModel { // MARK: - 獲取當前輸入法封包內的原廠核心語彙檔案所在路徑 static func getBundleDataPath(_ filenameSansExt: String) -> String { diff --git a/Source/Modules/LangModelRelated/mgrLangModel_Privates.h b/Source/Modules/LangModelRelated/mgrLangModel_Privates.h index cc42ca2a..8b137891 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel_Privates.h +++ b/Source/Modules/LangModelRelated/mgrLangModel_Privates.h @@ -1,40 +1 @@ -// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License). -// All possible vChewing-specific modifications are of: -// (c) 2021 and onwards The vChewing Project (MIT-NTL License). -/* -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: -1. The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -2. No trademark license is granted to use the trade names, trademarks, service -marks, or product names of Contributor, except as required to fulfill notice -requirements above. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#import "LMInstantiator.h" -#import "UserOverrideModel.h" -#import "mgrLangModel.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface mgrLangModel () -@property(class, readonly, nonatomic) vChewing::LMInstantiator *lmCHT; -@property(class, readonly, nonatomic) vChewing::LMInstantiator *lmCHS; -@property(class, readonly, nonatomic) vChewing::UserOverrideModel *userOverrideModelCHS; -@property(class, readonly, nonatomic) vChewing::UserOverrideModel *userOverrideModelCHT; -@end - -NS_ASSUME_NONNULL_END