From e44843e6038880872f54cbe442e600bffaf239d4 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 18 Feb 2024 15:51:24 +0800 Subject: [PATCH] LMAssembly // Pack LMUserOverride inside LMInstantiator, etc. --- Packages/vChewing_LangModelAssembly/README.md | 10 +- .../LangModelAssembly/InputToken.swift | 28 ++-- .../LangModelAssembly/LMConsolidator.swift | 2 +- .../LangModelAssembly/LMInstantiator.swift | 11 +- .../LMInstantiator_CassetteExtension.swift | 2 +- .../LMInstantiator_DateTimeExtension.swift | 2 +- .../LMInstantiator_NumPadExtension.swift | 2 +- .../LMInstantiator_SQLExtension.swift | 44 ++--- .../LMInstantiator_UOMRepresentable.swift | 60 +++++++ .../SubLMs/lmAssociates.swift | 4 +- .../LangModelAssembly/SubLMs/lmCassette.swift | 8 +- .../LangModelAssembly/SubLMs/lmCoreEX.swift | 4 +- .../SubLMs/lmPlainBopomofo.swift | 11 +- .../SubLMs/lmReplacements.swift | 4 +- .../SubLMs/lmRevLookup.swift | 76 --------- .../SubLMs/lmUserOverride.swift | 156 ++++++++++-------- .../LangModelAssembly/TestCoreLMSQLData.swift | 8 +- ....swift => vChewingLMAssembly_Common.swift} | 2 +- .../InputTokenTests.swift | 6 +- .../LMCassetteTests.swift | 4 +- .../LMCoreEXTests.swift | 2 +- .../LMInstantiatorSQLTests.swift | 12 +- .../LMUserOverrideTests.swift | 8 +- .../NumPadDataTests.swift | 2 +- .../InputHandler/InputHandler_Core.swift | 19 +-- .../LangModelManager/LMMgr_Core.swift | 40 ++--- .../LMMgr_PhraseEditorDelegate.swift | 12 +- .../LMMgr_UserPhraseStructure.swift | 4 +- .../LangModelManager/LMMgr_Utilities.swift | 8 +- .../RevLookupUI/CtlRevLookupWindow.swift | 2 +- .../SessionController/SessionCtl_Core.swift | 9 +- .../VwrSettingsPaneCocoaPhrases.swift | 8 +- .../MainAssemblyTests_Core.swift | 17 +- .../PhraseEditorUI/PhraseEditorDelegate.swift | 6 +- .../PhraseEditorUI/PhraseEditorUI.swift | 24 +-- 35 files changed, 302 insertions(+), 315 deletions(-) create mode 100644 Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_UOMRepresentable.swift delete mode 100644 Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmRevLookup.swift rename Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/{vChewingLM.swift => vChewingLMAssembly_Common.swift} (99%) diff --git a/Packages/vChewing_LangModelAssembly/README.md b/Packages/vChewing_LangModelAssembly/README.md index e679db0f..8bef1099 100644 --- a/Packages/vChewing_LangModelAssembly/README.md +++ b/Packages/vChewing_LangModelAssembly/README.md @@ -1,17 +1,17 @@ # LangModelAssembly -威注音輸入法的語言模組總成套裝。 +威注音輸入法的語言模組總成套裝,以 LMAssembly 命名空間承載下述唯二對外物件: -- vChewingLM:總命名空間,也承載一些在套裝內共用的工具函式。 - LMConsolidator:自動格式整理模組。 -- LMInstantiator:語言模組副本化模組。另有其日期時間擴充模組可用(對 CIN 磁帶模式無效)。 +- LMInstantiator:語言模組副本化模組,亦集成一些自身功能擴展。 + +LMAssembly 總命名空間也承載一些在套裝內共用的工具函式。 以下是子模組: -- lmCassette:專門用來處理 CIN 磁帶檔案的模組,命名為「遠野」引擎。 - LMAssociates:關聯詞語模組。 +- lmCassette:專門用來處理 CIN 磁帶檔案的模組,命名為「遠野」引擎。 - LMCoreEX:可以直接讀取 TXT 格式的帶有權重資料的語彙檔案的模組。 -- LMCoreJSON:專門用來讀取原廠 JSON 檔案的模組。 - lmPlainBopomofo:專門用來讀取使用者自訂ㄅ半候選字順序覆蓋定義檔案(plist)的模組。 - lmReplacements:專門用來讀取使用者語彙置換模式的辭典資料的模組。 - lmUserOverride:半衰記憶模組。 diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/InputToken.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/InputToken.swift index 3838395f..95b447cc 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/InputToken.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/InputToken.swift @@ -11,29 +11,31 @@ import Foundation /// 工作原理:先用 InputToken.parse 分析原始字串,給出準確的 Token。 /// 然後再讓這個 Token 用 .translated() 自我表述出轉換結果。 -public enum InputToken { - case timeZone(shortened: Bool) - case timeNow(shortened: Bool) - case date(dayDelta: Int = 0, yearDelta: Int = 0, shortened: Bool = true, luna: Bool = false) - case week(dayDelta: Int = 0, shortened: Bool = true) - case year(yearDelta: Int = 0) - case yearGanzhi(yearDelta: Int = 0) - case yearZodiac(yearDelta: Int = 0) +extension LMAssembly { + enum InputToken { + case timeZone(shortened: Bool) + case timeNow(shortened: Bool) + case date(dayDelta: Int = 0, yearDelta: Int = 0, shortened: Bool = true, luna: Bool = false) + case week(dayDelta: Int = 0, shortened: Bool = true) + case year(yearDelta: Int = 0) + case yearGanzhi(yearDelta: Int = 0) + case yearZodiac(yearDelta: Int = 0) + } } // MARK: - 正式對外投入使用的 API。 public extension String { func parseAsInputToken(isCHS: Bool) -> [String] { - InputToken.parse(from: self).map { $0.translated(isCHS: isCHS) }.flatMap { $0 }.deduplicated + LMAssembly.InputToken.parse(from: self).map { $0.translated(isCHS: isCHS) }.flatMap { $0 }.deduplicated } } // MARK: - Parser parsing raw token value to construct token. -public extension InputToken { - static func parse(from rawToken: String) -> [InputToken] { - var result: [InputToken] = [] +extension LMAssembly.InputToken { + static func parse(from rawToken: String) -> [LMAssembly.InputToken] { + var result: [LMAssembly.InputToken] = [] guard rawToken.prefix(6) == "MACRO@" else { return result } var mapParams: [String: Int] = [:] let tokenComponents = rawToken.dropFirst(6).split(separator: "_").map { param in @@ -69,7 +71,7 @@ public extension InputToken { // MARK: - Parser parsing token itself. -public extension InputToken { +extension LMAssembly.InputToken { func translated(isCHS: Bool) -> [String] { let locale = Locale(identifier: isCHS ? "zh-Hans" : "zh-Hant-TW") let formatter = DateFormatter() diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMConsolidator.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMConsolidator.swift index a6982cba..3219b333 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMConsolidator.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMConsolidator.swift @@ -10,7 +10,7 @@ import Foundation import LineReader import Shared -public extension vChewingLM { +public extension LMAssembly { enum LMConsolidator { public static let kPragmaHeader = "# 𝙵𝙾𝚁𝙼𝙰𝚃 𝚘𝚛𝚐.𝚊𝚝𝚎𝚕𝚒𝚎𝚛𝙸𝚗𝚖𝚞.𝚟𝚌𝚑𝚎𝚠𝚒𝚗𝚐.𝚞𝚜𝚎𝚛𝙻𝚊𝚗𝚐𝚞𝚊𝚐𝚎𝙼𝚘𝚍𝚎𝚕𝙳𝚊𝚝𝚊.𝚏𝚘𝚛𝚖𝚊𝚝𝚝𝚎𝚍" diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift index deb70455..f612ad11 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift @@ -11,7 +11,7 @@ import Megrez import Shared import SQLite3 -public extension vChewingLM { +public extension LMAssembly { /// 語言模組副本化模組(LMInstantiator,下稱「LMI」)自身為符合天權星組字引擎內 /// 的 LangModelProtocol 協定的模組、統籌且整理來自其它子模組的資料(包括使 /// 用者語彙、繪文字模組、語彙濾除表、原廠語言模組等)。 @@ -56,8 +56,12 @@ public extension vChewingLM { public var config = Config() // 這句需要留著,不然無法被 package 外界存取。 - public init(isCHS: Bool = false) { + public init( + isCHS: Bool = false, + uomDataURL: URL? = nil + ) { self.isCHS = isCHS + lmUserOverride = .init(dataURL: uomDataURL) } public func setOptions(handler: (inout Config) -> Void) { @@ -109,6 +113,9 @@ public extension vChewingLM { var lmAssociates = LMAssociates() var lmPlainBopomofo = LMPlainBopomofo() + // 半衰记忆模组 + var lmUserOverride: LMUserOverride + // MARK: - 工具函式 public func resetFactoryJSONModels() {} diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_CassetteExtension.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_CassetteExtension.swift index c5511382..beb09f4b 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_CassetteExtension.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_CassetteExtension.swift @@ -10,7 +10,7 @@ import Foundation import Megrez import Shared -public extension vChewingLM.LMInstantiator { +public extension LMAssembly.LMInstantiator { /// 磁帶模式專用:當前磁帶所規定的花牌鍵。 var cassetteWildcardKey: String { Self.lmCassette.wildcardKey } /// 磁帶模式專用:當前磁帶規定的最大碼長。 diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_DateTimeExtension.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_DateTimeExtension.swift index e0d3e945..d880b010 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_DateTimeExtension.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_DateTimeExtension.swift @@ -11,7 +11,7 @@ import Megrez // MARK: - 日期時間便捷輸入功能 -extension vChewingLM.LMInstantiator { +extension LMAssembly.LMInstantiator { func queryDateTimeUnigrams(with key: String = "") -> [Megrez.Unigram] { guard let tokenTrigger = TokenTrigger(rawValue: key) else { return [] } var results = [Megrez.Unigram]() diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_NumPadExtension.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_NumPadExtension.swift index 7fba313f..75316aa7 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_NumPadExtension.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_NumPadExtension.swift @@ -9,7 +9,7 @@ import Foundation import Megrez -public extension vChewingLM.LMInstantiator { +public extension LMAssembly.LMInstantiator { func supplyNumPadUnigrams(key: String) -> [Megrez.Unigram] { guard let status = config.numPadFWHWStatus else { return [] } let initials = "_NumPad_" diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift index 41eb2e33..267d7f59 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift @@ -31,30 +31,32 @@ import SQLite3 ) WITHOUT ROWID; */ -enum CoreColumn: Int32 { - case theDataCHS = 1 // 簡體中文 - case theDataCHT = 2 // 繁體中文 - case theDataCNS = 3 // 全字庫 - case theDataMISC = 4 // 待辦 - case theDataSYMB = 5 // 符號圖 - case theDataCHEW = 6 // 注音文 +extension LMAssembly.LMInstantiator { + enum CoreColumn: Int32 { + case theDataCHS = 1 // 簡體中文 + case theDataCHT = 2 // 繁體中文 + case theDataCNS = 3 // 全字庫 + case theDataMISC = 4 // 待辦 + case theDataSYMB = 5 // 符號圖 + case theDataCHEW = 6 // 注音文 - var name: String { String(describing: self) } + var name: String { String(describing: self) } - var id: Int32 { rawValue } + var id: Int32 { rawValue } - var defaultScore: Double { - switch self { - case .theDataCHEW: return -1 - case .theDataCNS: return -11 - case .theDataSYMB: return -13 - case .theDataMISC: return -10 - default: return -9.9 + var defaultScore: Double { + switch self { + case .theDataCHEW: return -1 + case .theDataCNS: return -11 + case .theDataSYMB: return -13 + case .theDataMISC: return -10 + default: return -9.9 + } } } } -extension vChewingLM.LMInstantiator { +extension LMAssembly.LMInstantiator { fileprivate static func querySQL(strStmt sqlQuery: String, coreColumn column: CoreColumn, handler: (String) -> Void) { guard Self.ptrSQL != nil else { return } performStatementSansResult { ptrStatement in @@ -134,7 +136,9 @@ extension vChewingLM.LMInstantiator { /// - parameters: /// - key: 讀音索引鍵。 /// - column: 資料欄位。 - func factoryUnigramsFor(key: String, column: CoreColumn) -> [Megrez.Unigram] { + func factoryUnigramsFor( + key: String, column: LMAssembly.LMInstantiator.CoreColumn + ) -> [Megrez.Unigram] { if key == "_punctuation_list" { return [] } var grams: [Megrez.Unigram] = [] var gramsHW: [Megrez.Unigram] = [] @@ -210,7 +214,7 @@ extension vChewingLM.LMInstantiator { } } -private extension vChewingLM.LMInstantiator { +private extension LMAssembly.LMInstantiator { /// 內部函式,用以將注音讀音索引鍵進行加密。 /// /// 使用這種加密字串作為索引鍵,可以增加對 json 資料庫的存取速度。 @@ -258,7 +262,7 @@ private extension vChewingLM.LMInstantiator { ] } -public extension vChewingLM.LMInstantiator { +public extension LMAssembly.LMInstantiator { @discardableResult static func connectToTestSQLDB() -> Bool { Self.connectSQLDB(dbPath: #":memory:"#) && sqlTestCoreLMData.runAsSQLExec(dbPointer: &ptrSQL) } diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_UOMRepresentable.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_UOMRepresentable.swift new file mode 100644 index 00000000..087a8abf --- /dev/null +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_UOMRepresentable.swift @@ -0,0 +1,60 @@ +// (c) 2021 and onwards The vChewing Project (MIT-NTL License). +// ==================== +// This code is released under the MIT license (SPDX-License-Identifier: MIT) +// ... with NTL restriction stating that: +// 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 defined in MIT License. + +import Foundation +import Megrez + +public extension LMAssembly.LMInstantiator { + func performUOMObservation( + walkedBefore: [Megrez.Node], + walkedAfter: [Megrez.Node], + cursor: Int, + timestamp: Double, + saveCallback: (() -> Void)? = nil + ) { + lmUserOverride.performObservation( + walkedBefore: walkedBefore, + walkedAfter: walkedAfter, + cursor: cursor, + timestamp: timestamp, + saveCallback: saveCallback + ) + } + + func fetchUOMSuggestion( + currentWalk: [Megrez.Node], + cursor: Int, + timestamp: Double + ) -> LMAssembly.OverrideSuggestion { + lmUserOverride.fetchSuggestion( + currentWalk: currentWalk, + cursor: cursor, + timestamp: timestamp + ) + } + + func loadUOMData(fromURL fileURL: URL? = nil) { + lmUserOverride.loadData(fromURL: fileURL) + } + + func saveUOMData(toURL fileURL: URL? = nil) { + lmUserOverride.saveData(toURL: fileURL) + } + + func clearUOMData(withURL fileURL: URL? = nil) { + lmUserOverride.clearData(withURL: fileURL) + } + + func bleachSpecifiedUOMSuggestions(targets: [String], saveCallback: (() -> Void)? = nil) { + lmUserOverride.bleachSpecifiedSuggestions(targets: targets, saveCallback: saveCallback) + } + + func bleachUOMUnigrams(saveCallback: (() -> Void)? = nil) { + lmUserOverride.bleachUnigrams(saveCallback: saveCallback) + } +} diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmAssociates.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmAssociates.swift index dec8b49a..6a9660ff 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmAssociates.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmAssociates.swift @@ -10,8 +10,8 @@ import Megrez import PinyinPhonaConverter import Shared -public extension vChewingLM { - @frozen struct LMAssociates { +extension LMAssembly { + struct LMAssociates { public private(set) var filePath: String? var rangeMap: [String: [(Range, Int)]] = [:] var strData: String = "" diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCassette.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCassette.swift index 91401609..94f4d42d 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCassette.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCassette.swift @@ -12,9 +12,9 @@ import LineReader import Megrez import Shared -public extension vChewingLM { +extension LMAssembly { /// 磁帶模組,用來方便使用者自行擴充字根輸入法。 - @frozen struct LMCassette { + struct LMCassette { public private(set) var filePath: String? public private(set) var nameShort: String = "" public private(set) var nameENG: String = "" @@ -45,7 +45,7 @@ public extension vChewingLM { } } -public extension vChewingLM.LMCassette { +extension LMAssembly.LMCassette { /// 計算頻率時要用到的東西 - fscale private static let fscale = 2.7 /// 萬用花牌字符,哪怕花牌鍵仍不可用。 @@ -86,7 +86,7 @@ public extension vChewingLM.LMCassette { if FileManager.default.fileExists(atPath: path) { do { guard let fileHandle = FileHandle(forReadingAtPath: path) else { - throw vChewingLM.FileErrors.fileHandleError("") + throw LMAssembly.FileErrors.fileHandleError("") } let lineReader = try LineReader(file: fileHandle) var theMaxKeyLength = 1 diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCoreEX.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCoreEX.swift index b92d2212..03285cf7 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCoreEX.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCoreEX.swift @@ -10,12 +10,12 @@ import Megrez import PinyinPhonaConverter import Shared -public extension vChewingLM { +extension LMAssembly { /// 與之前的 LMCore 不同,LMCoreEX 不在辭典內記錄實體,而是記錄 range 範圍。 /// 需要資料的時候,直接拿 range 去 strData 取資料。 /// 資料記錄原理與上游 C++ 的 ParselessLM 差不多,但用的是 Swift 原生手段。 /// 主要時間消耗仍在 For 迴圈,但這個算法可以顯著減少記憶體佔用。 - @frozen struct LMCoreEX { + struct LMCoreEX { public private(set) var filePath: String? /// 資料庫辭典。索引內容為注音字串,資料內容則為字串首尾範圍、方便自 strData 取資料。 var rangeMap: [String: [Range]] = [:] diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmPlainBopomofo.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmPlainBopomofo.swift index 70325c50..2b44e652 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmPlainBopomofo.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmPlainBopomofo.swift @@ -9,7 +9,7 @@ import Foundation import Shared -public extension vChewingLM { +public extension LMAssembly { @frozen struct LMPlainBopomofo { public private(set) var filePath: String? var dataMap: [String: String] = [:] @@ -29,13 +29,8 @@ public extension vChewingLM { do { let rawData = try Data(contentsOf: URL(fileURLWithPath: path)) - if let rawJSON = try? JSONSerialization.jsonObject(with: rawData) as? [String: String] { - dataMap = rawJSON - } else { - filePath = oldPath - vCLog("↑ Exception happened when reading JSON file at: \(path).") - return false - } + let rawJSON = try JSONDecoder().decode([String: String].self, from: rawData) + dataMap = rawJSON } catch { filePath = oldPath vCLog("\(error)") diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmReplacements.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmReplacements.swift index 06286c40..654d146f 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmReplacements.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmReplacements.swift @@ -8,8 +8,8 @@ import Shared -public extension vChewingLM { - @frozen struct LMReplacements { +extension LMAssembly { + struct LMReplacements { public private(set) var filePath: String? var rangeMap: [String: Range] = [:] var strData: String = "" diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmRevLookup.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmRevLookup.swift deleted file mode 100644 index 36348b52..00000000 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmRevLookup.swift +++ /dev/null @@ -1,76 +0,0 @@ -// (c) 2021 and onwards The vChewing Project (MIT-NTL License). -// ==================== -// This code is released under the MIT license (SPDX-License-Identifier: MIT) -// ... with NTL restriction stating that: -// 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 defined in MIT License. - -import Foundation -import Shared - -public extension vChewingLM { - @frozen struct LMRevLookup { - public private(set) var dataMap: [String: [String]] = [:] - public private(set) var filePath: String = "" - - public init(data dictData: (dict: [String: [String]]?, path: String)) { - guard let theDict = dictData.dict else { - vCLog("↑ Exception happened when reading JSON file at: \(dictData.path).") - return - } - filePath = dictData.path - dataMap = theDict - } - - public init(path: String) { - if path.isEmpty { return } - do { - let rawData = try Data(contentsOf: URL(fileURLWithPath: path)) - if let rawJSON = try? JSONSerialization.jsonObject(with: rawData) as? [String: [String]] { - dataMap = rawJSON - } else { - vCLog("↑ Exception happened when reading JSON file at: \(path).") - return - } - } catch { - vCLog("↑ Exception happened when reading JSON file at: \(path).") - return - } - filePath = path - } - - public func query(with kanji: String) -> [String]? { - guard let resultData = dataMap[kanji] else { return nil } - let resultArray = resultData.compactMap { - let result = restorePhonabetFromASCII($0) - return result.isEmpty ? nil : result - } - return resultArray.isEmpty ? nil : resultArray - } - - /// 內部函式,用以將被加密的注音讀音索引鍵進行解密。 - /// - /// 如果傳入的字串當中包含 ASCII 下畫線符號的話,則表明該字串並非注音讀音字串,會被忽略處理。 - /// - parameters: - /// - incoming: 傳入的已加密注音讀音字串。 - func restorePhonabetFromASCII(_ incoming: String) -> String { - var strOutput = incoming - if !strOutput.contains("_") { - for entry in Self.dicPhonabet4ASCII { - strOutput = strOutput.replacingOccurrences(of: entry.key, with: entry.value) - } - } - return strOutput - } - - // MARK: - Constants - - static let dicPhonabet4ASCII: [String: String] = [ - "b": "ㄅ", "p": "ㄆ", "m": "ㄇ", "f": "ㄈ", "d": "ㄉ", "t": "ㄊ", "n": "ㄋ", "l": "ㄌ", "g": "ㄍ", "k": "ㄎ", "h": "ㄏ", - "j": "ㄐ", "q": "ㄑ", "x": "ㄒ", "Z": "ㄓ", "C": "ㄔ", "S": "ㄕ", "r": "ㄖ", "z": "ㄗ", "c": "ㄘ", "s": "ㄙ", "i": "ㄧ", - "u": "ㄨ", "v": "ㄩ", "a": "ㄚ", "o": "ㄛ", "e": "ㄜ", "E": "ㄝ", "B": "ㄞ", "P": "ㄟ", "M": "ㄠ", "F": "ㄡ", "D": "ㄢ", - "T": "ㄣ", "N": "ㄤ", "L": "ㄥ", "R": "ㄦ", "2": "ˊ", "3": "ˇ", "4": "ˋ", "5": "˙", - ] - } -} diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmUserOverride.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmUserOverride.swift index 951e77c9..58be078d 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmUserOverride.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmUserOverride.swift @@ -11,72 +11,40 @@ import Foundation import Megrez import Shared -public extension vChewingLM { - class LMUserOverride { - // MARK: - Main +// MARK: - Public Types. +public extension LMAssembly { + struct OverrideSuggestion { + public var candidates = [(String, Megrez.Unigram)]() + public var forceHighScoreOverride = false + public var isEmpty: Bool { candidates.isEmpty } + } +} + +// MARK: - LMUserOverride Class Definition. + +extension LMAssembly { + class LMUserOverride { var mutCapacity: Int var mutDecayExponent: Double var mutLRUList: [KeyObservationPair] = [] var mutLRUMap: [String: KeyObservationPair] = [:] let kDecayThreshold: Double = 1.0 / 1_048_576.0 // 衰減二十次之後差不多就失效了。 - var fileSaveLocationURL: URL + var fileSaveLocationURL: URL? public static let kObservedOverrideHalfLife: Double = 3600.0 * 6 // 6 小時半衰一次,能持續不到六天的記憶。 - public init(capacity: Int = 500, decayConstant: Double = LMUserOverride.kObservedOverrideHalfLife, dataURL: URL) { + public init(capacity: Int = 500, decayConstant: Double = LMUserOverride.kObservedOverrideHalfLife, dataURL: URL? = nil) { mutCapacity = max(capacity, 1) // Ensures that this integer value is always > 0. mutDecayExponent = log(0.5) / decayConstant fileSaveLocationURL = dataURL } - - public func performObservation( - walkedBefore: [Megrez.Node], walkedAfter: [Megrez.Node], - cursor: Int, timestamp: Double, saveCallback: @escaping () -> Void - ) { - // 參數合規性檢查。 - guard !walkedAfter.isEmpty, !walkedBefore.isEmpty else { return } - guard walkedBefore.totalKeyCount == walkedAfter.totalKeyCount else { return } - // 先判斷用哪種覆寫方法。 - var actualCursor = 0 - guard let currentNode = walkedAfter.findNode(at: cursor, target: &actualCursor) else { return } - // 當前節點超過三個字的話,就不記憶了。在這種情形下,使用者可以考慮新增自訂語彙。 - guard currentNode.spanLength <= 3 else { return } - // 前一個節點得從前一次爬軌結果當中來找。 - guard actualCursor > 0 else { return } // 該情況應該不會出現。 - let currentNodeIndex = actualCursor - actualCursor -= 1 - var prevNodeIndex = 0 - guard let prevNode = walkedBefore.findNode(at: actualCursor, target: &prevNodeIndex) else { return } - - let forceHighScoreOverride: Bool = currentNode.spanLength > prevNode.spanLength - let breakingUp = currentNode.spanLength == 1 && prevNode.spanLength > 1 - - let targetNodeIndex = breakingUp ? currentNodeIndex : prevNodeIndex - let key: String = vChewingLM.LMUserOverride.formObservationKey( - walkedNodes: walkedAfter, headIndex: targetNodeIndex - ) - guard !key.isEmpty else { return } - doObservation( - key: key, candidate: currentNode.currentUnigram.value, timestamp: timestamp, - forceHighScoreOverride: forceHighScoreOverride, saveCallback: { saveCallback() } - ) - } - - public func fetchSuggestion( - currentWalk: [Megrez.Node], cursor: Int, timestamp: Double - ) -> Suggestion { - var headIndex = 0 - guard let nodeIter = currentWalk.findNode(at: cursor, target: &headIndex) else { return .init() } - let key = vChewingLM.LMUserOverride.formObservationKey(walkedNodes: currentWalk, headIndex: headIndex) - return getSuggestion(key: key, timestamp: timestamp, headReading: nodeIter.joinedKey()) - } } } // MARK: - Private Structures -extension vChewingLM.LMUserOverride { +extension LMAssembly.LMUserOverride { enum OverrideUnit: CodingKey { case count, timestamp, forceHighScoreOverride } enum ObservationUnit: CodingKey { case count, overrides } enum KeyObservationPairUnit: CodingKey { case key, observation } @@ -153,10 +121,52 @@ extension vChewingLM.LMUserOverride { } } -// MARK: - Hash and Dehash the entire UOM data, etc. +// MARK: - Internal Methods in LMAssembly. -public extension vChewingLM.LMUserOverride { - func bleachSpecifiedSuggestions(targets: [String], saveCallback: @escaping () -> Void) { +extension LMAssembly.LMUserOverride { + func performObservation( + walkedBefore: [Megrez.Node], walkedAfter: [Megrez.Node], + cursor: Int, timestamp: Double, saveCallback: (() -> Void)? = nil + ) { + // 參數合規性檢查。 + guard !walkedAfter.isEmpty, !walkedBefore.isEmpty else { return } + guard walkedBefore.totalKeyCount == walkedAfter.totalKeyCount else { return } + // 先判斷用哪種覆寫方法。 + var actualCursor = 0 + guard let currentNode = walkedAfter.findNode(at: cursor, target: &actualCursor) else { return } + // 當前節點超過三個字的話,就不記憶了。在這種情形下,使用者可以考慮新增自訂語彙。 + guard currentNode.spanLength <= 3 else { return } + // 前一個節點得從前一次爬軌結果當中來找。 + guard actualCursor > 0 else { return } // 該情況應該不會出現。 + let currentNodeIndex = actualCursor + actualCursor -= 1 + var prevNodeIndex = 0 + guard let prevNode = walkedBefore.findNode(at: actualCursor, target: &prevNodeIndex) else { return } + + let forceHighScoreOverride: Bool = currentNode.spanLength > prevNode.spanLength + let breakingUp = currentNode.spanLength == 1 && prevNode.spanLength > 1 + + let targetNodeIndex = breakingUp ? currentNodeIndex : prevNodeIndex + let key: String = LMAssembly.LMUserOverride.formObservationKey( + walkedNodes: walkedAfter, headIndex: targetNodeIndex + ) + guard !key.isEmpty else { return } + doObservation( + key: key, candidate: currentNode.currentUnigram.value, timestamp: timestamp, + forceHighScoreOverride: forceHighScoreOverride, saveCallback: saveCallback + ) + } + + func fetchSuggestion( + currentWalk: [Megrez.Node], cursor: Int, timestamp: Double + ) -> LMAssembly.OverrideSuggestion { + var headIndex = 0 + guard let nodeIter = currentWalk.findNode(at: cursor, target: &headIndex) else { return .init() } + let key = LMAssembly.LMUserOverride.formObservationKey(walkedNodes: currentWalk, headIndex: headIndex) + return getSuggestion(key: key, timestamp: timestamp, headReading: nodeIter.joinedKey()) + } + + func bleachSpecifiedSuggestions(targets: [String], saveCallback: (() -> Void)? = nil) { if targets.isEmpty { return } for neta in mutLRUMap { for target in targets { @@ -166,44 +176,50 @@ public extension vChewingLM.LMUserOverride { } } resetMRUList() - saveCallback() + saveCallback?() ?? saveData() } /// 自 LRU 辭典內移除所有的單元圖。 - func bleachUnigrams(saveCallback: @escaping () -> Void) { + func bleachUnigrams(saveCallback: (() -> Void)? = nil) { for key in mutLRUMap.keys { if !key.contains("(),()") { continue } mutLRUMap.removeValue(forKey: key) } resetMRUList() - saveCallback() + saveCallback?() ?? saveData() } - internal func resetMRUList() { + func resetMRUList() { mutLRUList.removeAll() for neta in mutLRUMap.reversed() { mutLRUList.append(neta.value) } } - func clearData(withURL fileURL: URL) { + func clearData(withURL fileURL: URL? = nil) { mutLRUMap = .init() mutLRUList = .init() do { let nullData = "{}" + guard let fileURL = fileURL ?? fileSaveLocationURL else { + throw "given fileURL is invalid or nil." + } try nullData.write(to: fileURL, atomically: false, encoding: .utf8) } catch { - vCLog("UOM Error: Unable to clear data. Details: \(error)") + vCLog("UOM Error: Unable to clear the data in the UOM file. Details: \(error)") return } } func saveData(toURL fileURL: URL? = nil) { + guard let fileURL: URL = fileURL ?? fileSaveLocationURL else { + vCLog("UOM saveData() failed. At least the file Save URL is not set for the current UOM.") + return + } // 此處不要使用 JSONSerialization,不然執行緒會炸掉。 let encoder = JSONEncoder() do { guard let jsonData = try? encoder.encode(mutLRUMap) else { return } - let fileURL: URL = fileURL ?? fileSaveLocationURL try jsonData.write(to: fileURL, options: .atomic) } catch { vCLog("UOM Error: Unable to save data, abort saving. Details: \(error)") @@ -211,7 +227,11 @@ public extension vChewingLM.LMUserOverride { } } - func loadData(fromURL fileURL: URL) { + func loadData(fromURL fileURL: URL? = nil) { + guard let fileURL: URL = fileURL ?? fileSaveLocationURL else { + vCLog("UOM loadData() failed. At least the file Load URL is not set for the current UOM.") + return + } // 此處不要使用 JSONSerialization,不然執行緒會炸掉。 let decoder = JSONDecoder() do { @@ -228,20 +248,14 @@ public extension vChewingLM.LMUserOverride { return } } - - struct Suggestion { - public var candidates = [(String, Megrez.Unigram)]() - public var forceHighScoreOverride = false - public var isEmpty: Bool { candidates.isEmpty } - } } -// MARK: - Private Methods +// MARK: - Other Non-Public Internal Methods -extension vChewingLM.LMUserOverride { +extension LMAssembly.LMUserOverride { func doObservation( key: String, candidate: String, timestamp: Double, forceHighScoreOverride: Bool, - saveCallback: @escaping () -> Void + saveCallback: (() -> Void)? ) { guard mutLRUMap[key] != nil else { var observation: Observation = .init() @@ -258,7 +272,7 @@ extension vChewingLM.LMUserOverride { mutLRUList.removeLast() } vCLog("UOM: Observation finished with new observation: \(key)") - saveCallback() + saveCallback?() ?? saveData() return } // 這裡還是不要做 decayCallback 判定「是否不急著更新觀察」了,不然會在嘗試覆寫掉錯誤的記憶時失敗。 @@ -269,11 +283,11 @@ extension vChewingLM.LMUserOverride { mutLRUList.insert(theNeta, at: 0) mutLRUMap[key] = theNeta vCLog("UOM: Observation finished with existing observation: \(key)") - saveCallback() + saveCallback?() ?? saveData() } } - func getSuggestion(key: String, timestamp: Double, headReading: String) -> Suggestion { + func getSuggestion(key: String, timestamp: Double, headReading: String) -> LMAssembly.OverrideSuggestion { guard !key.isEmpty, let kvPair = mutLRUMap[key] else { return .init() } let observation: Observation = kvPair.observation var candidates: [(String, Megrez.Unigram)] = .init() diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/TestCoreLMSQLData.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/TestCoreLMSQLData.swift index 674ca7b2..12f027c4 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/TestCoreLMSQLData.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/TestCoreLMSQLData.swift @@ -1,9 +1,5 @@ -// -// File.swift -// -// -// Created by ShikiSuen on 2023/11/26. -// +// 下述詞頻資料取自 libTaBE 資料庫 (http://sourceforge.net/projects/libtabe/) +// (2002 最終版). 該專案於 1999 年由 Pai-Hsiang Hsiao 發起、以 BSD 授權發行。 import Foundation diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLM.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLMAssembly_Common.swift similarity index 99% rename from Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLM.swift rename to Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLMAssembly_Common.swift index 8770011d..bcce259e 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLM.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLMAssembly_Common.swift @@ -10,7 +10,7 @@ import Foundation import Shared import SQLite3 -public enum vChewingLM { +public enum LMAssembly { enum FileErrors: Error { case fileHandleError(String) } diff --git a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/InputTokenTests.swift b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/InputTokenTests.swift index 588a472d..337867fd 100644 --- a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/InputTokenTests.swift +++ b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/InputTokenTests.swift @@ -57,8 +57,8 @@ final class InputTokenTests: XCTestCase { } func testGeneratedResultsFromLMInstantiator() throws { - let instance = vChewingLM.LMInstantiator(isCHS: true) - XCTAssertTrue(vChewingLM.LMInstantiator.connectToTestSQLDB()) + let instance = LMAssembly.LMInstantiator(isCHS: true) + XCTAssertTrue(LMAssembly.LMInstantiator.connectToTestSQLDB()) instance.setOptions { config in config.isCNSEnabled = false config.isSymbolEnabled = false @@ -70,6 +70,6 @@ final class InputTokenTests: XCTestCase { ) let x = instance.unigramsFor(keyArray: ["ㄐㄧㄣ", "ㄊㄧㄢ", "ㄖˋ", "ㄑㄧˊ"]).description print(x) - vChewingLM.LMInstantiator.disconnectSQLDB() + LMAssembly.LMInstantiator.disconnectSQLDB() } } diff --git a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMCassetteTests.swift b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMCassetteTests.swift index 5ce72080..0b99917f 100644 --- a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMCassetteTests.swift +++ b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMCassetteTests.swift @@ -20,7 +20,7 @@ private let testDataPath: String = packageRootPath + "/Tests/TestCINData/" final class LMCassetteTests: XCTestCase { func testCassetteLoadWubi86() throws { let pathCINFile = testDataPath + "wubi.cin" - var lmCassette = vChewingLM.LMCassette() + var lmCassette = LMAssembly.LMCassette() NSLog("LMCassette: Start loading CIN.") lmCassette.open(pathCINFile) NSLog("LMCassette: Finished loading CIN. Entries: \(lmCassette.count)") @@ -41,7 +41,7 @@ final class LMCassetteTests: XCTestCase { func testCassetteLoadArray30() throws { let pathCINFile = testDataPath + "array30.cin2" - var lmCassette = vChewingLM.LMCassette() + var lmCassette = LMAssembly.LMCassette() NSLog("LMCassette: Start loading CIN.") lmCassette.open(pathCINFile) NSLog("LMCassette: Finished loading CIN. Entries: \(lmCassette.count)") diff --git a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMCoreEXTests.swift b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMCoreEXTests.swift index ac2ea00f..7332e9b6 100644 --- a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMCoreEXTests.swift +++ b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMCoreEXTests.swift @@ -38,7 +38,7 @@ private let sampleData: String = #""" final class LMCoreEXTests: XCTestCase { func testLMCoreEXAsFactoryCoreDict() throws { - var lmTest = vChewingLM.LMCoreEX( + var lmTest = LMAssembly.LMCoreEX( reverse: false, consolidate: false, defaultScore: 0, forceDefaultScore: false ) lmTest.replaceData(textData: sampleData) diff --git a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMInstantiatorSQLTests.swift b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMInstantiatorSQLTests.swift index 3364810e..4c80a570 100644 --- a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMInstantiatorSQLTests.swift +++ b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMInstantiatorSQLTests.swift @@ -22,8 +22,8 @@ private let expectedReverseLookupResults: [String] = [ final class LMInstantiatorSQLTests: XCTestCase { func testSQL() throws { - let instance = vChewingLM.LMInstantiator(isCHS: true) - XCTAssertTrue(vChewingLM.LMInstantiator.connectToTestSQLDB()) + let instance = LMAssembly.LMInstantiator(isCHS: true) + XCTAssertTrue(LMAssembly.LMInstantiator.connectToTestSQLDB()) instance.setOptions { config in config.isCNSEnabled = false config.isSymbolEnabled = false @@ -41,13 +41,13 @@ final class LMInstantiatorSQLTests: XCTestCase { XCTAssertEqual(instance.unigramsFor(keyArray: strRefutationKey).count, 10) XCTAssertEqual(instance.unigramsFor(keyArray: strBoobsKey).last?.description, "(☉☉,-13.0)") // 再測試反查。 - XCTAssertEqual(vChewingLM.LMInstantiator.getFactoryReverseLookupData(with: "和"), expectedReverseLookupResults) - vChewingLM.LMInstantiator.disconnectSQLDB() + XCTAssertEqual(LMAssembly.LMInstantiator.getFactoryReverseLookupData(with: "和"), expectedReverseLookupResults) + LMAssembly.LMInstantiator.disconnectSQLDB() } func testCNSMask() throws { - let instance = vChewingLM.LMInstantiator(isCHS: false) - XCTAssertTrue(vChewingLM.LMInstantiator.connectToTestSQLDB()) + let instance = LMAssembly.LMInstantiator(isCHS: false) + XCTAssertTrue(LMAssembly.LMInstantiator.connectToTestSQLDB()) instance.setOptions { config in config.isCNSEnabled = false config.isSymbolEnabled = false diff --git a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMUserOverrideTests.swift b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMUserOverrideTests.swift index d907d282..12a33bcc 100644 --- a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMUserOverrideTests.swift +++ b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/LMUserOverrideTests.swift @@ -17,12 +17,12 @@ private let halfLife: Double = 5400 private let nullURL = URL(fileURLWithPath: "/dev/null") final class LMUserOverrideTests: XCTestCase { - private func observe(who uom: vChewingLM.LMUserOverride, key: String, candidate: String, timestamp stamp: Double) { + private func observe(who uom: LMAssembly.LMUserOverride, key: String, candidate: String, timestamp stamp: Double) { uom.doObservation(key: key, candidate: candidate, timestamp: stamp, forceHighScoreOverride: false, saveCallback: {}) } func testUOM_1_BasicOps() throws { - let uom = vChewingLM.LMUserOverride(capacity: capacity, decayConstant: Double(halfLife), dataURL: nullURL) + let uom = LMAssembly.LMUserOverride(capacity: capacity, decayConstant: Double(halfLife), dataURL: nullURL) let key = "((ㄕㄣˊ-ㄌㄧˇ-ㄌㄧㄥˊ-ㄏㄨㄚˊ,神里綾華),(ㄉㄜ˙,的),ㄍㄡˇ)" let headReading = "ㄍㄡˇ" let expectedSuggestion = "狗" @@ -45,7 +45,7 @@ final class LMUserOverrideTests: XCTestCase { } func testUOM_2_NewestAgainstRepeatedlyUsed() throws { - let uom = vChewingLM.LMUserOverride(capacity: capacity, decayConstant: Double(halfLife), dataURL: nullURL) + let uom = LMAssembly.LMUserOverride(capacity: capacity, decayConstant: Double(halfLife), dataURL: nullURL) let key = "((ㄕㄣˊ-ㄌㄧˇ-ㄌㄧㄥˊ-ㄏㄨㄚˊ,神里綾華),(ㄉㄜ˙,的),ㄍㄡˇ)" let headReading = "ㄍㄡˇ" let valRepeatedlyUsed = "狗" // 更常用 @@ -74,7 +74,7 @@ final class LMUserOverrideTests: XCTestCase { let b = (key: "((ㄆㄞˋ-ㄇㄥˊ,派蒙),(ㄉㄜ˙,的),ㄐㄧㄤˇ-ㄐㄧㄣ)", value: "伙食費", head: "ㄏㄨㄛˇ-ㄕˊ-ㄈㄟˋ") let c = (key: "((ㄍㄨㄛˊ-ㄅㄥ,國崩),(ㄉㄜ˙,的),ㄇㄠˋ-ㄗ˙)", value: "帽子", head: "ㄇㄠˋ-ㄗ˙") let d = (key: "((ㄌㄟˊ-ㄉㄧㄢˋ-ㄐㄧㄤ-ㄐㄩㄣ,雷電將軍),(ㄉㄜ˙,的),ㄐㄧㄠˇ-ㄔㄡˋ)", value: "腳臭", head: "ㄐㄧㄠˇ-ㄔㄡˋ") - let uom = vChewingLM.LMUserOverride(capacity: 2, decayConstant: Double(halfLife), dataURL: nullURL) + let uom = LMAssembly.LMUserOverride(capacity: 2, decayConstant: Double(halfLife), dataURL: nullURL) observe(who: uom, key: a.key, candidate: a.value, timestamp: nowTimeStamp) observe(who: uom, key: b.key, candidate: b.value, timestamp: nowTimeStamp + halfLife * 1) observe(who: uom, key: c.key, candidate: c.value, timestamp: nowTimeStamp + halfLife * 2) diff --git a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/NumPadDataTests.swift b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/NumPadDataTests.swift index 46e6e698..9a243e47 100644 --- a/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/NumPadDataTests.swift +++ b/Packages/vChewing_LangModelAssembly/Tests/LangModelAssemblyTests/NumPadDataTests.swift @@ -13,7 +13,7 @@ import XCTest final class LMInstantiatorNumericPadTests: XCTestCase { func testSQL() throws { - let instance = vChewingLM.LMInstantiator(isCHS: true) + let instance = LMAssembly.LMInstantiator(isCHS: true) instance.setOptions { config in config.numPadFWHWStatus = nil } diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_Core.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_Core.swift index 0852f1b2..e9f881fc 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_Core.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_Core.swift @@ -19,8 +19,7 @@ import Tekkon // MARK: - InputHandler 自身協定 (Protocol). public protocol InputHandlerProtocol { - var currentLM: vChewingLM.LMInstantiator { get set } - var currentUOM: vChewingLM.LMUserOverride { get set } + var currentLM: LMAssembly.LMInstantiator { get set } var delegate: InputHandlerDelegate? { get set } var keySeparator: String { get } static var keySeparator: String { get } @@ -99,8 +98,7 @@ public class InputHandler: InputHandlerProtocol { var composer: Tekkon.Composer = .init() // 注拼槽 var compositor: Megrez.Compositor // 組字器 - public var currentUOM: vChewingLM.LMUserOverride - public var currentLM: vChewingLM.LMInstantiator { + public var currentLM: LMAssembly.LMInstantiator { didSet { compositor.langModel = .init(withLM: currentLM) clear() @@ -108,10 +106,9 @@ public class InputHandler: InputHandlerProtocol { } /// 初期化。 - public init(lm: vChewingLM.LMInstantiator, uom: vChewingLM.LMUserOverride, pref: PrefMgrProtocol) { + public init(lm: LMAssembly.LMInstantiator, pref: PrefMgrProtocol) { prefs = pref currentLM = lm - currentUOM = uom /// 同步組字器單個詞的幅位長度上限。 Megrez.Compositor.maxSpanLength = prefs.maxCandidateLength /// 組字器初期化。因為是首次初期化變數,所以這裡不能用 ensureCompositor() 代勞。 @@ -369,8 +366,8 @@ public class InputHandler: InputHandlerProtocol { let currentNode = currentWalk.findNode(at: actualNodeCursorPosition, target: &accumulatedCursor) guard let currentNode = currentNode else { return } - uom: if currentNode.currentUnigram.score > -12, prefs.fetchSuggestionsFromUserOverrideModel { - if skipObservation { break uom } + uomProcessing: if currentNode.currentUnigram.score > -12, prefs.fetchSuggestionsFromUserOverrideModel { + if skipObservation { break uomProcessing } vCLog("UOM: Start Observation.") // 這個過程可能會因為使用者半衰記憶模組內部資料錯亂、而導致輸入法在選字時崩潰。 // 於是在這裡引入災後狀況察覺專用變數,且先開啟該開關。順利執行完觀察後會關閉。 @@ -378,9 +375,9 @@ public class InputHandler: InputHandlerProtocol { prefs.failureFlagForUOMObservation = true // 令半衰記憶模組觀測給定的三元圖。 // 這個過程會讓半衰引擎根據當前上下文生成三元圖索引鍵。 - currentUOM.performObservation( + currentLM.performUOMObservation( walkedBefore: previousWalk, walkedAfter: currentWalk, cursor: actualNodeCursorPosition, - timestamp: Date().timeIntervalSince1970, saveCallback: { self.currentUOM.saveData() } + timestamp: Date().timeIntervalSince1970 ) // 如果沒有出現崩框的話,那就將這個開關復位。 prefs.failureFlagForUOMObservation = false @@ -432,7 +429,7 @@ public class InputHandler: InputHandlerProtocol { /// 如果這個開關沒打開的話,直接放棄執行這個函式。 if !prefs.fetchSuggestionsFromUserOverrideModel { return arrResult } /// 獲取來自半衰記憶模組的建議結果 - let suggestion = currentUOM.fetchSuggestion( + let suggestion = currentLM.fetchUOMSuggestion( currentWalk: compositor.walkedNodes, cursor: actualNodeCursorPosition, timestamp: Date().timeIntervalSince1970 ) arrResult.append(contentsOf: suggestion.candidates) diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Core.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Core.swift index d2313f8f..124af4bc 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Core.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Core.swift @@ -15,26 +15,20 @@ 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)) + private static let lmCHS = LMAssembly.LMInstantiator( + isCHS: true, uomDataURL: LMMgr.userOverrideModelDataURL(.imeModeCHS) + ) + private static let lmCHT = LMAssembly.LMInstantiator( + isCHS: false, uomDataURL: LMMgr.userOverrideModelDataURL(.imeModeCHT) + ) - var langModel: vChewingLM.LMInstantiator { + var langModel: LMAssembly.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. @@ -54,14 +48,14 @@ public class LMMgr { Self.loadUserPhrasesData() } - public static var isCoreDBConnected: Bool { vChewingLM.LMInstantiator.isSQLDBConnected } + public static var isCoreDBConnected: Bool { LMAssembly.LMInstantiator.isSQLDBConnected } public static func connectCoreDB(dbPath: String? = nil) { guard let path: String = dbPath ?? Self.getCoreDictionaryDBPath() else { assertionFailure("vChewing factory SQLite data not found.") return } - let result = vChewingLM.LMInstantiator.connectSQLDB(dbPath: path) + let result = LMAssembly.LMInstantiator.connectSQLDB(dbPath: path) assert(result, "vChewing factory SQLite connection failed.") Notifier.notify( message: NSLocalizedString("Core Dict loading complete.", comment: "") @@ -71,10 +65,10 @@ public class LMMgr { /// 載入磁帶資料。 /// - Remark: cassettePath() 會在輸入法停用磁帶時直接返回 public static func loadCassetteData() { - vChewingLM.LMInstantiator.loadCassetteData(path: cassettePath()) + LMAssembly.LMInstantiator.loadCassetteData(path: cassettePath()) } - public static func loadUserPhrasesData(type: vChewingLM.ReplacableUserDataType? = nil) { + public static func loadUserPhrasesData(type: LMAssembly.ReplacableUserDataType? = nil) { guard let type = type else { Shared.InputMode.validCases.forEach { mode in mode.langModel.loadUserPhrasesData( @@ -82,7 +76,7 @@ public class LMMgr { filterPath: userDictDataURL(mode: mode, type: .theFilter).path ) mode.langModel.loadUserSymbolData(path: userDictDataURL(mode: mode, type: .theSymbols).path) - mode.uom.loadData(fromURL: userOverrideModelDataURL(mode)) + mode.langModel.loadUOMData() } if PrefMgr.shared.associatedPhrasesEnabled { Self.loadUserAssociatesData() } @@ -187,12 +181,12 @@ public class LMMgr { // MARK: UOM public static func saveUserOverrideModelData() { - let globalQueue = DispatchQueue(label: "vChewingLM_UOM", qos: .unspecified, attributes: .concurrent) + let globalQueue = DispatchQueue(label: "LMAssembly_UOM", qos: .unspecified, attributes: .concurrent) let group = DispatchGroup() Shared.InputMode.validCases.forEach { mode in group.enter() globalQueue.async { - mode.uom.saveData(toURL: userOverrideModelDataURL(mode)) + mode.langModel.saveUOMData() group.leave() } } @@ -201,11 +195,11 @@ public class LMMgr { } public static func bleachSpecifiedSuggestions(targets: [String], mode: Shared.InputMode) { - mode.uom.bleachSpecifiedSuggestions(targets: targets, saveCallback: { mode.uom.saveData() }) + mode.langModel.bleachSpecifiedUOMSuggestions(targets: targets) } public static func removeUnigramsFromUserOverrideModel(_ mode: Shared.InputMode) { - mode.uom.bleachUnigrams(saveCallback: { mode.uom.saveData() }) + mode.langModel.bleachUOMUnigrams() } public static func relocateWreckedUOMData() { @@ -227,6 +221,6 @@ public class LMMgr { } public static func clearUserOverrideModelData(_ mode: Shared.InputMode = .imeModeNULL) { - mode.uom.clearData(withURL: userOverrideModelDataURL(mode)) + mode.langModel.clearUOMData() } } diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_PhraseEditorDelegate.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_PhraseEditorDelegate.swift index 098dddb3..b24b061d 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_PhraseEditorDelegate.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_PhraseEditorDelegate.swift @@ -17,23 +17,23 @@ import Shared extension LMMgr: PhraseEditorDelegate { public var currentInputMode: Shared.InputMode { IMEApp.currentInputMode } - public func openPhraseFile(mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType, using app: FileOpenMethod) { + public func openPhraseFile(mode: Shared.InputMode, type: LMAssembly.ReplacableUserDataType, using app: FileOpenMethod) { Self.openPhraseFile(fromURL: Self.userDictDataURL(mode: mode, type: type), using: app) } public func consolidate(text strProcessed: inout String, pragma shouldCheckPragma: Bool) { - vChewingLM.LMConsolidator.consolidate(text: &strProcessed, pragma: shouldCheckPragma) + LMAssembly.LMConsolidator.consolidate(text: &strProcessed, pragma: shouldCheckPragma) } public func checkIfPhrasePairExists(userPhrase: String, mode: Shared.InputMode, key unigramKey: String) -> Bool { Self.checkIfPhrasePairExists(userPhrase: userPhrase, mode: mode, keyArray: [unigramKey]) } - public func retrieveData(mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType) -> String { + public func retrieveData(mode: Shared.InputMode, type: LMAssembly.ReplacableUserDataType) -> String { Self.retrieveData(mode: mode, type: type) } - public static func retrieveData(mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType) -> String { + public static func retrieveData(mode: Shared.InputMode, type: LMAssembly.ReplacableUserDataType) -> String { vCLog("Retrieving data. Mode: \(mode.localizedDescription), type: \(type.localizedDescription)") let theURL = Self.userDictDataURL(mode: mode, type: type) do { @@ -44,12 +44,12 @@ extension LMMgr: PhraseEditorDelegate { } } - public func saveData(mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType, data: String) -> String { + public func saveData(mode: Shared.InputMode, type: LMAssembly.ReplacableUserDataType, data: String) -> String { Self.saveData(mode: mode, type: type, data: data) } @discardableResult public static func saveData( - mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType, data: String + mode: Shared.InputMode, type: LMAssembly.ReplacableUserDataType, data: String ) -> String { DispatchQueue.main.async { let theURL = Self.userDictDataURL(mode: mode, type: type) diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_UserPhraseStructure.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_UserPhraseStructure.swift index 3c57dea4..c35dc8e2 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_UserPhraseStructure.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_UserPhraseStructure.swift @@ -88,7 +88,7 @@ public extension LMMgr { /// 有些使用者的語彙檔案已經過於龐大了(超過一千行), /// 每次寫入時都全文整理格式的話,會引發嚴重的效能問題。 /// 所以這裡不再強制要求整理格式。 - let theType: vChewingLM.ReplacableUserDataType = toFilter ? .theFilter : .thePhrases + let theType: LMAssembly.ReplacableUserDataType = toFilter ? .theFilter : .thePhrases let theURL = LMMgr.userDictDataURL(mode: inputMode, type: theType) var fileSize: UInt64? do { @@ -143,7 +143,7 @@ public extension LMMgr { } } let theURL = LMMgr.userDictDataURL(mode: inputMode, type: .theFilter) - if forceConsolidate, !vChewingLM.LMConsolidator.consolidate(path: theURL.path, pragma: false) { return false } + if forceConsolidate, !LMAssembly.LMConsolidator.consolidate(path: theURL.path, pragma: false) { return false } // Get FileSize. var fileSize: UInt64? do { diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Utilities.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Utilities.swift index a1d3426a..c211e44b 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Utilities.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Utilities.swift @@ -61,7 +61,7 @@ public extension LMMgr { /// - mode: 繁簡模式。 /// - type: 辭典資料類型 /// - Returns: 資料路徑(URL)。 - static func userDictDataURL(mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType) -> URL { + static func userDictDataURL(mode: Shared.InputMode, type: LMAssembly.ReplacableUserDataType) -> URL { var fileName: String = { switch type { case .thePhrases: return "userdata" @@ -271,7 +271,7 @@ public extension LMMgr { return true } - static func openUserDictFile(type: vChewingLM.ReplacableUserDataType, dual: Bool = false, alt: Bool) { + static func openUserDictFile(type: LMAssembly.ReplacableUserDataType, dual: Bool = false, alt: Bool) { let app: FileOpenMethod = alt ? .textEdit : .finder openPhraseFile(fromURL: userDictDataURL(mode: IMEApp.currentInputMode, type: type), using: app) guard dual else { return } @@ -324,7 +324,7 @@ public extension LMMgr { /// 前者的話,需要該檔案存在的人自己會建立。 /// 後者的話,你在敲字時自己就會建立。 var failed = false - caseCheck: for type in vChewingLM.ReplacableUserDataType.allCases { + caseCheck: for type in LMAssembly.ReplacableUserDataType.allCases { let templateName = Self.templateName(for: type, mode: mode) if !ensureFileExists(userDictDataURL(mode: mode, type: type), deployTemplate: templateName) { failed = true @@ -334,7 +334,7 @@ public extension LMMgr { return !failed } - internal static func templateName(for type: vChewingLM.ReplacableUserDataType, mode: Shared.InputMode) -> String { + internal static func templateName(for type: LMAssembly.ReplacableUserDataType, mode: Shared.InputMode) -> String { switch type { case .thePhrases: return kTemplateNameUserPhrases case .theFilter: return kTemplateNameUserFilterList diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/RevLookupUI/CtlRevLookupWindow.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/RevLookupUI/CtlRevLookupWindow.swift index 4212b326..8285b828 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/RevLookupUI/CtlRevLookupWindow.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/RevLookupUI/CtlRevLookupWindow.swift @@ -150,7 +150,7 @@ class FrmRevLookupWindow: NSWindow { strBuilder.append("Maximum 15 results returnable.".localized + "\n") break theLoop } - let arrResult = vChewingLM.LMInstantiator.getFactoryReverseLookupData(with: char)?.deduplicated ?? [] + let arrResult = LMAssembly.LMInstantiator.getFactoryReverseLookupData(with: char)?.deduplicated ?? [] if !arrResult.isEmpty { strBuilder.append(char + "\t") strBuilder.append(arrResult.joined(separator: ", ")) diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Core.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Core.swift index afcf8853..49c8f091 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Core.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Core.swift @@ -178,7 +178,6 @@ public class SessionCtl: IMKInputController { // ---------------------------- /// 重設所有語言模組。這裡不需要做按需重設,因為對運算量沒有影響。 inputHandler?.currentLM = inputMode.langModel // 會自動更新組字引擎內的模組。 - inputHandler?.currentUOM = inputMode.uom /// 清空注拼槽+同步最新的注拼槽排列設定。 inputHandler?.ensureKeyboardParser() /// 將輸入法偏好設定同步至語言模組內。 @@ -214,9 +213,7 @@ public class SessionCtl: IMKInputController { // 關掉所有之前的副本的視窗。 Self.current?.hidePalettes() Self.current = self - self.inputHandler = InputHandler( - lm: self.inputMode.langModel, uom: self.inputMode.uom, pref: PrefMgr.shared - ) + self.inputHandler = InputHandler(lm: self.inputMode.langModel, pref: PrefMgr.shared) self.inputHandler?.delegate = self self.syncBaseLMPrefs() // 下述兩行很有必要,否則輸入法會在手動重啟之後無法立刻生效。 @@ -313,9 +310,7 @@ public extension SessionCtl { if self.isActivated { return } // 這裡不需要 setValue(),因為 IMK 會在自動呼叫 activateServer() 之後自動執行 setValue()。 - self.inputHandler = InputHandler( - lm: self.inputMode.langModel, uom: self.inputMode.uom, pref: PrefMgr.shared - ) + self.inputHandler = InputHandler(lm: self.inputMode.langModel, pref: PrefMgr.shared) self.inputHandler?.delegate = self self.syncBaseLMPrefs() diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsCocoa/VwrSettingsPaneCocoaPhrases.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsCocoa/VwrSettingsPaneCocoaPhrases.swift index 3d06e2ff..02b9c47e 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsCocoa/VwrSettingsPaneCocoaPhrases.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsCocoa/VwrSettingsPaneCocoaPhrases.swift @@ -140,7 +140,7 @@ extension SettingsPanesCocoa.Phrases: NSTextViewDelegate, NSTextFieldDelegate { } } - var selUserDataType: vChewingLM.ReplacableUserDataType { + var selUserDataType: LMAssembly.ReplacableUserDataType { switch cmbPEDataTypeMenu.selectedTag() { case 0: return .thePhrases case 1: return .theFilter @@ -238,7 +238,7 @@ extension SettingsPanesCocoa.Phrases: NSTextViewDelegate, NSTextFieldDelegate { // 嚴重警告:NSMenu.items 在 macOS 10.13 為止的系統下是唯讀的!! // 往這個 property 裡面直接寫東西會導致整個視窗叫不出來!!! cmbPEDataTypeMenu.menu?.appendItems { - for (tag, neta) in vChewingLM.ReplacableUserDataType.allCases.enumerated() { + for (tag, neta) in LMAssembly.ReplacableUserDataType.allCases.enumerated() { NSMenu.Item(verbatim: neta.localizedDescription)?.tag(tag) } } @@ -332,7 +332,7 @@ extension SettingsPanesCocoa.Phrases: NSTextViewDelegate, NSTextFieldDelegate { DispatchQueue.main.async { [weak self] in guard let self = self else { return } self.isLoading = true - vChewingLM.LMConsolidator.consolidate(text: &self.tfdPETextEditor.string, pragma: false) + LMAssembly.LMConsolidator.consolidate(text: &self.tfdPETextEditor.string, pragma: false) if self.selUserDataType == .thePhrases { LMMgr.shared.tagOverrides(in: &self.tfdPETextEditor.string, mode: self.selInputMode) } @@ -416,7 +416,7 @@ private enum PETerminology { case weightInputBox = "If not filling the weight, it will be 0.0, the maximum one. An ideal weight situates in [-9.5, 0], making itself can be captured by the walking algorithm. The exception is -114.514, the disciplinary weight. The walking algorithm will ignore it unless it is the unique result." - public static func sampleDictionaryContent(for type: vChewingLM.ReplacableUserDataType) -> String { + public static func sampleDictionaryContent(for type: LMAssembly.ReplacableUserDataType) -> String { var result = "" switch type { case .thePhrases: diff --git a/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Core.swift b/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Core.swift index 5f7c13e3..60845c4c 100644 --- a/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Core.swift +++ b/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Core.swift @@ -34,16 +34,15 @@ func vCTestLog(_ str: String) { /// 該單元測試使用獨立的語彙資料,因此會在選字時的候選字 /// 順序等方面與威注音輸入法實際使用時的體驗有差異。 class MainAssemblyTests: XCTestCase { - let testUOM = LangModelAssembly.vChewingLM.LMUserOverride(dataURL: .init(fileURLWithPath: "/dev/null")) - var testLM = LangModelAssembly.vChewingLM.LMInstantiator.construct { _ in - vChewingLM.LMInstantiator.connectToTestSQLDB() + var testLM = LMAssembly.LMInstantiator.construct { _ in + LMAssembly.LMInstantiator.connectToTestSQLDB() } static let testServer = IMKServer(name: "org.atelierInmu.vChewing.MainAssembly.UnitTests_Connection", bundleIdentifier: "org.atelierInmu.vChewing.MainAssembly.UnitTests") static var _testHandler: InputHandler? var testHandler: InputHandler { - let result = Self._testHandler ?? InputHandler(lm: testLM, uom: testUOM, pref: PrefMgr.shared) + let result = Self._testHandler ?? InputHandler(lm: testLM, pref: PrefMgr.shared) if Self._testHandler == nil { Self._testHandler = result } return result } @@ -65,7 +64,7 @@ class MainAssemblyTests: XCTestCase { let dataTab = NSEvent.KeyEventData(chars: NSEvent.SpecialKey.tab.unicodeScalar.description, keyCode: KeyCode.kTab.rawValue) func clearTestUOM() { - testUOM.clearData(withURL: URL(fileURLWithPath: "/dev/null")) + testLM.clearUOMData() } func typeSentenceOrCandidates(_ sequence: String) { @@ -106,11 +105,11 @@ class MainAssemblyTests: XCTestCase { } } -extension vChewingLM.LMInstantiator { +extension LMAssembly.LMInstantiator { static func construct( - isCHS: Bool = false, completionHandler: @escaping (_ this: vChewingLM.LMInstantiator) -> Void - ) -> vChewingLM.LMInstantiator { - let this = vChewingLM.LMInstantiator(isCHS: isCHS) + isCHS: Bool = false, completionHandler: @escaping (_ this: LMAssembly.LMInstantiator) -> Void + ) -> LMAssembly.LMInstantiator { + let this = LMAssembly.LMInstantiator(isCHS: isCHS) completionHandler(this) return this } diff --git a/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorDelegate.swift b/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorDelegate.swift index 67a578f0..5e744312 100644 --- a/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorDelegate.swift +++ b/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorDelegate.swift @@ -12,11 +12,11 @@ import Shared public protocol PhraseEditorDelegate { var currentInputMode: Shared.InputMode { get } - func retrieveData(mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType) -> String - @discardableResult func saveData(mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType, data: String) + func retrieveData(mode: Shared.InputMode, type: LMAssembly.ReplacableUserDataType) -> String + @discardableResult func saveData(mode: Shared.InputMode, type: LMAssembly.ReplacableUserDataType, data: String) -> String func checkIfPhrasePairExists(userPhrase: String, mode: Shared.InputMode, key unigramKey: String) -> Bool func consolidate(text strProcessed: inout String, pragma shouldCheckPragma: Bool) - func openPhraseFile(mode: Shared.InputMode, type: vChewingLM.ReplacableUserDataType, using: FileOpenMethod) + func openPhraseFile(mode: Shared.InputMode, type: LMAssembly.ReplacableUserDataType, using: FileOpenMethod) func tagOverrides(in strProcessed: inout String, mode: Shared.InputMode) } diff --git a/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorUI.swift b/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorUI.swift index 3a65ee31..81191cf0 100644 --- a/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorUI.swift +++ b/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorUI.swift @@ -37,7 +37,7 @@ public struct VwrPhraseEditorUI: View { @State var txtAddPhraseField3 = "" @State var txtAddPhraseField4 = "" @State public var selInputMode: Shared.InputMode = .imeModeNULL - @State public var selUserDataType: vChewingLM.ReplacableUserDataType = .thePhrases + @State public var selUserDataType: LMAssembly.ReplacableUserDataType = .thePhrases @State private var isLoading = false @State private var textEditorTooltip = PETerms.TooltipTexts.sampleDictionaryContent(for: .thePhrases) public weak var window: NSWindow? @@ -212,16 +212,16 @@ public struct VwrPhraseEditorUI: View { } .labelsHidden() Picker("", selection: $selUserDataType.didChange { dropDownMenuDidChange() }) { - Text(vChewingLM.ReplacableUserDataType.thePhrases.localizedDescription).tag( - vChewingLM.ReplacableUserDataType.thePhrases) - Text(vChewingLM.ReplacableUserDataType.theFilter.localizedDescription).tag( - vChewingLM.ReplacableUserDataType.theFilter) - Text(vChewingLM.ReplacableUserDataType.theReplacements.localizedDescription).tag( - vChewingLM.ReplacableUserDataType.theReplacements) - Text(vChewingLM.ReplacableUserDataType.theAssociates.localizedDescription).tag( - vChewingLM.ReplacableUserDataType.theAssociates) - Text(vChewingLM.ReplacableUserDataType.theSymbols.localizedDescription).tag( - vChewingLM.ReplacableUserDataType.theSymbols) + Text(LMAssembly.ReplacableUserDataType.thePhrases.localizedDescription).tag( + LMAssembly.ReplacableUserDataType.thePhrases) + Text(LMAssembly.ReplacableUserDataType.theFilter.localizedDescription).tag( + LMAssembly.ReplacableUserDataType.theFilter) + Text(LMAssembly.ReplacableUserDataType.theReplacements.localizedDescription).tag( + LMAssembly.ReplacableUserDataType.theReplacements) + Text(LMAssembly.ReplacableUserDataType.theAssociates.localizedDescription).tag( + LMAssembly.ReplacableUserDataType.theAssociates) + Text(LMAssembly.ReplacableUserDataType.theSymbols.localizedDescription).tag( + LMAssembly.ReplacableUserDataType.theSymbols) } .labelsHidden() Button("Reload") { @@ -340,7 +340,7 @@ public enum PETerms { case weightInputBox = "If not filling the weight, it will be 0.0, the maximum one. An ideal weight situates in [-9.5, 0], making itself can be captured by the walking algorithm. The exception is -114.514, the disciplinary weight. The walking algorithm will ignore it unless it is the unique result." - public static func sampleDictionaryContent(for type: vChewingLM.ReplacableUserDataType) -> String { + public static func sampleDictionaryContent(for type: LMAssembly.ReplacableUserDataType) -> String { var result = "" switch type { case .thePhrases: