diff --git a/Packages/Fuziki_NSAttributedTextView/Package.swift b/Packages/Fuziki_NSAttributedTextView/Package.swift index d8ca8ecc..f027570b 100644 --- a/Packages/Fuziki_NSAttributedTextView/Package.swift +++ b/Packages/Fuziki_NSAttributedTextView/Package.swift @@ -13,13 +13,13 @@ let package = Package( ), ], dependencies: [ - .package(path: "../vChewing_CocoaExtension"), + .package(path: "../vChewing_OSFrameworkImpl"), ], targets: [ .target( name: "NSAttributedTextView", dependencies: [ - .product(name: "CocoaExtension", package: "vChewing_CocoaExtension"), + .product(name: "OSFrameworkImpl", package: "vChewing_OSFrameworkImpl"), ] ), .testTarget( diff --git a/Packages/Fuziki_NSAttributedTextView/Sources/NSAttributedTextView/NSAttributedTextView.swift b/Packages/Fuziki_NSAttributedTextView/Sources/NSAttributedTextView/NSAttributedTextView.swift index f2fcaa40..35c30967 100644 --- a/Packages/Fuziki_NSAttributedTextView/Sources/NSAttributedTextView/NSAttributedTextView.swift +++ b/Packages/Fuziki_NSAttributedTextView/Sources/NSAttributedTextView/NSAttributedTextView.swift @@ -6,7 +6,7 @@ // Modified by The vChewing Project in order to use it with AppKit. import AppKit -import CocoaExtension +import OSFrameworkImpl import SwiftUI @available(macOS 10.15, *) diff --git a/Packages/Fuziki_NSAttributedTextView/Tests/NSAttributedTextViewTests/NSAttributedTextViewTests.swift b/Packages/Fuziki_NSAttributedTextView/Tests/NSAttributedTextViewTests/NSAttributedTextViewTests.swift index 013b2db7..8d85e2a1 100644 --- a/Packages/Fuziki_NSAttributedTextView/Tests/NSAttributedTextViewTests/NSAttributedTextViewTests.swift +++ b/Packages/Fuziki_NSAttributedTextView/Tests/NSAttributedTextViewTests/NSAttributedTextViewTests.swift @@ -7,9 +7,9 @@ // requirements defined in MIT License. import AppKit -import CocoaExtension import Foundation @testable import NSAttributedTextView +import OSFrameworkImpl import Shared import XCTest diff --git a/Packages/RMJay_LineReader/Sources/LineReader/LineReader.swift b/Packages/RMJay_LineReader/Sources/LineReader/LineReader.swift index e353f56e..b13f6adb 100644 --- a/Packages/RMJay_LineReader/Sources/LineReader/LineReader.swift +++ b/Packages/RMJay_LineReader/Sources/LineReader/LineReader.swift @@ -1,7 +1,6 @@ // (c) 2019 and onwards Robert Muckle-Jones (Apache 2.0 License). import Foundation -import SwiftExtension public class LineReader { let encoding: String.Encoding diff --git a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/CtlCandidateTDK.swift b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/CtlCandidateTDK.swift index 9920bd20..0545dea8 100644 --- a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/CtlCandidateTDK.swift +++ b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/CtlCandidateTDK.swift @@ -7,7 +7,7 @@ // requirements defined in MIT License. import AppKit -import CocoaExtension +import OSFrameworkImpl import Shared private extension NSUserInterfaceLayoutOrientation { diff --git a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/VwrCandidateTDK_Appkit.swift b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/VwrCandidateTDK_Appkit.swift index 6c193d79..129a3cfb 100644 --- a/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/VwrCandidateTDK_Appkit.swift +++ b/Packages/vChewing_CandidateWindow/Sources/CandidateWindow/TDKCandidates/VwrCandidateTDK_Appkit.swift @@ -7,7 +7,7 @@ // requirements defined in MIT License. import AppKit -import CocoaExtension +import OSFrameworkImpl import Shared /// 田所選字窗的 AppKit 简单版本,繪製效率不受 SwiftUI 的限制。 diff --git a/Packages/vChewing_LangModelAssembly/Package.swift b/Packages/vChewing_LangModelAssembly/Package.swift index d9216023..fcfae8fc 100644 --- a/Packages/vChewing_LangModelAssembly/Package.swift +++ b/Packages/vChewing_LangModelAssembly/Package.swift @@ -15,8 +15,7 @@ let package = Package( dependencies: [ .package(path: "../RMJay_LineReader"), .package(path: "../vChewing_Megrez"), - .package(path: "../vChewing_PinyinPhonaConverter"), - .package(path: "../vChewing_Shared"), + .package(path: "../vChewing_SwiftExtension"), ], targets: [ .target( @@ -24,8 +23,7 @@ let package = Package( dependencies: [ .product(name: "LineReader", package: "RMJay_LineReader"), .product(name: "Megrez", package: "vChewing_Megrez"), - .product(name: "Shared", package: "vChewing_Shared"), - .product(name: "PinyinPhonaConverter", package: "vChewing_PinyinPhonaConverter"), + .product(name: "SwiftExtension", package: "vChewing_SwiftExtension"), ] ), .testTarget( diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMConsolidator.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMConsolidator.swift index 3219b333..ac3ff5b1 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMConsolidator.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMConsolidator.swift @@ -8,7 +8,6 @@ import Foundation import LineReader -import Shared public extension LMAssembly { enum LMConsolidator { @@ -26,19 +25,19 @@ public extension LMAssembly { let lineReader = try LineReader(file: fileHandle) for strLine in lineReader { // 不需要 i=0,因為第一遍迴圈就出結果。 if strLine != kPragmaHeader { - vCLog("Header Mismatch, Starting In-Place Consolidation.") + vCLMLog("Header Mismatch, Starting In-Place Consolidation.") return false } else { - vCLog("Header Verification Succeeded: \(strLine).") + vCLMLog("Header Verification Succeeded: \(strLine).") return true } } } catch { - vCLog("Header Verification Failed: File Access Error.") + vCLMLog("Header Verification Failed: File Access Error.") return false } } - vCLog("Header Verification Failed: File Missing.") + vCLMLog("Header Verification Failed: File Missing.") return false } @@ -51,12 +50,12 @@ public extension LMAssembly { let dict = try FileManager.default.attributesOfItem(atPath: path) if let value = dict[FileAttributeKey.size] as? UInt64 { fileSize = value } } catch { - vCLog("EOF Fix Failed: File Missing at \(path).") + vCLMLog("EOF Fix Failed: File Missing at \(path).") return false } guard let fileSize = fileSize else { return false } guard let writeFile = FileHandle(forUpdatingAtPath: path) else { - vCLog("EOF Fix Failed: File Not Writable at \(path).") + vCLMLog("EOF Fix Failed: File Not Writable at \(path).") return false } defer { writeFile.closeFile() } @@ -64,11 +63,11 @@ public extension LMAssembly { /// 但這個函式執行完之後往往就會 consolidate() 整理格式,所以不會有差。 writeFile.seek(toFileOffset: fileSize - 1) if writeFile.readDataToEndOfFile().first != 0x0A { - vCLog("EOF Missing Confirmed, Start Fixing.") + vCLMLog("EOF Missing Confirmed, Start Fixing.") var newData = Data() newData.append(0x0A) writeFile.write(newData) - vCLog("EOF Successfully Assured.") + vCLMLog("EOF Successfully Assured.") } return false } @@ -142,14 +141,29 @@ public extension LMAssembly { // Write consolidated file contents. try strProcessed.write(to: urlPath, atomically: false, encoding: .utf8) } catch { - vCLog("Consolidation Failed w/ File: \(path), error: \(error)") + vCLMLog("Consolidation Failed w/ File: \(path), error: \(error)") return false } - vCLog("Either Consolidation Successful Or No-Need-To-Consolidate.") + vCLMLog("Either Consolidation Successful Or No-Need-To-Consolidate.") return true } - vCLog("Consolidation Failed: File Missing at \(path).") + vCLMLog("Consolidation Failed: File Missing at \(path).") return false } } } + +private extension String { + mutating func regReplace(pattern: String, replaceWith: String = "") { + // Ref: https://stackoverflow.com/a/40993403/4162914 && https://stackoverflow.com/a/71291137/4162914 + do { + let regex = try NSRegularExpression( + pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines] + ) + let range = NSRange(startIndex..., in: self) + self = regex.stringByReplacingMatches( + in: self, options: [], range: range, withTemplate: replaceWith + ) + } catch { return } + } +} diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift index 295c808b..a7758a0d 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator.swift @@ -8,8 +8,6 @@ import Foundation import Megrez -import Shared -import SQLite3 public extension LMAssembly { /// 語言模組副本化模組(LMInstantiator,下稱「LMI」)自身為符合天權星組字引擎內 @@ -47,13 +45,13 @@ public extension LMAssembly { static var ptrSQL: OpaquePointer? // SQLite 連線是否已經建立。 - public private(set) static var isSQLDBConnected: Bool = false + public internal(set) static var isSQLDBConnected: Bool = false // 簡體中文模型? public let isCHS: Bool // 在函式內部用以記錄狀態的開關。 - public var config = Config() + public private(set) var config = Config() // 這句需要留著,不然無法被 package 外界存取。 public init( @@ -69,21 +67,8 @@ public extension LMAssembly { return self } - @discardableResult public static func connectSQLDB(dbPath: String, dropPreviousConnection: Bool = true) -> Bool { - if dropPreviousConnection { disconnectSQLDB() } - vCLog("Establishing SQLite connection to: \(dbPath)") - guard sqlite3_open(dbPath, &Self.ptrSQL) == SQLITE_OK else { return false } - guard "PRAGMA journal_mode = OFF;".runAsSQLExec(dbPointer: &ptrSQL) else { return false } - isSQLDBConnected = true - return true - } - - public static func disconnectSQLDB() { - if Self.ptrSQL != nil { - sqlite3_close_v2(Self.ptrSQL) - Self.ptrSQL = nil - } - isSQLDBConnected = false + public static func setCassetCandidateKeyValidator(_ validator: @escaping (String) -> Bool) { + Self.lmCassette.candidateKeysValidator = validator } /// 介紹一下幾個通用的語言模組型別: @@ -126,9 +111,9 @@ public extension LMAssembly { if FileManager.default.isReadableFile(atPath: path) { self.lmUserPhrases.clear() self.lmUserPhrases.open(path) - vCLog("lmUserPhrases: \(self.lmUserPhrases.count) entries of data loaded from: \(path)") + vCLMLog("lmUserPhrases: \(self.lmUserPhrases.count) entries of data loaded from: \(path)") } else { - vCLog("lmUserPhrases: File access failure: \(path)") + vCLMLog("lmUserPhrases: File access failure: \(path)") } } guard let filterPath = filterPath else { return } @@ -136,9 +121,9 @@ public extension LMAssembly { if FileManager.default.isReadableFile(atPath: filterPath) { self.lmFiltered.clear() self.lmFiltered.open(filterPath) - vCLog("lmFiltered: \(self.lmFiltered.count) entries of data loaded from: \(path)") + vCLMLog("lmFiltered: \(self.lmFiltered.count) entries of data loaded from: \(path)") } else { - vCLog("lmFiltered: File access failure: \(path)") + vCLMLog("lmFiltered: File access failure: \(path)") } } } @@ -148,9 +133,9 @@ public extension LMAssembly { if FileManager.default.isReadableFile(atPath: path) { lmFiltered.clear() lmFiltered.open(path) - vCLog("lmFiltered: \(lmFiltered.count) entries of data loaded from: \(path)") + vCLMLog("lmFiltered: \(lmFiltered.count) entries of data loaded from: \(path)") } else { - vCLog("lmFiltered: File access failure: \(path)") + vCLMLog("lmFiltered: File access failure: \(path)") } } @@ -159,9 +144,9 @@ public extension LMAssembly { if FileManager.default.isReadableFile(atPath: path) { self.lmUserSymbols.clear() self.lmUserSymbols.open(path) - vCLog("lmUserSymbol: \(self.lmUserSymbols.count) entries of data loaded from: \(path)") + vCLMLog("lmUserSymbol: \(self.lmUserSymbols.count) entries of data loaded from: \(path)") } else { - vCLog("lmUserSymbol: File access failure: \(path)") + vCLMLog("lmUserSymbol: File access failure: \(path)") } } } @@ -171,9 +156,9 @@ public extension LMAssembly { if FileManager.default.isReadableFile(atPath: path) { self.lmAssociates.clear() self.lmAssociates.open(path) - vCLog("lmAssociates: \(self.lmAssociates.count) entries of data loaded from: \(path)") + vCLMLog("lmAssociates: \(self.lmAssociates.count) entries of data loaded from: \(path)") } else { - vCLog("lmAssociates: File access failure: \(path)") + vCLMLog("lmAssociates: File access failure: \(path)") } } } @@ -183,9 +168,9 @@ public extension LMAssembly { if FileManager.default.isReadableFile(atPath: path) { self.lmReplacements.clear() self.lmReplacements.open(path) - vCLog("lmReplacements: \(self.lmReplacements.count) entries of data loaded from: \(path)") + vCLMLog("lmReplacements: \(self.lmReplacements.count) entries of data loaded from: \(path)") } else { - vCLog("lmReplacements: File access failure: \(path)") + vCLMLog("lmReplacements: File access failure: \(path)") } } } @@ -196,9 +181,9 @@ public extension LMAssembly { if FileManager.default.isReadableFile(atPath: path) { Self.lmCassette.clear() Self.lmCassette.open(path) - vCLog("lmCassette: \(Self.lmCassette.count) entries of data loaded from: \(path)") + vCLMLog("lmCassette: \(Self.lmCassette.count) entries of data loaded from: \(path)") } else { - vCLog("lmCassette: File access failure: \(path)") + vCLMLog("lmCassette: File access failure: \(path)") } } } diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_CassetteExtension.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_CassetteExtension.swift index beb09f4b..3a079663 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_CassetteExtension.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_CassetteExtension.swift @@ -8,7 +8,7 @@ import Foundation import Megrez -import Shared +import SwiftExtension public extension LMAssembly.LMInstantiator { /// 磁帶模式專用:當前磁帶所規定的花牌鍵。 diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift index f629fe9d..731f9350 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/LMInstantiator_SQLExtension.swift @@ -8,7 +8,6 @@ import Foundation import Megrez -import Shared import SQLite3 /* ============== @@ -57,6 +56,23 @@ extension LMAssembly.LMInstantiator { } extension LMAssembly.LMInstantiator { + @discardableResult public static func connectSQLDB(dbPath: String, dropPreviousConnection: Bool = true) -> Bool { + if dropPreviousConnection { disconnectSQLDB() } + vCLMLog("Establishing SQLite connection to: \(dbPath)") + guard sqlite3_open(dbPath, &Self.ptrSQL) == SQLITE_OK else { return false } + guard "PRAGMA journal_mode = OFF;".runAsSQLExec(dbPointer: &ptrSQL) else { return false } + isSQLDBConnected = true + return true + } + + public static func disconnectSQLDB() { + if Self.ptrSQL != nil { + sqlite3_close_v2(Self.ptrSQL) + Self.ptrSQL = nil + } + isSQLDBConnected = false + } + fileprivate static func querySQL(strStmt sqlQuery: String, coreColumn column: CoreColumn, handler: (String) -> Void) { guard Self.ptrSQL != nil else { return } performStatementSansResult { ptrStatement in diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/PinyinPhonaConverter.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/PinyinPhonaConverter.swift new file mode 100644 index 00000000..dca25d46 --- /dev/null +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/PinyinPhonaConverter.swift @@ -0,0 +1,123 @@ +// (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 + +// 該檔案使得 LMAssembly 擺脫對 Tekkon 的依賴。 + +private typealias LengthSortedDictionary = [Int: [String: String]] + +private let mapHanyuPinyinToPhonabets: LengthSortedDictionary = { + let parsed = try? JSONDecoder().decode(LengthSortedDictionary.self, from: jsnHanyuPinyinToMPS.data(using: .utf8) ?? Data([])) + return parsed ?? [:] +}() + +extension String { + mutating func convertToPhonabets(newToneOne: String = "") { + if isEmpty || contains("_") || !isNotPureAlphanumerical { return } + let lengths = mapHanyuPinyinToPhonabets.keys.sorted().reversed() + lengths.forEach { length in + mapHanyuPinyinToPhonabets[length]?.forEach { key, value in + self = replacingOccurrences(of: key, with: value) + } + } + self = replacingOccurrences(of: " ", with: newToneOne) + } +} + +/// 檢測字串是否包含半形英數內容 +private extension String { + var isNotPureAlphanumerical: Bool { + let regex = ".*[^A-Za-z0-9].*" + let testString = NSPredicate(format: "SELF MATCHES %@", regex) + return testString.evaluate(with: self) + } +} + +private let jsnHanyuPinyinToMPS = #""" +{ +"1":{"1":" ","2":"ˊ","3":"ˇ","4":"ˋ","5":"˙","a":"ㄚ","e":"ㄜ","o":"ㄛ","q":"ㄑ"}, +"2":{"ai":"ㄞ","an":"ㄢ","ao":"ㄠ","ba":"ㄅㄚ","bi":"ㄅㄧ","bo":"ㄅㄛ","bu":"ㄅㄨ", + "ca":"ㄘㄚ","ce":"ㄘㄜ","ci":"ㄘ","cu":"ㄘㄨ","da":"ㄉㄚ","de":"ㄉㄜ","di":"ㄉㄧ", + "du":"ㄉㄨ","eh":"ㄝ","ei":"ㄟ","en":"ㄣ","er":"ㄦ","fa":"ㄈㄚ","fo":"ㄈㄛ", + "fu":"ㄈㄨ","ga":"ㄍㄚ","ge":"ㄍㄜ","gi":"ㄍㄧ","gu":"ㄍㄨ","ha":"ㄏㄚ","he":"ㄏㄜ", + "hu":"ㄏㄨ","ji":"ㄐㄧ","ju":"ㄐㄩ","ka":"ㄎㄚ","ke":"ㄎㄜ","ku":"ㄎㄨ","la":"ㄌㄚ", + "le":"ㄌㄜ","li":"ㄌㄧ","lo":"ㄌㄛ","lu":"ㄌㄨ","lv":"ㄌㄩ","ma":"ㄇㄚ","me":"ㄇㄜ", + "mi":"ㄇㄧ","mo":"ㄇㄛ","mu":"ㄇㄨ","na":"ㄋㄚ","ne":"ㄋㄜ","ni":"ㄋㄧ","nu":"ㄋㄨ", + "nv":"ㄋㄩ","ou":"ㄡ","pa":"ㄆㄚ","pi":"ㄆㄧ","po":"ㄆㄛ","pu":"ㄆㄨ","qi":"ㄑㄧ", + "qu":"ㄑㄩ","re":"ㄖㄜ","ri":"ㄖ","ru":"ㄖㄨ","sa":"ㄙㄚ","se":"ㄙㄜ","si":"ㄙ", + "su":"ㄙㄨ","ta":"ㄊㄚ","te":"ㄊㄜ","ti":"ㄊㄧ","tu":"ㄊㄨ","wa":"ㄨㄚ","wo":"ㄨㄛ", + "wu":"ㄨ","xi":"ㄒㄧ","xu":"ㄒㄩ","ya":"ㄧㄚ","ye":"ㄧㄝ","yi":"ㄧ","yo":"ㄧㄛ", + "yu":"ㄩ","za":"ㄗㄚ","ze":"ㄗㄜ","zi":"ㄗ","zu":"ㄗㄨ"}, +"3":{"ang":"ㄤ","bai":"ㄅㄞ","ban":"ㄅㄢ","bao":"ㄅㄠ","bei":"ㄅㄟ","ben":"ㄅㄣ", + "bie":"ㄅㄧㄝ","bin":"ㄅㄧㄣ","cai":"ㄘㄞ","can":"ㄘㄢ","cao":"ㄘㄠ","cei":"ㄘㄟ", + "cen":"ㄘㄣ","cha":"ㄔㄚ","che":"ㄔㄜ","chi":"ㄔ","chu":"ㄔㄨ","cou":"ㄘㄡ", + "cui":"ㄘㄨㄟ","cun":"ㄘㄨㄣ","cuo":"ㄘㄨㄛ","dai":"ㄉㄞ","dan":"ㄉㄢ","dao":"ㄉㄠ", + "dei":"ㄉㄟ","den":"ㄉㄣ","dia":"ㄉㄧㄚ","die":"ㄉㄧㄝ","diu":"ㄉㄧㄡ","dou":"ㄉㄡ", + "dui":"ㄉㄨㄟ","dun":"ㄉㄨㄣ","duo":"ㄉㄨㄛ","eng":"ㄥ","fan":"ㄈㄢ","fei":"ㄈㄟ", + "fen":"ㄈㄣ","fou":"ㄈㄡ","gai":"ㄍㄞ","gan":"ㄍㄢ","gao":"ㄍㄠ","gei":"ㄍㄟ", + "gen":"ㄍㄣ","gin":"ㄍㄧㄣ","gou":"ㄍㄡ","gua":"ㄍㄨㄚ","gue":"ㄍㄨㄜ","gui":"ㄍㄨㄟ", + "gun":"ㄍㄨㄣ","guo":"ㄍㄨㄛ","hai":"ㄏㄞ","han":"ㄏㄢ","hao":"ㄏㄠ","hei":"ㄏㄟ", + "hen":"ㄏㄣ","hou":"ㄏㄡ","hua":"ㄏㄨㄚ","hui":"ㄏㄨㄟ","hun":"ㄏㄨㄣ","huo":"ㄏㄨㄛ", + "jia":"ㄐㄧㄚ","jie":"ㄐㄧㄝ","jin":"ㄐㄧㄣ","jiu":"ㄐㄧㄡ","jue":"ㄐㄩㄝ", + "jun":"ㄐㄩㄣ","kai":"ㄎㄞ","kan":"ㄎㄢ","kao":"ㄎㄠ","ken":"ㄎㄣ","kiu":"ㄎㄧㄡ", + "kou":"ㄎㄡ","kua":"ㄎㄨㄚ","kui":"ㄎㄨㄟ","kun":"ㄎㄨㄣ","kuo":"ㄎㄨㄛ","lai":"ㄌㄞ", + "lan":"ㄌㄢ","lao":"ㄌㄠ","lei":"ㄌㄟ","lia":"ㄌㄧㄚ","lie":"ㄌㄧㄝ","lin":"ㄌㄧㄣ", + "liu":"ㄌㄧㄡ","lou":"ㄌㄡ","lun":"ㄌㄨㄣ","luo":"ㄌㄨㄛ","lve":"ㄌㄩㄝ","mai":"ㄇㄞ", + "man":"ㄇㄢ","mao":"ㄇㄠ","mei":"ㄇㄟ","men":"ㄇㄣ","mie":"ㄇㄧㄝ","min":"ㄇㄧㄣ", + "miu":"ㄇㄧㄡ","mou":"ㄇㄡ","nai":"ㄋㄞ","nan":"ㄋㄢ","nao":"ㄋㄠ","nei":"ㄋㄟ", + "nen":"ㄋㄣ","nie":"ㄋㄧㄝ","nin":"ㄋㄧㄣ","niu":"ㄋㄧㄡ","nou":"ㄋㄡ","nui":"ㄋㄨㄟ", + "nun":"ㄋㄨㄣ","nuo":"ㄋㄨㄛ","nve":"ㄋㄩㄝ","pai":"ㄆㄞ","pan":"ㄆㄢ","pao":"ㄆㄠ", + "pei":"ㄆㄟ","pen":"ㄆㄣ","pia":"ㄆㄧㄚ","pie":"ㄆㄧㄝ","pin":"ㄆㄧㄣ","pou":"ㄆㄡ", + "qia":"ㄑㄧㄚ","qie":"ㄑㄧㄝ","qin":"ㄑㄧㄣ","qiu":"ㄑㄧㄡ","que":"ㄑㄩㄝ", + "qun":"ㄑㄩㄣ","ran":"ㄖㄢ","rao":"ㄖㄠ","ren":"ㄖㄣ","rou":"ㄖㄡ","rui":"ㄖㄨㄟ", + "run":"ㄖㄨㄣ","ruo":"ㄖㄨㄛ","sai":"ㄙㄞ","san":"ㄙㄢ","sao":"ㄙㄠ","sei":"ㄙㄟ", + "sen":"ㄙㄣ","sha":"ㄕㄚ","she":"ㄕㄜ","shi":"ㄕ","shu":"ㄕㄨ","sou":"ㄙㄡ", + "sui":"ㄙㄨㄟ","sun":"ㄙㄨㄣ","suo":"ㄙㄨㄛ","tai":"ㄊㄞ","tan":"ㄊㄢ","tao":"ㄊㄠ", + "tie":"ㄊㄧㄝ","tou":"ㄊㄡ","tui":"ㄊㄨㄟ","tun":"ㄊㄨㄣ","tuo":"ㄊㄨㄛ", + "wai":"ㄨㄞ","wan":"ㄨㄢ","wei":"ㄨㄟ","wen":"ㄨㄣ","xia":"ㄒㄧㄚ","xie":"ㄒㄧㄝ", + "xin":"ㄒㄧㄣ","xiu":"ㄒㄧㄡ","xue":"ㄒㄩㄝ","xun":"ㄒㄩㄣ","yai":"ㄧㄞ", + "yan":"ㄧㄢ","yao":"ㄧㄠ","yin":"ㄧㄣ","you":"ㄧㄡ","yue":"ㄩㄝ","yun":"ㄩㄣ", + "zai":"ㄗㄞ","zan":"ㄗㄢ","zao":"ㄗㄠ","zei":"ㄗㄟ","zen":"ㄗㄣ","zha":"ㄓㄚ", + "zhe":"ㄓㄜ","zhi":"ㄓ","zhu":"ㄓㄨ","zou":"ㄗㄡ","zui":"ㄗㄨㄟ","zun":"ㄗㄨㄣ", + "zuo":"ㄗㄨㄛ"}, +"4":{"bang":"ㄅㄤ","beng":"ㄅㄥ","bian":"ㄅㄧㄢ","biao":"ㄅㄧㄠ","bing":"ㄅㄧㄥ", + "cang":"ㄘㄤ","ceng":"ㄘㄥ","chai":"ㄔㄞ","chan":"ㄔㄢ","chao":"ㄔㄠ","chen":"ㄔㄣ", + "chou":"ㄔㄡ","chua":"ㄔㄨㄚ","chui":"ㄔㄨㄟ","chun":"ㄔㄨㄣ","chuo":"ㄔㄨㄛ", + "cong":"ㄘㄨㄥ","cuan":"ㄘㄨㄢ","dang":"ㄉㄤ","deng":"ㄉㄥ","dian":"ㄉㄧㄢ", + "diao":"ㄉㄧㄠ","ding":"ㄉㄧㄥ","dong":"ㄉㄨㄥ","duan":"ㄉㄨㄢ","fang":"ㄈㄤ", + "feng":"ㄈㄥ","fiao":"ㄈㄧㄠ","fong":"ㄈㄨㄥ","gang":"ㄍㄤ","geng":"ㄍㄥ", + "giao":"ㄍㄧㄠ","gong":"ㄍㄨㄥ","guai":"ㄍㄨㄞ","guan":"ㄍㄨㄢ","hang":"ㄏㄤ", + "heng":"ㄏㄥ","hong":"ㄏㄨㄥ","huai":"ㄏㄨㄞ","huan":"ㄏㄨㄢ","jian":"ㄐㄧㄢ", + "jiao":"ㄐㄧㄠ","jing":"ㄐㄧㄥ","juan":"ㄐㄩㄢ","kang":"ㄎㄤ","keng":"ㄎㄥ", + "kong":"ㄎㄨㄥ","kuai":"ㄎㄨㄞ","kuan":"ㄎㄨㄢ","lang":"ㄌㄤ","leng":"ㄌㄥ", + "lian":"ㄌㄧㄢ","liao":"ㄌㄧㄠ","ling":"ㄌㄧㄥ","long":"ㄌㄨㄥ","luan":"ㄌㄨㄢ", + "lvan":"ㄌㄩㄢ","mang":"ㄇㄤ","meng":"ㄇㄥ","mian":"ㄇㄧㄢ","miao":"ㄇㄧㄠ", + "ming":"ㄇㄧㄥ","nang":"ㄋㄤ","neng":"ㄋㄥ","nian":"ㄋㄧㄢ","niao":"ㄋㄧㄠ", + "ning":"ㄋㄧㄥ","nong":"ㄋㄨㄥ","nuan":"ㄋㄨㄢ","pang":"ㄆㄤ","peng":"ㄆㄥ", + "pian":"ㄆㄧㄢ","piao":"ㄆㄧㄠ","ping":"ㄆㄧㄥ","qian":"ㄑㄧㄢ","qiao":"ㄑㄧㄠ", + "qing":"ㄑㄧㄥ","quan":"ㄑㄩㄢ","rang":"ㄖㄤ","reng":"ㄖㄥ","rong":"ㄖㄨㄥ", + "ruan":"ㄖㄨㄢ","sang":"ㄙㄤ","seng":"ㄙㄥ","shai":"ㄕㄞ","shan":"ㄕㄢ", + "shao":"ㄕㄠ","shei":"ㄕㄟ","shen":"ㄕㄣ","shou":"ㄕㄡ","shua":"ㄕㄨㄚ", + "shui":"ㄕㄨㄟ","shun":"ㄕㄨㄣ","shuo":"ㄕㄨㄛ","song":"ㄙㄨㄥ","suan":"ㄙㄨㄢ", + "tang":"ㄊㄤ","teng":"ㄊㄥ","tian":"ㄊㄧㄢ","tiao":"ㄊㄧㄠ","ting":"ㄊㄧㄥ", + "tong":"ㄊㄨㄥ","tuan":"ㄊㄨㄢ","wang":"ㄨㄤ","weng":"ㄨㄥ","xian":"ㄒㄧㄢ", + "xiao":"ㄒㄧㄠ","xing":"ㄒㄧㄥ","xuan":"ㄒㄩㄢ","yang":"ㄧㄤ","ying":"ㄧㄥ", + "yong":"ㄩㄥ","yuan":"ㄩㄢ","zang":"ㄗㄤ","zeng":"ㄗㄥ","zhai":"ㄓㄞ", + "zhan":"ㄓㄢ","zhao":"ㄓㄠ","zhei":"ㄓㄟ","zhen":"ㄓㄣ","zhou":"ㄓㄡ", + "zhua":"ㄓㄨㄚ","zhui":"ㄓㄨㄟ","zhun":"ㄓㄨㄣ","zhuo":"ㄓㄨㄛ", + "zong":"ㄗㄨㄥ","zuan":"ㄗㄨㄢ"}, +"5":{"biang":"ㄅㄧㄤ","chang":"ㄔㄤ","cheng":"ㄔㄥ","chong":"ㄔㄨㄥ","chuai":"ㄔㄨㄞ", + "chuan":"ㄔㄨㄢ","duang":"ㄉㄨㄤ","guang":"ㄍㄨㄤ","huang":"ㄏㄨㄤ","jiang":"ㄐㄧㄤ", + "jiong":"ㄐㄩㄥ","kiang":"ㄎㄧㄤ","kuang":"ㄎㄨㄤ","liang":"ㄌㄧㄤ","niang":"ㄋㄧㄤ", + "qiang":"ㄑㄧㄤ","qiong":"ㄑㄩㄥ","shang":"ㄕㄤ","sheng":"ㄕㄥ","shuai":"ㄕㄨㄞ", + "shuan":"ㄕㄨㄢ","xiang":"ㄒㄧㄤ","xiong":"ㄒㄩㄥ","zhang":"ㄓㄤ","zheng":"ㄓㄥ", + "zhong":"ㄓㄨㄥ","zhuai":"ㄓㄨㄞ","zhuan":"ㄓㄨㄢ"}, +"6":{"chuang":"ㄔㄨㄤ","shuang":"ㄕㄨㄤ","zhuang":"ㄓㄨㄤ"} +} +"""# diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmAssociates.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmAssociates.swift index 6a9660ff..a5aa2030 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmAssociates.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmAssociates.swift @@ -7,8 +7,6 @@ // requirements defined in MIT License. import Megrez -import PinyinPhonaConverter -import Shared extension LMAssembly { struct LMAssociates { @@ -48,8 +46,8 @@ extension LMAssembly { replaceData(textData: rawStrData) } catch { filePath = oldPath - vCLog("\(error)") - vCLog("↑ Exception happened when reading data at: \(path).") + vCLMLog("\(error)") + vCLMLog("↑ Exception happened when reading data at: \(path).") return false } @@ -93,7 +91,7 @@ extension LMAssembly { do { try strData.write(toFile: filePath, atomically: true, encoding: .utf8) } catch { - vCLog("Failed to save current database to: \(filePath)") + vCLMLog("Failed to save current database to: \(filePath)") } } @@ -113,8 +111,7 @@ extension LMAssembly { pairs.append(theValue) } } - var set = Set() - return pairs.filter { set.insert($0).inserted } + return pairs.deduplicated } public func hasValuesFor(pair: Megrez.KeyValuePaired) -> Bool { diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCassette.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCassette.swift index 94f4d42d..3815e516 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCassette.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCassette.swift @@ -10,7 +10,6 @@ import Foundation import LineReader import Megrez -import Shared extension LMAssembly { /// 磁帶模組,用來方便使用者自行擴充字根輸入法。 @@ -40,6 +39,7 @@ extension LMAssembly { public private(set) var areCandidateKeysShiftHeld: Bool = false public private(set) var supplyQuickResults: Bool = false public private(set) var supplyPartiallyMatchedResults: Bool = false + public var candidateKeysValidator: (String) -> Bool = { _ in false } /// 計算頻率時要用到的東西 - NORM private var norm = 0.0 } @@ -195,7 +195,7 @@ extension LMAssembly.LMCassette { // Post process. // 備註:因為 Package 層級嵌套的現狀,此處不太方便檢查是否需要篩掉 J / K 鍵。 // 因此只能在其他地方做篩檢。 - if CandidateKey.validate(keys: selectionKeys) != nil { selectionKeys = "1234567890" } + if !candidateKeysValidator(selectionKeys) { selectionKeys = "1234567890" } if !keysUsedInCharDef.intersection(selectionKeys.map(\.description)).isEmpty { areCandidateKeysShiftHeld = true } @@ -204,10 +204,10 @@ extension LMAssembly.LMCassette { filePath = path return true } catch { - vCLog("CIN Loading Failed: File Access Error.") + vCLMLog("CIN Loading Failed: File Access Error.") } } else { - vCLog("CIN Loading Failed: File Missing.") + vCLMLog("CIN Loading Failed: File Missing.") } filePath = oldPath return false diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCoreEX.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCoreEX.swift index 03285cf7..fb1e8eb8 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCoreEX.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmCoreEX.swift @@ -7,8 +7,6 @@ // requirements defined in MIT License. import Megrez -import PinyinPhonaConverter -import Shared extension LMAssembly { /// 與之前的 LMCore 不同,LMCoreEX 不在辭典內記錄實體,而是記錄 range 範圍。 @@ -81,8 +79,8 @@ extension LMAssembly { replaceData(textData: rawStrData) } catch { filePath = oldPath - vCLog("\(error)") - vCLog("↑ Exception happened when reading data at: \(path).") + vCLMLog("\(error)") + vCLMLog("↑ Exception happened when reading data at: \(path).") return false } @@ -133,7 +131,7 @@ extension LMAssembly { } try dataToWrite.write(toFile: filePath, atomically: true, encoding: .utf8) } catch { - vCLog("Failed to save current database to: \(filePath)") + vCLMLog("Failed to save current database to: \(filePath)") } } @@ -150,7 +148,7 @@ extension LMAssembly { strDump += addline } } - vCLog(strDump) + vCLMLog(strDump) } /// 根據給定的讀音索引鍵,來獲取資料庫辭典內的對應資料陣列的字串首尾範圍資料、據此自 strData 取得字串形式的資料、生成單元圖陣列。 diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmPlainBopomofo.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmPlainBopomofo.swift index bfd79fdf..9f4492b2 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmPlainBopomofo.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmPlainBopomofo.swift @@ -7,7 +7,6 @@ // requirements defined in MIT License. import Foundation -import Shared extension LMAssembly { struct LMPlainBopomofo { @@ -22,8 +21,8 @@ extension LMAssembly { let rawJSON = try JSONDecoder().decode([String: [String: String]].self, from: rawData) dataMap = rawJSON } catch { - vCLog("\(error)") - vCLog("↑ Exception happened when parsing raw JSON sequence data from vChewing LMAssembly.") + vCLMLog("\(error)") + vCLMLog("↑ Exception happened when parsing raw JSON sequence data from vChewing LMAssembly.") dataMap = [:] } } diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmReplacements.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmReplacements.swift index 654d146f..46ed79d3 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmReplacements.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmReplacements.swift @@ -6,8 +6,6 @@ // marks, or product names of Contributor, except as required to fulfill notice // requirements defined in MIT License. -import Shared - extension LMAssembly { struct LMReplacements { public private(set) var filePath: String? @@ -35,8 +33,8 @@ extension LMAssembly { replaceData(textData: rawStrData) } catch { filePath = oldPath - vCLog("\(error)") - vCLog("↑ Exception happened when reading data at: \(path).") + vCLMLog("\(error)") + vCLMLog("↑ Exception happened when reading data at: \(path).") return false } @@ -72,7 +70,7 @@ extension LMAssembly { do { try strData.write(toFile: filePath, atomically: true, encoding: .utf8) } catch { - vCLog("Failed to save current database to: \(filePath)") + vCLMLog("Failed to save current database to: \(filePath)") } } @@ -81,7 +79,7 @@ extension LMAssembly { for entry in rangeMap { strDump += strData[entry.value] + "\n" } - vCLog(strDump) + vCLMLog(strDump) } public func valuesFor(key: String) -> String { diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmUserOverride.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmUserOverride.swift index 58be078d..bf75bdf8 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmUserOverride.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/SubLMs/lmUserOverride.swift @@ -9,7 +9,6 @@ import Foundation import Megrez -import Shared // MARK: - Public Types. @@ -202,18 +201,18 @@ extension LMAssembly.LMUserOverride { do { let nullData = "{}" guard let fileURL = fileURL ?? fileSaveLocationURL else { - throw "given fileURL is invalid or nil." + throw UOMError(rawValue: "given fileURL is invalid or nil.") } try nullData.write(to: fileURL, atomically: false, encoding: .utf8) } catch { - vCLog("UOM Error: Unable to clear the data in the UOM file. Details: \(error)") + vCLMLog("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.") + vCLMLog("UOM saveData() failed. At least the file Save URL is not set for the current UOM.") return } // 此處不要使用 JSONSerialization,不然執行緒會炸掉。 @@ -222,14 +221,14 @@ extension LMAssembly.LMUserOverride { guard let jsonData = try? encoder.encode(mutLRUMap) else { return } try jsonData.write(to: fileURL, options: .atomic) } catch { - vCLog("UOM Error: Unable to save data, abort saving. Details: \(error)") + vCLMLog("UOM Error: Unable to save data, abort saving. Details: \(error)") return } } 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.") + vCLMLog("UOM loadData() failed. At least the file Load URL is not set for the current UOM.") return } // 此處不要使用 JSONSerialization,不然執行緒會炸掉。 @@ -238,13 +237,13 @@ extension LMAssembly.LMUserOverride { let data = try Data(contentsOf: fileURL, options: .mappedIfSafe) if ["", "{}"].contains(String(data: data, encoding: .utf8)) { return } guard let jsonResult = try? decoder.decode([String: KeyObservationPair].self, from: data) else { - vCLog("UOM Error: Read file content type invalid, abort loading.") + vCLMLog("UOM Error: Read file content type invalid, abort loading.") return } mutLRUMap = jsonResult resetMRUList() } catch { - vCLog("UOM Error: Unable to read file or parse the data, abort loading. Details: \(error)") + vCLMLog("UOM Error: Unable to read file or parse the data, abort loading. Details: \(error)") return } } @@ -271,7 +270,7 @@ extension LMAssembly.LMUserOverride { mutLRUMap.removeValue(forKey: mutLRUList[mutLRUList.endIndex - 1].key) mutLRUList.removeLast() } - vCLog("UOM: Observation finished with new observation: \(key)") + vCLMLog("UOM: Observation finished with new observation: \(key)") saveCallback?() ?? saveData() return } @@ -282,7 +281,7 @@ extension LMAssembly.LMUserOverride { ) mutLRUList.insert(theNeta, at: 0) mutLRUMap[key] = theNeta - vCLog("UOM: Observation finished with existing observation: \(key)") + vCLMLog("UOM: Observation finished with existing observation: \(key)") saveCallback?() ?? saveData() } } @@ -400,3 +399,10 @@ extension LMAssembly.LMUserOverride { return result } } + +struct UOMError: LocalizedError { + var rawValue: String + var errorDescription: String? { + NSLocalizedString("rawValue", comment: "") + } +} diff --git a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLMAssembly_Common.swift b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLMAssembly_Common.swift index bcce259e..d262e92e 100644 --- a/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLMAssembly_Common.swift +++ b/Packages/vChewing_LangModelAssembly/Sources/LangModelAssembly/vChewingLMAssembly_Common.swift @@ -7,7 +7,6 @@ // requirements defined in MIT License. import Foundation -import Shared import SQLite3 public enum LMAssembly { @@ -56,7 +55,7 @@ extension Array where Element == String { sqlite3_prepare_v2(ptrDB, strStmt, -1, &ptrStmt, nil) == SQLITE_OK && sqlite3_step(ptrStmt) == SQLITE_DONE } guard thisResult else { - vCLog("SQL Query Error. Statement: \(strStmt)") + vCLMLog("SQL Query Error. Statement: \(strStmt)") return false } } @@ -83,3 +82,13 @@ func performStatementSansResult(_ handler: (inout OpaquePointer?) -> Void) { } handler(&ptrStmt) } + +func vCLMLog(_ strPrint: StringLiteralType) { + guard let toLog = UserDefaults.standard.object(forKey: "_DebugMode") as? Bool else { + NSLog("vChewingDebug: %@", strPrint) + return + } + if toLog { + NSLog("vChewingDebug: %@", strPrint) + } +} diff --git a/Packages/vChewing_MainAssembly/Package.swift b/Packages/vChewing_MainAssembly/Package.swift index a10dde34..ed55f27e 100644 --- a/Packages/vChewing_MainAssembly/Package.swift +++ b/Packages/vChewing_MainAssembly/Package.swift @@ -19,7 +19,7 @@ let package = Package( .package(path: "../Qwertyyb_ShiftKeyUpChecker"), .package(path: "../vChewing_BrailleSputnik"), .package(path: "../vChewing_CandidateWindow"), - .package(path: "../vChewing_CocoaExtension"), + .package(path: "../vChewing_OSFrameworkImpl"), .package(path: "../vChewing_Hotenka"), .package(path: "../vChewing_IMKUtils"), .package(path: "../vChewing_KimoDataReader"), @@ -42,7 +42,7 @@ let package = Package( .product(name: "BrailleSputnik", package: "vChewing_BrailleSputnik"), .product(name: "BookmarkManager", package: "Jad_BookmarkManager"), .product(name: "CandidateWindow", package: "vChewing_CandidateWindow"), - .product(name: "CocoaExtension", package: "vChewing_CocoaExtension"), + .product(name: "OSFrameworkImpl", package: "vChewing_OSFrameworkImpl"), .product(name: "FolderMonitor", package: "DanielGalasko_FolderMonitor"), .product(name: "Hotenka", package: "vChewing_Hotenka"), .product(name: "IMKUtils", package: "vChewing_IMKUtils"), diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_HandleCandidate.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_HandleCandidate.swift index f9b61a34..a8bc9149 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_HandleCandidate.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_HandleCandidate.swift @@ -9,9 +9,9 @@ /// 該檔案乃輸入調度模組當中「用來規定在選字窗出現時的按鍵行為」的部分。 import CandidateWindow -import CocoaExtension import InputMethodKit import Megrez +import OSFrameworkImpl import Shared // MARK: - § 對選字狀態進行調度 (Handle Candidate State). diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_HandleStates.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_HandleStates.swift index 0dae302d..4ed6f668 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_HandleStates.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_HandleStates.swift @@ -1041,11 +1041,15 @@ extension InputHandler { let fullWidthResult = behaviorValue % 2 != 0 // 能被二整除的都是半形。 triagePrefs: switch (behaviorValue, isConsideredEmptyForNow) { case (2, _), (3, _), (4, false), (5, false): - currentLM.config.numPadFWHWStatus = fullWidthResult + currentLM.setOptions { config in + config.numPadFWHWStatus = fullWidthResult + } if handlePunctuation("_NumPad_\(inputText)") { return true } default: break triagePrefs // 包括 case 0 & 1。 } - currentLM.config.numPadFWHWStatus = nil + currentLM.setOptions { config in + config.numPadFWHWStatus = nil + } delegate.switchState(IMEState.ofEmpty()) let charToCommit = inputText.applyingTransformFW2HW(reverse: fullWidthResult) delegate.switchState(IMEState.ofCommitting(textToCommit: charToCommit)) diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_TriageInput.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_TriageInput.swift index 26d8da14..a0e90194 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_TriageInput.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/InputHandler/InputHandler_TriageInput.swift @@ -9,11 +9,11 @@ /// 該檔案乃輸入調度模組當中「用來規定當 IMK 接受按鍵訊號時且首次交給輸入調度模組處理時、 /// 輸入調度模組要率先處理」的部分。據此判斷是否需要將按鍵處理委派給其它成員函式。 -import CocoaExtension import IMKUtils import InputMethodKit import LangModelAssembly import Megrez +import OSFrameworkImpl import Shared // MARK: - § 根據狀態調度按鍵輸入 (Handle Input with States) * Triage diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Core.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Core.swift index 55c424aa..15d1a718 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Core.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/LangModelManager/LMMgr_Core.swift @@ -65,6 +65,11 @@ public class LMMgr { /// 載入磁帶資料。 /// - Remark: cassettePath() 會在輸入法停用磁帶時直接返回 public static func loadCassetteData() { + func validateCassetteCandidateKey(_ target: String) -> Bool { + CandidateKey.validate(keys: target) == nil + } + + LMAssembly.LMInstantiator.setCassetCandidateKeyValidator(validateCassetteCandidateKey) LMAssembly.LMInstantiator.loadCassetteData(path: cassettePath()) } diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/SecurityAgentHelper.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/SecurityAgentHelper.swift index 83f7ffc7..8e0abe95 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/SecurityAgentHelper.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/SecurityAgentHelper.swift @@ -8,7 +8,7 @@ import AppKit import Carbon -import CocoaExtension +import OSFrameworkImpl import Shared public class SecurityAgentHelper { diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/ServiceMenuEditor/VwrServiceMenuEditor.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/ServiceMenuEditor/VwrServiceMenuEditor.swift index ca475863..8586786c 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/ServiceMenuEditor/VwrServiceMenuEditor.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/ServiceMenuEditor/VwrServiceMenuEditor.swift @@ -7,8 +7,8 @@ // requirements defined in MIT License. import AppKit -import CocoaExtension import Foundation +import OSFrameworkImpl import Shared public class VwrServiceMenuEditor: NSViewController { diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Core.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Core.swift index 49c8f091..fdc9be83 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Core.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Core.swift @@ -7,10 +7,10 @@ // requirements defined in MIT License. import CandidateWindow -import CocoaExtension import IMKUtils import InputMethodKit import NotifierUI +import OSFrameworkImpl import PopupCompositionBuffer import Shared import ShiftKeyUpChecker diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_HandleEvent.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_HandleEvent.swift index 9867f313..ebe1d0d0 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_HandleEvent.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_HandleEvent.swift @@ -6,10 +6,10 @@ // marks, or product names of Contributor, except as required to fulfill notice // requirements defined in MIT License. -import CocoaExtension import IMKUtils import InputMethodKit import NotifierUI +import OSFrameworkImpl import Shared import SwiftyCapsLockToggler diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Menu.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Menu.swift index 69e09788..9ac744fd 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Menu.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/SessionController/SessionCtl_Menu.swift @@ -7,8 +7,8 @@ // requirements defined in MIT License. import AppKit -import CocoaExtension import NotifierUI +import OSFrameworkImpl import Shared import SwiftExtension diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsCocoa/VwrSettingsPaneCocoaDictionary.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsCocoa/VwrSettingsPaneCocoaDictionary.swift index 57f2d1ac..6077d9c5 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsCocoa/VwrSettingsPaneCocoaDictionary.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsCocoa/VwrSettingsPaneCocoaDictionary.swift @@ -8,8 +8,8 @@ import AppKit import BookmarkManager -import CocoaExtension import Foundation +import OSFrameworkImpl import Shared public extension SettingsPanesCocoa { diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsUI/VwrSettingsPaneCassette.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsUI/VwrSettingsPaneCassette.swift index 42c6e4e6..18d10c5a 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsUI/VwrSettingsPaneCassette.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsUI/VwrSettingsPaneCassette.swift @@ -7,8 +7,8 @@ // requirements defined in MIT License. import BookmarkManager +import OSFrameworkImpl import Shared -import SwiftExtension import SwiftUI @available(macOS 13, *) diff --git a/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsUI/VwrSettingsPaneDictionary.swift b/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsUI/VwrSettingsPaneDictionary.swift index 70d3a438..957706ec 100644 --- a/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsUI/VwrSettingsPaneDictionary.swift +++ b/Packages/vChewing_MainAssembly/Sources/MainAssembly/Settings/SettingsUI/VwrSettingsPaneDictionary.swift @@ -7,7 +7,7 @@ // requirements defined in MIT License. import BookmarkManager -import CocoaExtension +import OSFrameworkImpl import Shared import SwiftExtension import SwiftUI diff --git a/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/CandidateServiceCoordinatorTests.swift b/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/CandidateServiceCoordinatorTests.swift index 1e7a64c3..1746a929 100644 --- a/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/CandidateServiceCoordinatorTests.swift +++ b/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/CandidateServiceCoordinatorTests.swift @@ -6,10 +6,10 @@ // marks, or product names of Contributor, except as required to fulfill notice // requirements defined in MIT License. -import CocoaExtension import InputMethodKit import LangModelAssembly @testable import MainAssembly +import OSFrameworkImpl import Shared import XCTest diff --git a/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Core.swift b/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Core.swift index 60845c4c..609196d3 100644 --- a/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Core.swift +++ b/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Core.swift @@ -6,10 +6,10 @@ // marks, or product names of Contributor, except as required to fulfill notice // requirements defined in MIT License. -import CocoaExtension import InputMethodKit import LangModelAssembly @testable import MainAssembly +import OSFrameworkImpl import Shared import XCTest diff --git a/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Test1.swift b/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Test1.swift index 262a4ab6..2ef67bbf 100644 --- a/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Test1.swift +++ b/Packages/vChewing_MainAssembly/Tests/MainAssemblyTests/MainAssemblyTests_Test1.swift @@ -6,10 +6,10 @@ // marks, or product names of Contributor, except as required to fulfill notice // requirements defined in MIT License. -import CocoaExtension import InputMethodKit import LangModelAssembly @testable import MainAssembly +import OSFrameworkImpl import Shared import XCTest diff --git a/Packages/vChewing_NotifierUI/Package.swift b/Packages/vChewing_NotifierUI/Package.swift index 529a6df8..8b69b4ce 100644 --- a/Packages/vChewing_NotifierUI/Package.swift +++ b/Packages/vChewing_NotifierUI/Package.swift @@ -13,13 +13,13 @@ let package = Package( ), ], dependencies: [ - .package(path: "../vChewing_CocoaExtension"), + .package(path: "../vChewing_OSFrameworkImpl"), ], targets: [ .target( name: "NotifierUI", dependencies: [ - .product(name: "CocoaExtension", package: "vChewing_CocoaExtension"), + .product(name: "OSFrameworkImpl", package: "vChewing_OSFrameworkImpl"), ] ), ] diff --git a/Packages/vChewing_NotifierUI/Sources/NotifierUI/NotifierUI.swift b/Packages/vChewing_NotifierUI/Sources/NotifierUI/NotifierUI.swift index b244df3e..09656234 100644 --- a/Packages/vChewing_NotifierUI/Sources/NotifierUI/NotifierUI.swift +++ b/Packages/vChewing_NotifierUI/Sources/NotifierUI/NotifierUI.swift @@ -7,7 +7,7 @@ // requirements defined in MIT License. import AppKit -import CocoaExtension +import OSFrameworkImpl public class Notifier: NSWindowController { public static func notify(message: String) { diff --git a/Packages/vChewing_CocoaExtension/.gitignore b/Packages/vChewing_OSFrameworkImpl/.gitignore similarity index 100% rename from Packages/vChewing_CocoaExtension/.gitignore rename to Packages/vChewing_OSFrameworkImpl/.gitignore diff --git a/Packages/vChewing_CocoaExtension/Package.swift b/Packages/vChewing_OSFrameworkImpl/Package.swift similarity index 75% rename from Packages/vChewing_CocoaExtension/Package.swift rename to Packages/vChewing_OSFrameworkImpl/Package.swift index 64bf2fa8..3659d6be 100644 --- a/Packages/vChewing_CocoaExtension/Package.swift +++ b/Packages/vChewing_OSFrameworkImpl/Package.swift @@ -2,14 +2,14 @@ import PackageDescription let package = Package( - name: "CocoaExtension", + name: "OSFrameworkImpl", platforms: [ .macOS(.v11), ], products: [ .library( - name: "CocoaExtension", - targets: ["CocoaExtension"] + name: "OSFrameworkImpl", + targets: ["OSFrameworkImpl"] ), ], dependencies: [ @@ -17,7 +17,7 @@ let package = Package( ], targets: [ .target( - name: "CocoaExtension", + name: "OSFrameworkImpl", dependencies: [ .product(name: "SwiftExtension", package: "vChewing_SwiftExtension"), ] diff --git a/Packages/vChewing_CocoaExtension/README.md b/Packages/vChewing_OSFrameworkImpl/README.md similarity index 96% rename from Packages/vChewing_CocoaExtension/README.md rename to Packages/vChewing_OSFrameworkImpl/README.md index 514c6144..228a5522 100644 --- a/Packages/vChewing_CocoaExtension/README.md +++ b/Packages/vChewing_OSFrameworkImpl/README.md @@ -1,4 +1,4 @@ -# CocoaExtension +# OSFrameworkImpl 威注音輸入法針對 Cocoa 的一些功能擴充,使程式維護體驗更佳。 diff --git a/Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_Misc.swift b/Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/AppKitImpl/AppKitImpl_Misc.swift similarity index 96% rename from Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_Misc.swift rename to Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/AppKitImpl/AppKitImpl_Misc.swift index b7054a87..421972dd 100644 --- a/Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_Misc.swift +++ b/Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/AppKitImpl/AppKitImpl_Misc.swift @@ -210,19 +210,6 @@ public extension NSApplication { } } -// MARK: - String.applyingTransform - -public extension String { - func applyingTransformFW2HW(reverse: Bool) -> String { - if #available(macOS 10.11, *) { - return applyingTransform(.fullwidthToHalfwidth, reverse: reverse) ?? self - } - let theString = NSMutableString(string: self) - CFStringTransform(theString, nil, kCFStringTransformFullwidthHalfwidth, reverse) - return theString as String - } -} - // MARK: - Check whether current date is the given date. public extension Date { diff --git a/Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_NSSound.swift b/Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/AppKitImpl/AppKitImpl_NSSound.swift similarity index 100% rename from Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_NSSound.swift rename to Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/AppKitImpl/AppKitImpl_NSSound.swift diff --git a/Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_NSView.swift b/Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/AppKitImpl/AppKitImpl_NSView.swift similarity index 100% rename from Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_NSView.swift rename to Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/AppKitImpl/AppKitImpl_NSView.swift diff --git a/Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_NSWindowController.swift b/Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/AppKitImpl/AppKitImpl_NSWindowController.swift similarity index 100% rename from Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_NSWindowController.swift rename to Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/AppKitImpl/AppKitImpl_NSWindowController.swift diff --git a/Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_NSWindowPositioner.swift b/Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/AppKitImpl/AppKitImpl_NSWindowPositioner.swift similarity index 100% rename from Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_NSWindowPositioner.swift rename to Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/AppKitImpl/AppKitImpl_NSWindowPositioner.swift diff --git a/Packages/vChewing_CocoaExtension/Sources/CocoaExtension/SecureEventInputSputnik.swift b/Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/SecureEventInputSputnik.swift similarity index 100% rename from Packages/vChewing_CocoaExtension/Sources/CocoaExtension/SecureEventInputSputnik.swift rename to Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/SecureEventInputSputnik.swift diff --git a/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftUIExtension.swift b/Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/SwiftUIImpl.swift similarity index 99% rename from Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftUIExtension.swift rename to Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/SwiftUIImpl.swift index 3251ae4a..bb02f96d 100644 --- a/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftUIExtension.swift +++ b/Packages/vChewing_OSFrameworkImpl/Sources/OSFrameworkImpl/SwiftUIImpl.swift @@ -6,6 +6,7 @@ // marks, or product names of Contributor, except as required to fulfill notice // requirements defined in MIT License. +import SwiftExtension import SwiftUI // MARK: - Add "didChange" support to bindings. diff --git a/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorUI.swift b/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorUI.swift index 81191cf0..e65c7df3 100644 --- a/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorUI.swift +++ b/Packages/vChewing_PhraseEditorUI/Sources/PhraseEditorUI/PhraseEditorUI.swift @@ -10,6 +10,7 @@ import AppKit import Combine import Foundation import LangModelAssembly +import OSFrameworkImpl import Shared import SwiftExtension import SwiftUI diff --git a/Packages/vChewing_PinyinPhonaConverter/.gitignore b/Packages/vChewing_PinyinPhonaConverter/.gitignore deleted file mode 100644 index 3b298120..00000000 --- a/Packages/vChewing_PinyinPhonaConverter/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -.DS_Store -/.build -/Packages -/*.xcodeproj -xcuserdata/ -DerivedData/ -.swiftpm/config/registries.json -.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata -.netrc diff --git a/Packages/vChewing_PinyinPhonaConverter/Package.swift b/Packages/vChewing_PinyinPhonaConverter/Package.swift deleted file mode 100644 index 59aac5f3..00000000 --- a/Packages/vChewing_PinyinPhonaConverter/Package.swift +++ /dev/null @@ -1,22 +0,0 @@ -// swift-tools-version:5.3 -import PackageDescription - -let package = Package( - name: "PinyinPhonaConverter", - platforms: [ - .macOS(.v11), - ], - products: [ - .library( - name: "PinyinPhonaConverter", - targets: ["PinyinPhonaConverter"] - ), - ], - dependencies: [], - targets: [ - .target( - name: "PinyinPhonaConverter", - dependencies: [] - ), - ] -) diff --git a/Packages/vChewing_PinyinPhonaConverter/README.md b/Packages/vChewing_PinyinPhonaConverter/README.md deleted file mode 100644 index b871fc93..00000000 --- a/Packages/vChewing_PinyinPhonaConverter/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# PinyinPhonaConverter - -拼音轉注音模組。因為太耽誤編譯時間,所以單獨拿出來寫了一個給 LangModelAssembly 專用的版本。 - -``` -// (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. -``` diff --git a/Packages/vChewing_PinyinPhonaConverter/Sources/PinyinPhonaConverter/PinyinPhonaConverter.swift b/Packages/vChewing_PinyinPhonaConverter/Sources/PinyinPhonaConverter/PinyinPhonaConverter.swift deleted file mode 100644 index 2b3f34ab..00000000 --- a/Packages/vChewing_PinyinPhonaConverter/Sources/PinyinPhonaConverter/PinyinPhonaConverter.swift +++ /dev/null @@ -1,92 +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 AppKit - -public extension String { - mutating func convertToPhonabets(newToneOne: String = "") { - if isEmpty || contains("_") || !isNotPureAlphanumerical { return } - for key in arrHanyuPinyinToPhonabets { - self = replacingOccurrences(of: key.0, with: key.1) - } - self = replacingOccurrences(of: " ", with: newToneOne) - } -} - -/// 檢測字串是否包含半形英數內容 -private extension String { - var isNotPureAlphanumerical: Bool { - let regex = ".*[^A-Za-z0-9].*" - let testString = NSPredicate(format: "SELF MATCHES %@", regex) - return testString.evaluate(with: self) - } -} - -private let arrHanyuPinyinToPhonabets: [(String, String)] = [ - ("chuang", "ㄔㄨㄤ"), ("shuang", "ㄕㄨㄤ"), ("zhuang", "ㄓㄨㄤ"), ("chang", "ㄔㄤ"), ("cheng", "ㄔㄥ"), ("chong", "ㄔㄨㄥ"), - ("chuai", "ㄔㄨㄞ"), ("chuan", "ㄔㄨㄢ"), ("guang", "ㄍㄨㄤ"), ("huang", "ㄏㄨㄤ"), ("jiang", "ㄐㄧㄤ"), ("jiong", "ㄐㄩㄥ"), - ("kiang", "ㄎㄧㄤ"), ("kuang", "ㄎㄨㄤ"), ("biang", "ㄅㄧㄤ"), ("duang", "ㄉㄨㄤ"), ("liang", "ㄌㄧㄤ"), ("niang", "ㄋㄧㄤ"), - ("qiang", "ㄑㄧㄤ"), ("qiong", "ㄑㄩㄥ"), ("shang", "ㄕㄤ"), ("sheng", "ㄕㄥ"), ("shuai", "ㄕㄨㄞ"), ("shuan", "ㄕㄨㄢ"), - ("xiang", "ㄒㄧㄤ"), ("xiong", "ㄒㄩㄥ"), ("zhang", "ㄓㄤ"), ("zheng", "ㄓㄥ"), ("zhong", "ㄓㄨㄥ"), ("zhuai", "ㄓㄨㄞ"), - ("zhuan", "ㄓㄨㄢ"), ("bang", "ㄅㄤ"), ("beng", "ㄅㄥ"), ("bian", "ㄅㄧㄢ"), ("biao", "ㄅㄧㄠ"), ("bing", "ㄅㄧㄥ"), ("cang", "ㄘㄤ"), - ("ceng", "ㄘㄥ"), ("chai", "ㄔㄞ"), ("chan", "ㄔㄢ"), ("chao", "ㄔㄠ"), ("chen", "ㄔㄣ"), ("chou", "ㄔㄡ"), ("chua", "ㄔㄨㄚ"), - ("chui", "ㄔㄨㄟ"), ("chun", "ㄔㄨㄣ"), ("chuo", "ㄔㄨㄛ"), ("cong", "ㄘㄨㄥ"), ("cuan", "ㄘㄨㄢ"), ("dang", "ㄉㄤ"), ("deng", "ㄉㄥ"), - ("dian", "ㄉㄧㄢ"), ("diao", "ㄉㄧㄠ"), ("ding", "ㄉㄧㄥ"), ("dong", "ㄉㄨㄥ"), ("duan", "ㄉㄨㄢ"), ("fang", "ㄈㄤ"), ("feng", "ㄈㄥ"), - ("fiao", "ㄈㄧㄠ"), ("fong", "ㄈㄨㄥ"), ("gang", "ㄍㄤ"), ("geng", "ㄍㄥ"), ("giao", "ㄍㄧㄠ"), ("gong", "ㄍㄨㄥ"), ("guai", "ㄍㄨㄞ"), - ("guan", "ㄍㄨㄢ"), ("hang", "ㄏㄤ"), ("heng", "ㄏㄥ"), ("hong", "ㄏㄨㄥ"), ("huai", "ㄏㄨㄞ"), ("huan", "ㄏㄨㄢ"), ("jian", "ㄐㄧㄢ"), - ("jiao", "ㄐㄧㄠ"), ("jing", "ㄐㄧㄥ"), ("juan", "ㄐㄩㄢ"), ("kang", "ㄎㄤ"), ("keng", "ㄎㄥ"), ("kong", "ㄎㄨㄥ"), ("kuai", "ㄎㄨㄞ"), - ("kuan", "ㄎㄨㄢ"), ("lang", "ㄌㄤ"), ("leng", "ㄌㄥ"), ("lian", "ㄌㄧㄢ"), ("liao", "ㄌㄧㄠ"), ("ling", "ㄌㄧㄥ"), ("long", "ㄌㄨㄥ"), - ("luan", "ㄌㄨㄢ"), ("lvan", "ㄌㄩㄢ"), ("mang", "ㄇㄤ"), ("meng", "ㄇㄥ"), ("mian", "ㄇㄧㄢ"), ("miao", "ㄇㄧㄠ"), ("ming", "ㄇㄧㄥ"), - ("nang", "ㄋㄤ"), ("neng", "ㄋㄥ"), ("nian", "ㄋㄧㄢ"), ("niao", "ㄋㄧㄠ"), ("ning", "ㄋㄧㄥ"), ("nong", "ㄋㄨㄥ"), ("nuan", "ㄋㄨㄢ"), - ("pang", "ㄆㄤ"), ("peng", "ㄆㄥ"), ("pian", "ㄆㄧㄢ"), ("piao", "ㄆㄧㄠ"), ("ping", "ㄆㄧㄥ"), ("qian", "ㄑㄧㄢ"), ("qiao", "ㄑㄧㄠ"), - ("qing", "ㄑㄧㄥ"), ("quan", "ㄑㄩㄢ"), ("rang", "ㄖㄤ"), ("reng", "ㄖㄥ"), ("rong", "ㄖㄨㄥ"), ("ruan", "ㄖㄨㄢ"), ("sang", "ㄙㄤ"), - ("seng", "ㄙㄥ"), ("shai", "ㄕㄞ"), ("shan", "ㄕㄢ"), ("shao", "ㄕㄠ"), ("shei", "ㄕㄟ"), ("shen", "ㄕㄣ"), ("shou", "ㄕㄡ"), - ("shua", "ㄕㄨㄚ"), ("shui", "ㄕㄨㄟ"), ("shun", "ㄕㄨㄣ"), ("shuo", "ㄕㄨㄛ"), ("song", "ㄙㄨㄥ"), ("suan", "ㄙㄨㄢ"), ("tang", "ㄊㄤ"), - ("teng", "ㄊㄥ"), ("tian", "ㄊㄧㄢ"), ("tiao", "ㄊㄧㄠ"), ("ting", "ㄊㄧㄥ"), ("tong", "ㄊㄨㄥ"), ("tuan", "ㄊㄨㄢ"), ("wang", "ㄨㄤ"), - ("weng", "ㄨㄥ"), ("xian", "ㄒㄧㄢ"), ("xiao", "ㄒㄧㄠ"), ("xing", "ㄒㄧㄥ"), ("xuan", "ㄒㄩㄢ"), ("yang", "ㄧㄤ"), ("ying", "ㄧㄥ"), - ("yong", "ㄩㄥ"), ("yuan", "ㄩㄢ"), ("zang", "ㄗㄤ"), ("zeng", "ㄗㄥ"), ("zhai", "ㄓㄞ"), ("zhan", "ㄓㄢ"), ("zhao", "ㄓㄠ"), - ("zhei", "ㄓㄟ"), ("zhen", "ㄓㄣ"), ("zhou", "ㄓㄡ"), ("zhua", "ㄓㄨㄚ"), ("zhui", "ㄓㄨㄟ"), ("zhun", "ㄓㄨㄣ"), ("zhuo", "ㄓㄨㄛ"), - ("zong", "ㄗㄨㄥ"), ("zuan", "ㄗㄨㄢ"), ("jun", "ㄐㄩㄣ"), ("ang", "ㄤ"), ("bai", "ㄅㄞ"), ("ban", "ㄅㄢ"), ("bao", "ㄅㄠ"), - ("bei", "ㄅㄟ"), ("ben", "ㄅㄣ"), ("bie", "ㄅㄧㄝ"), ("bin", "ㄅㄧㄣ"), ("cai", "ㄘㄞ"), ("can", "ㄘㄢ"), ("cao", "ㄘㄠ"), - ("cei", "ㄘㄟ"), ("cen", "ㄘㄣ"), ("cha", "ㄔㄚ"), ("che", "ㄔㄜ"), ("chi", "ㄔ"), ("chu", "ㄔㄨ"), ("cou", "ㄘㄡ"), - ("cui", "ㄘㄨㄟ"), ("cun", "ㄘㄨㄣ"), ("cuo", "ㄘㄨㄛ"), ("dai", "ㄉㄞ"), ("dan", "ㄉㄢ"), ("dao", "ㄉㄠ"), ("dei", "ㄉㄟ"), - ("den", "ㄉㄣ"), ("dia", "ㄉㄧㄚ"), ("die", "ㄉㄧㄝ"), ("diu", "ㄉㄧㄡ"), ("dou", "ㄉㄡ"), ("dui", "ㄉㄨㄟ"), ("dun", "ㄉㄨㄣ"), - ("duo", "ㄉㄨㄛ"), ("eng", "ㄥ"), ("fan", "ㄈㄢ"), ("fei", "ㄈㄟ"), ("fen", "ㄈㄣ"), ("fou", "ㄈㄡ"), ("gai", "ㄍㄞ"), - ("gan", "ㄍㄢ"), ("gao", "ㄍㄠ"), ("gei", "ㄍㄟ"), ("gin", "ㄍㄧㄣ"), ("gen", "ㄍㄣ"), ("gou", "ㄍㄡ"), ("gua", "ㄍㄨㄚ"), - ("gue", "ㄍㄨㄜ"), ("gui", "ㄍㄨㄟ"), ("gun", "ㄍㄨㄣ"), ("guo", "ㄍㄨㄛ"), ("hai", "ㄏㄞ"), ("han", "ㄏㄢ"), ("hao", "ㄏㄠ"), - ("hei", "ㄏㄟ"), ("hen", "ㄏㄣ"), ("hou", "ㄏㄡ"), ("hua", "ㄏㄨㄚ"), ("hui", "ㄏㄨㄟ"), ("hun", "ㄏㄨㄣ"), ("huo", "ㄏㄨㄛ"), - ("jia", "ㄐㄧㄚ"), ("jie", "ㄐㄧㄝ"), ("jin", "ㄐㄧㄣ"), ("jiu", "ㄐㄧㄡ"), ("jue", "ㄐㄩㄝ"), ("kai", "ㄎㄞ"), ("kan", "ㄎㄢ"), - ("kao", "ㄎㄠ"), ("ken", "ㄎㄣ"), ("kiu", "ㄎㄧㄡ"), ("kou", "ㄎㄡ"), ("kua", "ㄎㄨㄚ"), ("kui", "ㄎㄨㄟ"), ("kun", "ㄎㄨㄣ"), - ("kuo", "ㄎㄨㄛ"), ("lai", "ㄌㄞ"), ("lan", "ㄌㄢ"), ("lao", "ㄌㄠ"), ("lei", "ㄌㄟ"), ("lia", "ㄌㄧㄚ"), ("lie", "ㄌㄧㄝ"), - ("lin", "ㄌㄧㄣ"), ("liu", "ㄌㄧㄡ"), ("lou", "ㄌㄡ"), ("lun", "ㄌㄨㄣ"), ("luo", "ㄌㄨㄛ"), ("lve", "ㄌㄩㄝ"), ("mai", "ㄇㄞ"), - ("man", "ㄇㄢ"), ("mao", "ㄇㄠ"), ("mei", "ㄇㄟ"), ("men", "ㄇㄣ"), ("mie", "ㄇㄧㄝ"), ("min", "ㄇㄧㄣ"), ("miu", "ㄇㄧㄡ"), - ("mou", "ㄇㄡ"), ("nai", "ㄋㄞ"), ("nan", "ㄋㄢ"), ("nao", "ㄋㄠ"), ("nei", "ㄋㄟ"), ("nen", "ㄋㄣ"), ("nie", "ㄋㄧㄝ"), - ("nin", "ㄋㄧㄣ"), ("niu", "ㄋㄧㄡ"), ("nou", "ㄋㄡ"), ("nui", "ㄋㄨㄟ"), ("nun", "ㄋㄨㄣ"), ("nuo", "ㄋㄨㄛ"), ("nve", "ㄋㄩㄝ"), - ("pai", "ㄆㄞ"), ("pan", "ㄆㄢ"), ("pao", "ㄆㄠ"), ("pei", "ㄆㄟ"), ("pen", "ㄆㄣ"), ("pia", "ㄆㄧㄚ"), ("pie", "ㄆㄧㄝ"), - ("pin", "ㄆㄧㄣ"), ("pou", "ㄆㄡ"), ("qia", "ㄑㄧㄚ"), ("qie", "ㄑㄧㄝ"), ("qin", "ㄑㄧㄣ"), ("qiu", "ㄑㄧㄡ"), ("que", "ㄑㄩㄝ"), - ("qun", "ㄑㄩㄣ"), ("ran", "ㄖㄢ"), ("rao", "ㄖㄠ"), ("ren", "ㄖㄣ"), ("rou", "ㄖㄡ"), ("rui", "ㄖㄨㄟ"), ("run", "ㄖㄨㄣ"), - ("ruo", "ㄖㄨㄛ"), ("sai", "ㄙㄞ"), ("san", "ㄙㄢ"), ("sao", "ㄙㄠ"), ("sei", "ㄙㄟ"), ("sen", "ㄙㄣ"), ("sha", "ㄕㄚ"), - ("she", "ㄕㄜ"), ("shi", "ㄕ"), ("shu", "ㄕㄨ"), ("sou", "ㄙㄡ"), ("sui", "ㄙㄨㄟ"), ("sun", "ㄙㄨㄣ"), ("suo", "ㄙㄨㄛ"), - ("tai", "ㄊㄞ"), ("tan", "ㄊㄢ"), ("tao", "ㄊㄠ"), ("tie", "ㄊㄧㄝ"), ("tou", "ㄊㄡ"), ("tui", "ㄊㄨㄟ"), ("tun", "ㄊㄨㄣ"), - ("tuo", "ㄊㄨㄛ"), ("wai", "ㄨㄞ"), ("wan", "ㄨㄢ"), ("wei", "ㄨㄟ"), ("wen", "ㄨㄣ"), ("xia", "ㄒㄧㄚ"), ("xie", "ㄒㄧㄝ"), - ("xin", "ㄒㄧㄣ"), ("xiu", "ㄒㄧㄡ"), ("xue", "ㄒㄩㄝ"), ("xun", "ㄒㄩㄣ"), ("yai", "ㄧㄞ"), ("yan", "ㄧㄢ"), ("yao", "ㄧㄠ"), - ("yin", "ㄧㄣ"), ("you", "ㄧㄡ"), ("yue", "ㄩㄝ"), ("yun", "ㄩㄣ"), ("zai", "ㄗㄞ"), ("zan", "ㄗㄢ"), ("zao", "ㄗㄠ"), - ("zei", "ㄗㄟ"), ("zen", "ㄗㄣ"), ("zha", "ㄓㄚ"), ("zhe", "ㄓㄜ"), ("zhi", "ㄓ"), ("zhu", "ㄓㄨ"), ("zou", "ㄗㄡ"), - ("zui", "ㄗㄨㄟ"), ("zun", "ㄗㄨㄣ"), ("zuo", "ㄗㄨㄛ"), ("ai", "ㄞ"), ("an", "ㄢ"), ("ao", "ㄠ"), ("ba", "ㄅㄚ"), ("bi", "ㄅㄧ"), - ("bo", "ㄅㄛ"), ("bu", "ㄅㄨ"), ("ca", "ㄘㄚ"), ("ce", "ㄘㄜ"), ("ci", "ㄘ"), ("cu", "ㄘㄨ"), ("da", "ㄉㄚ"), ("de", "ㄉㄜ"), - ("di", "ㄉㄧ"), ("du", "ㄉㄨ"), ("eh", "ㄝ"), ("ei", "ㄟ"), ("en", "ㄣ"), ("er", "ㄦ"), ("fa", "ㄈㄚ"), ("fo", "ㄈㄛ"), - ("fu", "ㄈㄨ"), ("ga", "ㄍㄚ"), ("ge", "ㄍㄜ"), ("gi", "ㄍㄧ"), ("gu", "ㄍㄨ"), ("ha", "ㄏㄚ"), ("he", "ㄏㄜ"), ("hu", "ㄏㄨ"), - ("ji", "ㄐㄧ"), ("ju", "ㄐㄩ"), ("ka", "ㄎㄚ"), ("ke", "ㄎㄜ"), ("ku", "ㄎㄨ"), ("la", "ㄌㄚ"), ("le", "ㄌㄜ"), ("li", "ㄌㄧ"), - ("lo", "ㄌㄛ"), ("lu", "ㄌㄨ"), ("lv", "ㄌㄩ"), ("ma", "ㄇㄚ"), ("me", "ㄇㄜ"), ("mi", "ㄇㄧ"), ("mo", "ㄇㄛ"), ("mu", "ㄇㄨ"), - ("na", "ㄋㄚ"), ("ne", "ㄋㄜ"), ("ni", "ㄋㄧ"), ("nu", "ㄋㄨ"), ("nv", "ㄋㄩ"), ("ou", "ㄡ"), ("pa", "ㄆㄚ"), ("pi", "ㄆㄧ"), - ("po", "ㄆㄛ"), ("pu", "ㄆㄨ"), ("qi", "ㄑㄧ"), ("qu", "ㄑㄩ"), ("re", "ㄖㄜ"), ("ri", "ㄖ"), ("ru", "ㄖㄨ"), ("sa", "ㄙㄚ"), - ("se", "ㄙㄜ"), ("si", "ㄙ"), ("su", "ㄙㄨ"), ("ta", "ㄊㄚ"), ("te", "ㄊㄜ"), ("ti", "ㄊㄧ"), ("tu", "ㄊㄨ"), ("wa", "ㄨㄚ"), - ("wo", "ㄨㄛ"), ("wu", "ㄨ"), ("xi", "ㄒㄧ"), ("xu", "ㄒㄩ"), ("ya", "ㄧㄚ"), ("ye", "ㄧㄝ"), ("yi", "ㄧ"), ("yo", "ㄧㄛ"), - ("yu", "ㄩ"), ("za", "ㄗㄚ"), ("ze", "ㄗㄜ"), ("zi", "ㄗ"), ("zu", "ㄗㄨ"), ("a", "ㄚ"), ("e", "ㄜ"), ("o", "ㄛ"), ("q", "ㄑ"), - ("1", " "), ("2", "ˊ"), ("3", "ˇ"), ("4", "ˋ"), ("5", "˙"), -] diff --git a/Packages/vChewing_Shared/Package.swift b/Packages/vChewing_Shared/Package.swift index a78a3d4d..d2839693 100644 --- a/Packages/vChewing_Shared/Package.swift +++ b/Packages/vChewing_Shared/Package.swift @@ -13,7 +13,7 @@ let package = Package( ), ], dependencies: [ - .package(path: "../vChewing_CocoaExtension"), + .package(path: "../vChewing_OSFrameworkImpl"), .package(path: "../vChewing_IMKUtils"), .package(path: "../vChewing_SwiftExtension"), ], @@ -21,7 +21,7 @@ let package = Package( .target( name: "Shared", dependencies: [ - .product(name: "CocoaExtension", package: "vChewing_CocoaExtension"), + .product(name: "OSFrameworkImpl", package: "vChewing_OSFrameworkImpl"), .product(name: "IMKUtils", package: "vChewing_IMKUtils"), .product(name: "SwiftExtension", package: "vChewing_SwiftExtension"), ] diff --git a/Packages/vChewing_Shared/Sources/Shared/Broadcaster.swift b/Packages/vChewing_Shared/Sources/Shared/Broadcaster.swift index e9ae798f..837d9d31 100644 --- a/Packages/vChewing_Shared/Sources/Shared/Broadcaster.swift +++ b/Packages/vChewing_Shared/Sources/Shared/Broadcaster.swift @@ -8,7 +8,7 @@ // marks, or product names of Contributor, except as required to fulfill notice // requirements defined in MIT License. -import AppKit +import Foundation @objcMembers public class Broadcaster: NSObject { public static var shared = Broadcaster() diff --git a/Packages/vChewing_Shared/Sources/Shared/CandidateNode.swift b/Packages/vChewing_Shared/Sources/Shared/CandidateNode.swift index 166cbec3..974d7604 100644 --- a/Packages/vChewing_Shared/Sources/Shared/CandidateNode.swift +++ b/Packages/vChewing_Shared/Sources/Shared/CandidateNode.swift @@ -6,8 +6,6 @@ // marks, or product names of Contributor, except as required to fulfill notice // requirements defined in MIT License. -import Foundation - open class CandidateNode { public var name: String public var members: [CandidateNode] diff --git a/Packages/vChewing_Shared/Sources/Shared/CandidateNode_ServiceImpl.swift b/Packages/vChewing_Shared/Sources/Shared/CandidateNode_ServiceImpl.swift index ff0ea009..569d1f6c 100644 --- a/Packages/vChewing_Shared/Sources/Shared/CandidateNode_ServiceImpl.swift +++ b/Packages/vChewing_Shared/Sources/Shared/CandidateNode_ServiceImpl.swift @@ -6,8 +6,6 @@ // marks, or product names of Contributor, except as required to fulfill notice // requirements defined in MIT License. -import Foundation - public extension CandidateNode { convenience init( name: String, services: [CandidateTextService], previous: CandidateNode? = nil diff --git a/Packages/vChewing_Shared/Sources/Shared/Protocols/InputSignalProtocol.swift b/Packages/vChewing_Shared/Sources/Shared/Protocols/InputSignalProtocol.swift index 3bc5e81f..7991c234 100644 --- a/Packages/vChewing_Shared/Sources/Shared/Protocols/InputSignalProtocol.swift +++ b/Packages/vChewing_Shared/Sources/Shared/Protocols/InputSignalProtocol.swift @@ -7,7 +7,7 @@ // requirements defined in MIT License. import AppKit -import CocoaExtension +import OSFrameworkImpl // MARK: - InputSignalProtocol diff --git a/Packages/vChewing_Shared/Sources/Shared/UserDef/UserDefRenderableCocoa.swift b/Packages/vChewing_Shared/Sources/Shared/UserDef/UserDefRenderableCocoa.swift index dd7e7302..7c5f8f79 100644 --- a/Packages/vChewing_Shared/Sources/Shared/UserDef/UserDefRenderableCocoa.swift +++ b/Packages/vChewing_Shared/Sources/Shared/UserDef/UserDefRenderableCocoa.swift @@ -9,9 +9,9 @@ // 這其實是 UserDefRenderable 的另一個版本,但用的是 AppKit 而非 SwiftUI。 import AppKit -import CocoaExtension import Foundation import IMKUtils +import OSFrameworkImpl public class UserDefRenderableCocoa: NSObject, Identifiable { public let def: UserDef diff --git a/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftExtension.swift b/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftExtension.swift index 587e5ea5..ee32fdf4 100644 --- a/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftExtension.swift +++ b/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftExtension.swift @@ -6,8 +6,6 @@ // marks, or product names of Contributor, except as required to fulfill notice // requirements defined in MIT License. -import Foundation - // MARK: - Bool Operators public func |= (lhs: inout Bool, rhs: Bool) { @@ -22,25 +20,11 @@ public func ^= (lhs: inout Bool, rhs: Bool) { lhs = lhs != rhs } -// MARK: - String.localized extension - -public extension StringLiteralType { - var localized: String { NSLocalizedString(description, comment: "") } -} - -// MARK: - Root Extensions +// MARK: - Root Extensions (deduplicated) // Extend the RangeReplaceableCollection to allow it clean duplicated characters. // Ref: https://stackoverflow.com/questions/25738817/ public extension RangeReplaceableCollection where Element: Hashable { - /// 使用 NSOrderedSet 處理 class 陣列的「去重複化」。 - var classDeduplicated: Self { - NSOrderedSet(array: Array(self)).compactMap { $0 as? Element.Type } as? Self ?? self - // 下述方法有 Bug 會在處理 KeyValuePaired 的時候崩掉,暫時停用。 - // var set = Set() - // return filter { set.insert($0).inserted } - } - /// 去重複化。 /// - Remark: 該方法不適合用來處理 class,除非該 class 遵循 Identifiable 協定。 var deduplicated: Self { @@ -49,22 +33,6 @@ public extension RangeReplaceableCollection where Element: Hashable { } } -// MARK: - String Tildes Expansion Extension - -public extension String { - var expandingTildeInPath: String { - (self as NSString).expandingTildeInPath - } -} - -// MARK: - String Localized Error Extension - -extension String: LocalizedError { - public var errorDescription: String? { - self - } -} - // MARK: - Ensuring trailing slash of a string public extension String { @@ -77,21 +45,6 @@ public extension String { // MARK: - CharCode printability check -// Ref: https://forums.swift.org/t/57085/5 -public extension UniChar { - var isPrintable: Bool { - guard Unicode.Scalar(UInt32(self)) != nil else { - struct NotAWholeScalar: Error {} - return false - } - return true - } - - var isPrintableASCII: Bool { - (32 ... 126).contains(self) - } -} - public extension Unicode.Scalar { var isPrintableASCII: Bool { (32 ... 126).contains(value) @@ -133,70 +86,23 @@ public extension Bool { } } -// MARK: - User Defaults Storage - -public extension UserDefaults { - // 內部標記,看輸入法是否處於測試模式。 - static var pendingUnitTests = false - - static var unitTests = UserDefaults(suiteName: "UnitTests") - - static var current: UserDefaults { - pendingUnitTests ? .unitTests ?? .standard : .standard - } -} - -// MARK: - Property Wrapper - -// Ref: https://www.avanderlee.com/swift/property-wrappers/ - -@propertyWrapper -public struct AppProperty { - public let key: String - public let defaultValue: Value - public var container: UserDefaults { .current } - public init(key: String, defaultValue: Value) { - self.key = key - self.defaultValue = defaultValue - if container.object(forKey: key) == nil { - container.set(defaultValue, forKey: key) - } - } - - public var wrappedValue: Value { - get { - container.object(forKey: key) as? Value ?? defaultValue - } - set { - container.set(newValue, forKey: key) - } - } -} - // MARK: - 引入小數點位數控制函式 // Ref: https://stackoverflow.com/a/32581409/4162914 public extension Double { func rounded(toPlaces places: Int) -> Double { - let divisor = pow(10.0, Double(places)) + let divisor = 10.0.mathPowered(by: places) return (self * divisor).rounded() / divisor } } -// MARK: - String RegReplace Extension - -// Ref: https://stackoverflow.com/a/40993403/4162914 && https://stackoverflow.com/a/71291137/4162914 -public extension String { - mutating func regReplace(pattern: String, replaceWith: String = "") { - do { - let regex = try NSRegularExpression( - pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines] - ) - let range = NSRange(startIndex..., in: self) - self = regex.stringByReplacingMatches( - in: self, options: [], range: range, withTemplate: replaceWith - ) - } catch { return } +public extension Double { + func mathPowered(by operand: Int) -> Double { + var target = self + for _ in 0 ..< operand { + target = target * target + } + return target } } @@ -236,26 +142,6 @@ public extension String { var withEllipsis: String { self + "…" } } -// MARK: - Localized String Extension for Integers and Floats - -public extension BinaryFloatingPoint { - func i18n(loc: String) -> String { - let formatter = NumberFormatter() - formatter.locale = Locale(identifier: loc) - formatter.numberStyle = .spellOut - return formatter.string(from: NSDecimalNumber(string: "\(self)")) ?? "" - } -} - -public extension BinaryInteger { - func i18n(loc: String) -> String { - let formatter = NumberFormatter() - formatter.locale = Locale(identifier: loc) - formatter.numberStyle = .spellOut - return formatter.string(from: NSDecimalNumber(string: "\(self)")) ?? "" - } -} - // MARK: - Index Revolver (only for Array) // Further discussion: https://forums.swift.org/t/62847 @@ -283,31 +169,6 @@ public extension Int { } } -// MARK: - Parse String As Hex Literal - -// Original author: Shiki Suen -// Refactored by: Isaac Xen - -public extension String { - func parsedAsHexLiteral(encoding: CFStringEncodings? = nil) -> String? { - guard !isEmpty else { return nil } - var charBytes = [Int8]() - var buffer: Int? - compactMap(\.hexDigitValue).forEach { neta in - if let validBuffer = buffer { - charBytes.append(.init(bitPattern: UInt8(validBuffer << 4 + neta))) - buffer = nil - } else { - buffer = neta - } - } - let encodingUBE = CFStringBuiltInEncodings.UTF16BE.rawValue - let encodingRAW = encoding.map { UInt32($0.rawValue) } ?? encodingUBE - let result = CFStringCreateWithCString(nil, &charBytes, encodingRAW) as String? - return result?.isEmpty ?? true ? nil : result - } -} - // MARK: - Overlap Checker (for two sets) public extension Set where Element: Hashable { @@ -340,32 +201,6 @@ public extension Array where Element: Hashable { } } -// MARK: - Version Comparer. - -public extension String { - /// ref: https://sarunw.com/posts/how-to-compare-two-app-version-strings-in-swift/ - func versionCompare(_ otherVersion: String) -> ComparisonResult { - let versionDelimiter = "." - - var versionComponents = components(separatedBy: versionDelimiter) // <1> - var otherVersionComponents = otherVersion.components(separatedBy: versionDelimiter) - - let zeroDiff = versionComponents.count - otherVersionComponents.count // <2> - - // <3> Compare normally if the formats are the same. - guard zeroDiff != 0 else { return compare(otherVersion, options: .numeric) } - - let zeros = Array(repeating: "0", count: abs(zeroDiff)) // <4> - if zeroDiff > 0 { - otherVersionComponents.append(contentsOf: zeros) // <5> - } else { - versionComponents.append(contentsOf: zeros) - } - return versionComponents.joined(separator: versionDelimiter) - .compare(otherVersionComponents.joined(separator: versionDelimiter), options: .numeric) // <6> - } -} - // MARK: - Array Builder. @resultBuilder @@ -419,3 +254,33 @@ public extension Comparable { return givenMap[returnableID] } } + +// MARK: - String.applyingTransform + +public extension String { + /// This only works with ASCII chars for now. + func applyingTransformFW2HW(reverse: Bool) -> String { + var arr: [Character] = map { $0 } + for i in 0 ..< arr.count { + let oldChar = arr[i] + guard oldChar.unicodeScalars.count == 1 else { continue } + guard let oldCodePoint = oldChar.unicodeScalars.first?.value else { continue } + if reverse { + guard oldChar.isASCII else { continue } + } else { + guard oldCodePoint > 0xFEE0 || oldCodePoint == 0x3000 else { continue } + } + var newCodePoint: Int32 = reverse ? (Int32(oldCodePoint) + 0xFEE0) : (Int32(oldCodePoint) - 0xFEE0) + checkSpace: switch (oldCodePoint, reverse) { + case (0x3000, false): newCodePoint = 0x20 + case (0x20, true): newCodePoint = 0x3000 + default: break checkSpace + } + guard newCodePoint > 0 else { continue } + guard let newScalar = Unicode.Scalar(UInt16(newCodePoint)) else { continue } + let newChar = Character(newScalar) + arr[i] = newChar + } + return String(arr) + } +} diff --git a/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftFoundationImpl.swift b/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftFoundationImpl.swift new file mode 100644 index 00000000..e1a74e5d --- /dev/null +++ b/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftFoundationImpl.swift @@ -0,0 +1,190 @@ +// (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 + +// MARK: - String.localized extension + +public extension StringLiteralType { + var localized: String { NSLocalizedString(description, comment: "") } +} + +// MARK: - Root Extensions (classDeduplicated) + +// Extend the RangeReplaceableCollection to allow it clean duplicated characters. +// Ref: https://stackoverflow.com/questions/25738817/ +public extension RangeReplaceableCollection where Element: Hashable { + /// 使用 NSOrderedSet 處理 class 陣列的「去重複化」。 + var classDeduplicated: Self { + NSOrderedSet(array: Array(self)).compactMap { $0 as? Element.Type } as? Self ?? self + // 下述方法有 Bug 會在處理 KeyValuePaired 的時候崩掉,暫時停用。 + // var set = Set() + // return filter { set.insert($0).inserted } + } +} + +// MARK: - String Tildes Expansion Extension + +public extension String { + var expandingTildeInPath: String { + (self as NSString).expandingTildeInPath + } +} + +// MARK: - String Localized Error Extension + +extension String: LocalizedError { + public var errorDescription: String? { + self + } +} + +// MARK: - CharCode printability check for UniChar (CoreFoundation) + +// Ref: https://forums.swift.org/t/57085/5 +public extension UniChar { + var isPrintable: Bool { + guard Unicode.Scalar(UInt32(self)) != nil else { + struct NotAWholeScalar: Error {} + return false + } + return true + } + + var isPrintableASCII: Bool { + (32 ... 126).contains(self) + } +} + +// MARK: - User Defaults Storage + +public extension UserDefaults { + // 內部標記,看輸入法是否處於測試模式。 + static var pendingUnitTests = false + + static var unitTests = UserDefaults(suiteName: "UnitTests") + + static var current: UserDefaults { + pendingUnitTests ? .unitTests ?? .standard : .standard + } +} + +// MARK: - Property Wrapper + +// Ref: https://www.avanderlee.com/swift/property-wrappers/ + +@propertyWrapper +public struct AppProperty { + public let key: String + public let defaultValue: Value + public var container: UserDefaults { .current } + public init(key: String, defaultValue: Value) { + self.key = key + self.defaultValue = defaultValue + if container.object(forKey: key) == nil { + container.set(defaultValue, forKey: key) + } + } + + public var wrappedValue: Value { + get { + container.object(forKey: key) as? Value ?? defaultValue + } + set { + container.set(newValue, forKey: key) + } + } +} + +// MARK: - String RegReplace Extension + +// Ref: https://stackoverflow.com/a/40993403/4162914 && https://stackoverflow.com/a/71291137/4162914 +public extension String { + mutating func regReplace(pattern: String, replaceWith: String = "") { + do { + let regex = try NSRegularExpression( + pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines] + ) + let range = NSRange(startIndex..., in: self) + self = regex.stringByReplacingMatches( + in: self, options: [], range: range, withTemplate: replaceWith + ) + } catch { return } + } +} + +// MARK: - Localized String Extension for Integers and Floats + +public extension BinaryFloatingPoint { + func i18n(loc: String) -> String { + let formatter = NumberFormatter() + formatter.locale = Locale(identifier: loc) + formatter.numberStyle = .spellOut + return formatter.string(from: NSDecimalNumber(string: "\(self)")) ?? "" + } +} + +public extension BinaryInteger { + func i18n(loc: String) -> String { + let formatter = NumberFormatter() + formatter.locale = Locale(identifier: loc) + formatter.numberStyle = .spellOut + return formatter.string(from: NSDecimalNumber(string: "\(self)")) ?? "" + } +} + +// MARK: - Parse String As Hex Literal + +// Original author: Shiki Suen +// Refactored by: Isaac Xen + +public extension String { + func parsedAsHexLiteral(encoding: CFStringEncodings? = nil) -> String? { + guard !isEmpty else { return nil } + var charBytes = [Int8]() + var buffer: Int? + compactMap(\.hexDigitValue).forEach { neta in + if let validBuffer = buffer { + charBytes.append(.init(bitPattern: UInt8(validBuffer << 4 + neta))) + buffer = nil + } else { + buffer = neta + } + } + let encodingUBE = CFStringBuiltInEncodings.UTF16BE.rawValue + let encodingRAW = encoding.map { UInt32($0.rawValue) } ?? encodingUBE + let result = CFStringCreateWithCString(nil, &charBytes, encodingRAW) as String? + return result?.isEmpty ?? true ? nil : result + } +} + +// MARK: - Version Comparer. + +public extension String { + /// ref: https://sarunw.com/posts/how-to-compare-two-app-version-strings-in-swift/ + func versionCompare(_ otherVersion: String) -> ComparisonResult { + let versionDelimiter = "." + + var versionComponents = components(separatedBy: versionDelimiter) // <1> + var otherVersionComponents = otherVersion.components(separatedBy: versionDelimiter) + + let zeroDiff = versionComponents.count - otherVersionComponents.count // <2> + + // <3> Compare normally if the formats are the same. + guard zeroDiff != 0 else { return compare(otherVersion, options: .numeric) } + + let zeros = Array(repeating: "0", count: abs(zeroDiff)) // <4> + if zeroDiff > 0 { + otherVersionComponents.append(contentsOf: zeros) // <5> + } else { + versionComponents.append(contentsOf: zeros) + } + return versionComponents.joined(separator: versionDelimiter) + .compare(otherVersionComponents.joined(separator: versionDelimiter), options: .numeric) // <6> + } +} diff --git a/Packages/vChewing_TooltipUI/Package.swift b/Packages/vChewing_TooltipUI/Package.swift index ef56e02f..99666de9 100644 --- a/Packages/vChewing_TooltipUI/Package.swift +++ b/Packages/vChewing_TooltipUI/Package.swift @@ -14,7 +14,7 @@ let package = Package( ], dependencies: [ .package(path: "../Fuziki_NSAttributedTextView"), - .package(path: "../vChewing_CocoaExtension"), + .package(path: "../vChewing_OSFrameworkImpl"), .package(path: "../vChewing_Shared"), ], targets: [ @@ -22,7 +22,7 @@ let package = Package( name: "TooltipUI", dependencies: [ .product(name: "NSAttributedTextView", package: "Fuziki_NSAttributedTextView"), - .product(name: "CocoaExtension", package: "vChewing_CocoaExtension"), + .product(name: "OSFrameworkImpl", package: "vChewing_OSFrameworkImpl"), .product(name: "Shared", package: "vChewing_Shared"), ] ), diff --git a/Packages/vChewing_TooltipUI/Sources/TooltipUI/TooltipUI_LateCocoa.swift b/Packages/vChewing_TooltipUI/Sources/TooltipUI/TooltipUI_LateCocoa.swift index f966da81..e541bcff 100644 --- a/Packages/vChewing_TooltipUI/Sources/TooltipUI/TooltipUI_LateCocoa.swift +++ b/Packages/vChewing_TooltipUI/Sources/TooltipUI/TooltipUI_LateCocoa.swift @@ -7,8 +7,8 @@ // requirements defined in MIT License. import AppKit -import CocoaExtension import NSAttributedTextView +import OSFrameworkImpl import Shared public class TooltipUI_LateCocoa: NSWindowController, TooltipUIProtocol { diff --git a/Packages/vChewing_Uninstaller/Package.swift b/Packages/vChewing_Uninstaller/Package.swift index e05019d7..d00aa833 100644 --- a/Packages/vChewing_Uninstaller/Package.swift +++ b/Packages/vChewing_Uninstaller/Package.swift @@ -13,13 +13,13 @@ let package = Package( ), ], dependencies: [ - .package(path: "../vChewing_CocoaExtension"), + .package(path: "../vChewing_OSFrameworkImpl"), ], targets: [ .target( name: "Uninstaller", dependencies: [ - .product(name: "CocoaExtension", package: "vChewing_CocoaExtension"), + .product(name: "OSFrameworkImpl", package: "vChewing_OSFrameworkImpl"), ] ), ] diff --git a/Packages/vChewing_Uninstaller/Sources/Uninstaller/Uninstaller.swift b/Packages/vChewing_Uninstaller/Sources/Uninstaller/Uninstaller.swift index 76066292..f60ac06c 100644 --- a/Packages/vChewing_Uninstaller/Sources/Uninstaller/Uninstaller.swift +++ b/Packages/vChewing_Uninstaller/Sources/Uninstaller/Uninstaller.swift @@ -7,7 +7,7 @@ // requirements defined in MIT License. import AppKit -import CocoaExtension +import OSFrameworkImpl public enum Uninstaller { // MARK: - Uninstall the input method. diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 29bef43a..f5a0e574 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -26,9 +26,8 @@ 5B70F4EC2A0BE900005EA8C4 /* MenuIcon-TCVIM@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 5B70F4E82A0BE900005EA8C4 /* MenuIcon-TCVIM@2x.png */; }; 5B765F09293A253C00122315 /* PhraseEditorUI in Frameworks */ = {isa = PBXBuildFile; productRef = 5B765F08293A253C00122315 /* PhraseEditorUI */; }; 5B7DA80328BF6BC600D7B2AD /* fixinstall.sh in Resources */ = {isa = PBXBuildFile; fileRef = 5B7DA80228BF6BBA00D7B2AD /* fixinstall.sh */; }; - 5B963C9D28D5BFB800DCEE88 /* CocoaExtension in Frameworks */ = {isa = PBXBuildFile; productRef = 5B963C9C28D5BFB800DCEE88 /* CocoaExtension */; }; + 5B963C9D28D5BFB800DCEE88 /* OSFrameworkImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 5B963C9C28D5BFB800DCEE88 /* OSFrameworkImpl */; }; 5B963CA328D5C23600DCEE88 /* SwiftExtension in Frameworks */ = {isa = PBXBuildFile; productRef = 5B963CA228D5C23600DCEE88 /* SwiftExtension */; }; - 5B98114828D6198700CBC605 /* PinyinPhonaConverter in Frameworks */ = {isa = PBXBuildFile; productRef = 5B98114728D6198700CBC605 /* PinyinPhonaConverter */; }; 5BA8C30328DF0360004C5CC4 /* CandidateWindow in Frameworks */ = {isa = PBXBuildFile; productRef = 5BA8C30228DF0360004C5CC4 /* CandidateWindow */; }; 5BAD0CD527D701F6003D127F /* vChewingKeyLayout.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */; }; 5BBBB75F27AED54C0023B93A /* Beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB75D27AED54C0023B93A /* Beep.m4a */; }; @@ -144,10 +143,8 @@ 5B70F4E82A0BE900005EA8C4 /* MenuIcon-TCVIM@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MenuIcon-TCVIM@2x.png"; sourceTree = ""; }; 5B765F07293A250000122315 /* vChewing_PhraseEditorUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_PhraseEditorUI; path = Packages/vChewing_PhraseEditorUI; sourceTree = ""; }; 5B7DA80228BF6BBA00D7B2AD /* fixinstall.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; lineEnding = 0; path = fixinstall.sh; sourceTree = ""; }; - 5B963C9B28D5BE4100DCEE88 /* vChewing_CocoaExtension */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_CocoaExtension; path = Packages/vChewing_CocoaExtension; sourceTree = ""; }; 5B963C9E28D5C14600DCEE88 /* vChewing_Shared */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_Shared; path = Packages/vChewing_Shared; sourceTree = ""; }; 5B963CA128D5C22D00DCEE88 /* vChewing_SwiftExtension */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_SwiftExtension; path = Packages/vChewing_SwiftExtension; sourceTree = ""; }; - 5B98114628D6198000CBC605 /* vChewing_PinyinPhonaConverter */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_PinyinPhonaConverter; path = Packages/vChewing_PinyinPhonaConverter; sourceTree = ""; }; 5BA8C30128DEFE4F004C5CC4 /* vChewing_CandidateWindow */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_CandidateWindow; path = Packages/vChewing_CandidateWindow; sourceTree = ""; }; 5BAD29D12B7E1A1B0013D695 /* vChewing_KimoDataReader */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_KimoDataReader; path = Packages/vChewing_KimoDataReader; sourceTree = ""; }; 5BAD67E12ADAB62D005A4842 /* HangarRash_SwiftyCapsLockToggler */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = HangarRash_SwiftyCapsLockToggler; path = Packages/HangarRash_SwiftyCapsLockToggler; sourceTree = ""; }; @@ -163,6 +160,7 @@ 5BC5E01C28DDE4270094E427 /* vChewing_NotifierUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_NotifierUI; path = Packages/vChewing_NotifierUI; sourceTree = ""; }; 5BC5E01F28DDEFD80094E427 /* vChewing_TooltipUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_TooltipUI; path = Packages/vChewing_TooltipUI; sourceTree = ""; }; 5BC5E02228DE07250094E427 /* vChewing_PopupCompositionBuffer */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_PopupCompositionBuffer; path = Packages/vChewing_PopupCompositionBuffer; sourceTree = ""; }; + 5BDA45492B97588B00DFA179 /* vChewing_OSFrameworkImpl */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_OSFrameworkImpl; path = Packages/vChewing_OSFrameworkImpl; sourceTree = ""; }; 5BDB7A3028D47587001AC277 /* Jad_BookmarkManager */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Jad_BookmarkManager; path = Packages/Jad_BookmarkManager; sourceTree = ""; }; 5BDB7A3128D47587001AC277 /* DanielGalasko_FolderMonitor */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = DanielGalasko_FolderMonitor; path = Packages/DanielGalasko_FolderMonitor; sourceTree = ""; }; 5BDB7A3228D47587001AC277 /* vChewing_Hotenka */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_Hotenka; path = Packages/vChewing_Hotenka; sourceTree = ""; }; @@ -229,8 +227,7 @@ 5BDB7A4728D4824A001AC277 /* Tekkon in Frameworks */, 5BDB7A3D28D4824A001AC277 /* Hotenka in Frameworks */, 5BDB7A3F28D4824A001AC277 /* LineReader in Frameworks */, - 5B963C9D28D5BFB800DCEE88 /* CocoaExtension in Frameworks */, - 5B98114828D6198700CBC605 /* PinyinPhonaConverter in Frameworks */, + 5B963C9D28D5BFB800DCEE88 /* OSFrameworkImpl in Frameworks */, 5BFC63CF28D4ACA3004A77B7 /* LangModelAssembly in Frameworks */, 5BC5E02128DDEFE00094E427 /* TooltipUI in Frameworks */, 5B765F09293A253C00122315 /* PhraseEditorUI in Frameworks */, @@ -389,7 +386,6 @@ 5BDB7A3528D47587001AC277 /* RMJay_LineReader */, 5B6CA6272B8A1C9200A85050 /* vChewing_BrailleSputnik */, 5BA8C30128DEFE4F004C5CC4 /* vChewing_CandidateWindow */, - 5B963C9B28D5BE4100DCEE88 /* vChewing_CocoaExtension */, 5BDB7A3228D47587001AC277 /* vChewing_Hotenka */, 5BFC63C728D49511004A77B7 /* vChewing_IMKUtils */, 5BAD29D12B7E1A1B0013D695 /* vChewing_KimoDataReader */, @@ -397,8 +393,8 @@ 5B65FB322A9518C9007EEFB0 /* vChewing_MainAssembly */, 5BDB7A3328D47587001AC277 /* vChewing_Megrez */, 5BC5E01C28DDE4270094E427 /* vChewing_NotifierUI */, + 5BDA45492B97588B00DFA179 /* vChewing_OSFrameworkImpl */, 5B765F07293A250000122315 /* vChewing_PhraseEditorUI */, - 5B98114628D6198000CBC605 /* vChewing_PinyinPhonaConverter */, 5BC5E02228DE07250094E427 /* vChewing_PopupCompositionBuffer */, 5B963C9E28D5C14600DCEE88 /* vChewing_Shared */, 5B963CA128D5C22D00DCEE88 /* vChewing_SwiftExtension */, @@ -558,9 +554,8 @@ 5BFC63C828D49754004A77B7 /* IMKUtils */, 5BFC63CB28D49BBC004A77B7 /* UpdateSputnik */, 5BFC63CE28D4ACA3004A77B7 /* LangModelAssembly */, - 5B963C9C28D5BFB800DCEE88 /* CocoaExtension */, + 5B963C9C28D5BFB800DCEE88 /* OSFrameworkImpl */, 5B963CA228D5C23600DCEE88 /* SwiftExtension */, - 5B98114728D6198700CBC605 /* PinyinPhonaConverter */, 5B40113828D7050D00A9D4CB /* Shared */, 5B40113B28D71C0100A9D4CB /* Uninstaller */, 5BC5E01D28DDE4770094E427 /* NotifierUI */, @@ -1377,18 +1372,14 @@ isa = XCSwiftPackageProductDependency; productName = PhraseEditorUI; }; - 5B963C9C28D5BFB800DCEE88 /* CocoaExtension */ = { + 5B963C9C28D5BFB800DCEE88 /* OSFrameworkImpl */ = { isa = XCSwiftPackageProductDependency; - productName = CocoaExtension; + productName = OSFrameworkImpl; }; 5B963CA228D5C23600DCEE88 /* SwiftExtension */ = { isa = XCSwiftPackageProductDependency; productName = SwiftExtension; }; - 5B98114728D6198700CBC605 /* PinyinPhonaConverter */ = { - isa = XCSwiftPackageProductDependency; - productName = PinyinPhonaConverter; - }; 5BA8C30228DF0360004C5CC4 /* CandidateWindow */ = { isa = XCSwiftPackageProductDependency; productName = CandidateWindow;