LMAssembly // Pack LMUserOverride inside LMInstantiator, etc.

This commit is contained in:
ShikiSuen 2024-02-18 15:51:24 +08:00
parent c5899152e6
commit e44843e603
35 changed files with 302 additions and 315 deletions

View File

@ -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半衰記憶模組。

View File

@ -11,7 +11,8 @@ import Foundation
/// InputToken.parse Token
/// Token .translated()
public enum InputToken {
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)
@ -20,20 +21,21 @@ public enum InputToken {
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()

View File

@ -10,7 +10,7 @@ import Foundation
import LineReader
import Shared
public extension vChewingLM {
public extension LMAssembly {
enum LMConsolidator {
public static let kPragmaHeader = "# 𝙵𝙾𝚁𝙼𝙰𝚃 𝚘𝚛𝚐.𝚊𝚝𝚎𝚕𝚒𝚎𝚛𝙸𝚗𝚖𝚞.𝚟𝚌𝚑𝚎𝚠𝚒𝚗𝚐.𝚞𝚜𝚎𝚛𝙻𝚊𝚗𝚐𝚞𝚊𝚐𝚎𝙼𝚘𝚍𝚎𝚕𝙳𝚊𝚝𝚊.𝚏𝚘𝚛𝚖𝚊𝚝𝚝𝚎𝚍"

View File

@ -11,7 +11,7 @@ import Megrez
import Shared
import SQLite3
public extension vChewingLM {
public extension LMAssembly {
/// LMInstantiatorLMI
/// 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() {}

View File

@ -10,7 +10,7 @@ import Foundation
import Megrez
import Shared
public extension vChewingLM.LMInstantiator {
public extension LMAssembly.LMInstantiator {
///
var cassetteWildcardKey: String { Self.lmCassette.wildcardKey }
///

View File

@ -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]()

View File

@ -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_"

View File

@ -31,6 +31,7 @@ import SQLite3
) WITHOUT ROWID;
*/
extension LMAssembly.LMInstantiator {
enum CoreColumn: Int32 {
case theDataCHS = 1 //
case theDataCHT = 2 //
@ -53,8 +54,9 @@ enum CoreColumn: Int32 {
}
}
}
}
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)
}

View File

@ -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)
}
}

View File

@ -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<String.Index>, Int)]] = [:]
var strData: String = ""

View File

@ -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

View File

@ -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<String.Index>]] = [:]

View File

@ -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] {
let rawJSON = try JSONDecoder().decode([String: String].self, from: rawData)
dataMap = rawJSON
} else {
filePath = oldPath
vCLog("↑ Exception happened when reading JSON file at: \(path).")
return false
}
} catch {
filePath = oldPath
vCLog("\(error)")

View File

@ -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<String.Index>] = [:]
var strData: String = ""

View File

@ -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": "˙",
]
}
}

View File

@ -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()

View File

@ -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

View File

@ -10,7 +10,7 @@ import Foundation
import Shared
import SQLite3
public enum vChewingLM {
public enum LMAssembly {
enum FileErrors: Error {
case fileHandleError(String)
}

View File

@ -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()
}
}

View File

@ -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)")

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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)

View File

@ -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()
}
}

View File

@ -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)

View File

@ -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 {

View File

@ -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

View File

@ -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: ", "))

View File

@ -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()

View File

@ -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:

View File

@ -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
}

View File

@ -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)
}

View File

@ -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: