diff --git a/Source/Modules/LangModelRelated/LMInstantiator.swift b/Source/Modules/LangModelRelated/LMInstantiator.swift index e0c3c681..ad8f742e 100644 --- a/Source/Modules/LangModelRelated/LMInstantiator.swift +++ b/Source/Modules/LangModelRelated/LMInstantiator.swift @@ -76,6 +76,7 @@ extension vChewing { ) var lmReplacements = LMReplacments() var lmAssociates = LMAssociates() + var lmPlainBopomofo = LMPlainBopomofo() // MARK: - 工具函式 @@ -166,6 +167,16 @@ extension vChewing { } } + public func loadUserSCPCSequencesData(path: String) { + if FileManager.default.isReadableFile(atPath: path) { + lmPlainBopomofo.close() + lmPlainBopomofo.open(path) + IME.prtDebugIntel("lmPlainBopomofo: \(lmPlainBopomofo.count) entries of data loaded from: \(path)") + } else { + IME.prtDebugIntel("lmPlainBopomofo: File access failure: \(path)") + } + } + // MARK: - 核心函式(對外) /// 威注音輸入法目前尚未具備對雙元圖的處理能力,故停用該函式。 @@ -181,6 +192,11 @@ extension vChewing { /// 準備不同的語言模組容器,開始逐漸往容器陣列內塞入資料。 var rawAllUnigrams: [Megrez.Unigram] = [] + // 如果有檢測到使用者自訂逐字選字語料庫內的相關資料的話,在這裡先插入。 + if mgrPrefs.useSCPCTypingMode { + rawAllUnigrams += lmPlainBopomofo.valuesFor(key: key).map { Megrez.Unigram.init(value: $0, score: 0) } + } + // 用 reversed 指令讓使用者語彙檔案內的詞條優先順序隨著行數增加而逐漸增高。 // 這樣一來就可以在就地新增語彙時徹底複寫優先權。 // 將兩句差分也是為了讓 rawUserUnigrams 的類型不受可能的影響。 diff --git a/Source/Modules/LangModelRelated/SubLMs/lmPlainBopomofo.swift b/Source/Modules/LangModelRelated/SubLMs/lmPlainBopomofo.swift new file mode 100644 index 00000000..356bcce3 --- /dev/null +++ b/Source/Modules/LangModelRelated/SubLMs/lmPlainBopomofo.swift @@ -0,0 +1,83 @@ +// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License). +// StringView Ranges extension by (c) 2022 and onwards Isaac Xen (MIT 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 + +extension vChewing { + @frozen public struct LMPlainBopomofo { + var rangeMap: [String: String] = [:] + + public var count: Int { + rangeMap.count + } + + public init() { + rangeMap = [:] + } + + public func isLoaded() -> Bool { + !rangeMap.isEmpty + } + + @discardableResult public mutating func open(_ path: String) -> Bool { + if isLoaded() { + return false + } + + do { + let rawData = try Data(contentsOf: URL(fileURLWithPath: path)) + let rawPlist: [String: String] = + try PropertyListSerialization.propertyList(from: rawData, format: nil) as? [String: String] ?? .init() + rangeMap = rawPlist + } catch { + IME.prtDebugIntel("\(error)") + IME.prtDebugIntel("↑ Exception happened when reading data at: \(path).") + return false + } + + return true + } + + public mutating func close() { + if isLoaded() { + rangeMap.removeAll() + } + } + + public func dump() { + // We remove this function in order to reduce out maintenance workload. + // This function will be implemented only if further hard-necessity comes. + } + + public func valuesFor(key: String) -> [String] { + var pairs: [String] = [] + if let arrRangeRecords: String = rangeMap[key] { + pairs.append(contentsOf: arrRangeRecords.map({ String($0) })) + } + var set = Set() + return pairs.filter { set.insert($0).inserted } + } + + public func hasValuesFor(key: String) -> Bool { rangeMap.keys.contains(key) } + } +} + +// MARK: - StringView Ranges Extension (by Isaac Xen) + +extension String { + fileprivate func ranges(splitBy separator: Element) -> [Range] { + var startIndex = startIndex + return split(separator: separator).reduce(into: []) { ranges, substring in + _ = range(of: substring, range: startIndex..