diff --git a/BuildVersionSpecifier.swift b/BuildVersionSpecifier.swift index 21920c1d..691bd3ab 100755 --- a/BuildVersionSpecifier.swift +++ b/BuildVersionSpecifier.swift @@ -31,10 +31,12 @@ extension 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(self.startIndex..., in: self) + pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines] + ) + let range = NSRange(startIndex..., in: self) self = regex.stringByReplacingMatches( - in: self, options: [], range: range, withTemplate: replaceWith) + in: self, options: [], range: range, withTemplate: replaceWith + ) } catch { return } } } @@ -59,9 +61,11 @@ if CommandLine.arguments.count == 3 { } strXcodeProjContent.regReplace( - pattern: #"CURRENT_PROJECT_VERSION = .*$"#, replaceWith: "CURRENT_PROJECT_VERSION = " + verBuild + ";") + pattern: #"CURRENT_PROJECT_VERSION = .*$"#, replaceWith: "CURRENT_PROJECT_VERSION = " + verBuild + ";" + ) strXcodeProjContent.regReplace( - pattern: #"MARKETING_VERSION = .*$"#, replaceWith: "MARKETING_VERSION = " + verMarket + ";") + pattern: #"MARKETING_VERSION = .*$"#, replaceWith: "MARKETING_VERSION = " + verMarket + ";" + ) do { try strXcodeProjContent.write(to: URL(fileURLWithPath: dirXcodeProjectFile), atomically: false, encoding: .utf8) } catch { @@ -81,5 +85,4 @@ if CommandLine.arguments.count == 3 { theDictionary?.setValue(verMarket, forKeyPath: "CFBundleShortVersionString") theDictionary?.write(toFile: dirUpdateInfoPlist, atomically: true) NSLog(" - 更新用通知 plist 版本資訊更新完成:\(verMarket) \(verBuild)。") - } diff --git a/DataCompiler/dataCompiler.swift b/DataCompiler/dataCompiler.swift index 8423b057..5e0a97ee 100644 --- a/DataCompiler/dataCompiler.swift +++ b/DataCompiler/dataCompiler.swift @@ -27,20 +27,24 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Foundation // MARK: - 前導工作 + extension String { fileprivate 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(self.startIndex..., in: self) + pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines] + ) + let range = NSRange(startIndex..., in: self) self = regex.stringByReplacingMatches( - in: self, options: [], range: range, withTemplate: replaceWith) + in: self, options: [], range: range, withTemplate: replaceWith + ) } catch { return } } } // MARK: - 引入小數點位數控制函數 + // Ref: https://stackoverflow.com/a/32581409/4162914 extension Float { fileprivate func rounded(toPlaces places: Int) -> Float { @@ -50,6 +54,7 @@ extension Float { } // MARK: - 引入幂乘函數 + // Ref: https://stackoverflow.com/a/41581695/4162914 precedencegroup ExponentiationPrecedence { associativity: right @@ -59,11 +64,11 @@ precedencegroup ExponentiationPrecedence { infix operator **: ExponentiationPrecedence func ** (_ base: Double, _ exp: Double) -> Double { - return pow(base, exp) + pow(base, exp) } func ** (_ base: Float, _ exp: Float) -> Float { - return pow(base, exp) + pow(base, exp) } // MARK: - 定義檔案結構 @@ -101,7 +106,7 @@ private let urlOutputCHT: String = "./data-cht.txt" func rawDictForPhrases(isCHS: Bool) -> [Entry] { var arrEntryRAW: [Entry] = [] - var strRAW: String = "" + var strRAW = "" let urlCustom: String = isCHS ? urlCHSforCustom : urlCHTforCustom let urlMCBP: String = isCHS ? urlCHSforMCBP : urlCHTforMCBP let urlMOE: String = isCHS ? urlCHSforMOE : urlCHTforMOE @@ -136,7 +141,7 @@ func rawDictForPhrases(isCHS: Bool) -> [Entry] { for lineData in arrData { // 第三欄開始是注音 let arrLineData = lineData.components(separatedBy: " ") - var varLineDataProcessed: String = "" + var varLineDataProcessed = "" var count = 0 for currentCell in arrLineData { count += 1 @@ -165,9 +170,10 @@ func rawDictForPhrases(isCHS: Bool) -> [Entry] { } if phrase != "" { // 廢掉空數據;之後無須再這樣處理。 arrEntryRAW += [ - Entry.init( + Entry( valPhone: phone, valPhrase: phrase, valWeight: 0.0, - valCount: occurrence) + valCount: occurrence + ) ] } } @@ -179,7 +185,7 @@ func rawDictForPhrases(isCHS: Bool) -> [Entry] { func rawDictForKanjis(isCHS: Bool) -> [Entry] { var arrEntryRAW: [Entry] = [] - var strRAW: String = "" + var strRAW = "" let i18n: String = isCHS ? "簡體中文" : "繁體中文" // 讀取內容 do { @@ -201,7 +207,7 @@ func rawDictForKanjis(isCHS: Bool) -> [Entry] { // 正式整理格式,現在就開始去重複: let arrData = Array( NSOrderedSet(array: strRAW.components(separatedBy: "\n")).array as! [String]) - var varLineData: String = "" + var varLineData = "" for lineData in arrData { // 簡體中文的話,提取 1,2,4;繁體中文的話,提取 1,3,4。 let varLineDataPre = lineData.components(separatedBy: " ").prefix(isCHS ? 2 : 1) @@ -212,7 +218,7 @@ func rawDictForKanjis(isCHS: Bool) -> [Entry] { separator: "\t") varLineData = varLineDataPre + "\t" + varLineDataPost let arrLineData = varLineData.components(separatedBy: " ") - var varLineDataProcessed: String = "" + var varLineDataProcessed = "" var count = 0 for currentCell in arrLineData { count += 1 @@ -241,9 +247,10 @@ func rawDictForKanjis(isCHS: Bool) -> [Entry] { } if phrase != "" { // 廢掉空數據;之後無須再這樣處理。 arrEntryRAW += [ - Entry.init( + Entry( valPhone: phone, valPhrase: phrase, valWeight: 0.0, - valCount: occurrence) + valCount: occurrence + ) ] } } @@ -255,7 +262,7 @@ func rawDictForKanjis(isCHS: Bool) -> [Entry] { func rawDictForNonKanjis(isCHS: Bool) -> [Entry] { var arrEntryRAW: [Entry] = [] - var strRAW: String = "" + var strRAW = "" let i18n: String = isCHS ? "簡體中文" : "繁體中文" // 讀取內容 do { @@ -279,14 +286,14 @@ func rawDictForNonKanjis(isCHS: Bool) -> [Entry] { // 正式整理格式,現在就開始去重複: let arrData = Array( NSOrderedSet(array: strRAW.components(separatedBy: "\n")).array as! [String]) - var varLineData: String = "" + var varLineData = "" for lineData in arrData { varLineData = lineData // 先完成某兩步需要分行處理才能完成的格式整理。 varLineData = varLineData.components(separatedBy: " ").prefix(3).joined( separator: "\t") // 提取前三欄的內容。 let arrLineData = varLineData.components(separatedBy: " ") - var varLineDataProcessed: String = "" + var varLineDataProcessed = "" var count = 0 for currentCell in arrLineData { count += 1 @@ -315,9 +322,10 @@ func rawDictForNonKanjis(isCHS: Bool) -> [Entry] { } if phrase != "" { // 廢掉空數據;之後無須再這樣處理。 arrEntryRAW += [ - Entry.init( + Entry( valPhone: phone, valPhrase: phrase, valWeight: 0.0, - valCount: occurrence) + valCount: occurrence + ) ] } } @@ -356,16 +364,17 @@ func weightAndSort(_ arrStructUncalculated: [Entry], isCHS: Bool) -> [Entry] { } let weightRounded: Float = weight.rounded(toPlaces: 3) // 為了節省生成的檔案體積,僅保留小數點後三位。 arrStructCalculated += [ - Entry.init( + Entry( valPhone: entry.valPhone, valPhrase: entry.valPhrase, valWeight: weightRounded, - valCount: entry.valCount) + valCount: entry.valCount + ) ] } NSLog(" - \(i18n): 成功計算權重。") // ========================================== // 接下來是排序,先按照注音遞減排序一遍、再按照權重遞減排序一遍。 - let arrStructSorted: [Entry] = arrStructCalculated.sorted(by: { (lhs, rhs) -> Bool in - return (lhs.valPhone, rhs.valCount) < (rhs.valPhone, lhs.valCount) + let arrStructSorted: [Entry] = arrStructCalculated.sorted(by: { lhs, rhs -> Bool in + (lhs.valPhone, rhs.valCount) < (rhs.valPhone, lhs.valCount) }) NSLog(" - \(i18n): 排序整理完畢,準備編譯要寫入的檔案內容。") return arrStructSorted @@ -406,6 +415,7 @@ func fileOutput(isCHS: Bool) { } // MARK: - 主执行绪 + func main() { NSLog("// 準備編譯繁體中文核心語料檔案。") fileOutput(isCHS: false) diff --git a/Installer/AppDelegate.swift b/Installer/AppDelegate.swift index 18399314..fcfeaef7 100644 --- a/Installer/AppDelegate.swift +++ b/Installer/AppDelegate.swift @@ -31,7 +31,8 @@ private let kTargetType = "app" private let kTargetBundle = "vChewing.app" private let urlDestinationPartial = FileManager.default.urls( - for: .inputMethodsDirectory, in: .userDomainMask)[0] + for: .inputMethodsDirectory, in: .userDomainMask +)[0] private let urlTargetPartial = urlDestinationPartial.appendingPathComponent(kTargetBundle) private let urlTargetFullBinPartial = urlTargetPartial.appendingPathComponent("Contents/MacOS/") .appendingPathComponent(kTargetBin) @@ -46,12 +47,12 @@ private let kTranslocationRemovalDeadline: TimeInterval = 60.0 @NSApplicationMain @objc(AppDelegate) class AppDelegate: NSWindowController, NSApplicationDelegate { - @IBOutlet weak private var installButton: NSButton! - @IBOutlet weak private var cancelButton: NSButton! - @IBOutlet weak private var progressSheet: NSWindow! - @IBOutlet weak private var progressIndicator: NSProgressIndicator! - @IBOutlet weak private var appVersionLabel: NSTextField! - @IBOutlet weak private var appCopyrightLabel: NSTextField! + @IBOutlet private var installButton: NSButton! + @IBOutlet private var cancelButton: NSButton! + @IBOutlet private var progressSheet: NSWindow! + @IBOutlet private var progressIndicator: NSProgressIndicator! + @IBOutlet private var appVersionLabel: NSTextField! + @IBOutlet private var appCopyrightLabel: NSTextField! @IBOutlet private var appEULAContent: NSTextView! private var archiveUtil: ArchiveUtil? @@ -69,7 +70,7 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { alert.runModal() } - func applicationDidFinishLaunching(_ notification: Notification) { + func applicationDidFinishLaunching(_: Notification) { guard let installingVersion = Bundle.main.infoDictionary?[kCFBundleVersionKey as String] as? String, @@ -96,11 +97,13 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { appEULAContent.string = eulaContent } appVersionLabel.stringValue = String( - format: "%@ Build %@", versionString, installingVersion) + format: "%@ Build %@", versionString, installingVersion + ) window?.title = String( format: NSLocalizedString("%@ (for version %@, r%@)", comment: ""), window?.title ?? "", - versionString, installingVersion) + versionString, installingVersion + ) window?.standardWindowButton(.closeButton)?.isHidden = true window?.standardWindowButton(.miniaturizeButton)?.isHidden = true window?.standardWindowButton(.zoomButton)?.isHidden = true @@ -130,7 +133,7 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { NSApp.activate(ignoringOtherApps: true) } - @IBAction func agreeAndInstallAction(_ sender: AnyObject) { + @IBAction func agreeAndInstallAction(_: AnyObject) { cancelButton.isEnabled = false installButton.isEnabled = false removeThenInstallInputMethod() @@ -154,7 +157,8 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { == false { installInputMethod( - previousExists: false, previousVersionNotFullyDeactivatedWarning: false) + previousExists: false, previousVersionNotFullyDeactivatedWarning: false + ) return } @@ -194,11 +198,13 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { if returnCode == .continue { self.installInputMethod( previousExists: true, - previousVersionNotFullyDeactivatedWarning: false) + previousVersionNotFullyDeactivatedWarning: false + ) } else { self.installInputMethod( previousExists: true, - previousVersionNotFullyDeactivatedWarning: true) + previousVersionNotFullyDeactivatedWarning: true + ) } } } @@ -206,15 +212,17 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { translocationRemovalStartTime = Date() Timer.scheduledTimer( timeInterval: kTranslocationRemovalTickInterval, target: self, - selector: #selector(timerTick(_:)), userInfo: nil, repeats: true) + selector: #selector(timerTick(_:)), userInfo: nil, repeats: true + ) } else { installInputMethod( - previousExists: false, previousVersionNotFullyDeactivatedWarning: false) + previousExists: false, previousVersionNotFullyDeactivatedWarning: false + ) } } func installInputMethod( - previousExists: Bool, previousVersionNotFullyDeactivatedWarning warning: Bool + previousExists _: Bool, previousVersionNotFullyDeactivatedWarning warning: Bool ) { guard let targetBundle = archiveUtil?.unzipNotarizedArchive() @@ -234,7 +242,8 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { runAlertPanel( title: NSLocalizedString("Install Failed", comment: ""), message: NSLocalizedString("Cannot copy the file to the destination.", comment: ""), - buttonTitle: NSLocalizedString("Cancel", comment: "")) + buttonTitle: NSLocalizedString("Cancel", comment: "") + ) endAppWithDelay() } @@ -254,11 +263,14 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { if !status { let message = String( format: NSLocalizedString( - "Cannot find input source %@ after registration.", comment: ""), - imeIdentifier) + "Cannot find input source %@ after registration.", comment: "" + ), + imeIdentifier + ) runAlertPanel( title: NSLocalizedString("Fatal Error", comment: ""), message: message, - buttonTitle: NSLocalizedString("Abort", comment: "")) + buttonTitle: NSLocalizedString("Abort", comment: "") + ) endAppWithDelay() return } @@ -267,11 +279,14 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { if inputSource == nil { let message = String( format: NSLocalizedString( - "Cannot find input source %@ after registration.", comment: ""), - imeIdentifier) + "Cannot find input source %@ after registration.", comment: "" + ), + imeIdentifier + ) runAlertPanel( title: NSLocalizedString("Fatal Error", comment: ""), message: message, - buttonTitle: NSLocalizedString("Abort", comment: "")) + buttonTitle: NSLocalizedString("Abort", comment: "") + ) } } @@ -304,20 +319,24 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { ntfPostInstall.messageText = NSLocalizedString("Attention", comment: "") ntfPostInstall.informativeText = NSLocalizedString( "vChewing is upgraded, but please log out or reboot for the new version to be fully functional.", - comment: "") + comment: "" + ) ntfPostInstall.addButton(withTitle: NSLocalizedString("OK", comment: "")) } else { - if !mainInputSourceEnabled && !isMacOS12OrAbove { + if !mainInputSourceEnabled, !isMacOS12OrAbove { ntfPostInstall.messageText = NSLocalizedString("Warning", comment: "") ntfPostInstall.informativeText = NSLocalizedString( "Input method may not be fully enabled. Please enable it through System Preferences > Keyboard > Input Sources.", - comment: "") + comment: "" + ) ntfPostInstall.addButton(withTitle: NSLocalizedString("Continue", comment: "")) } else { ntfPostInstall.messageText = NSLocalizedString( - "Installation Successful", comment: "") + "Installation Successful", comment: "" + ) ntfPostInstall.informativeText = NSLocalizedString( - "vChewing is ready to use.", comment: "") + "vChewing is ready to use.", comment: "" + ) ntfPostInstall.addButton(withTitle: NSLocalizedString("OK", comment: "")) } } @@ -332,12 +351,11 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { } } - @IBAction func cancelAction(_ sender: AnyObject) { + @IBAction func cancelAction(_: AnyObject) { NSApp.terminate(self) } - func windowWillClose(_ notification: Notification) { + func windowWillClose(_: Notification) { NSApp.terminate(self) } - } diff --git a/Installer/ArchiveUtil.swift b/Installer/ArchiveUtil.swift index 85e0eebb..e422428a 100644 --- a/Installer/ArchiveUtil.swift +++ b/Installer/ArchiveUtil.swift @@ -53,7 +53,8 @@ struct ArchiveUtil { let notarizedArchiveExists = FileManager.default.fileExists(atPath: notarizedArchive) let devModeAppBundleExists = FileManager.default.fileExists(atPath: devModeAppBundlePath) - if count > 0 { + if !notarizedArchivesContent.isEmpty { + // 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。 if count != 1 || !notarizedArchiveExists || devModeAppBundleExists { let alert = NSAlert() alert.alertStyle = .informational @@ -105,7 +106,8 @@ struct ArchiveUtil { let result = (tempFilePath as NSString).appendingPathComponent(targetAppBundleName) assert( FileManager.default.fileExists(atPath: result), - "App bundle must be unzipped at \(result).") + "App bundle must be unzipped at \(result)." + ) return result } @@ -130,5 +132,4 @@ struct ArchiveUtil { notarizedArchiveBasename) return notarizedArchive } - } diff --git a/Packages/SwiftyOpenCC/Package.swift b/Packages/SwiftyOpenCC/Package.swift index 115ce9e0..470d63c1 100644 --- a/Packages/SwiftyOpenCC/Package.swift +++ b/Packages/SwiftyOpenCC/Package.swift @@ -7,7 +7,8 @@ let package = Package( products: [ .library( name: "OpenCC", - targets: ["OpenCC"]) + targets: ["OpenCC"] + ) ], targets: [ .target( @@ -15,14 +16,16 @@ let package = Package( dependencies: ["copencc"], resources: [ .copy("Dictionary") - ]), + ] + ), .testTarget( name: "OpenCCTests", dependencies: ["OpenCC"], resources: [ .copy("benchmark"), .copy("testcases"), - ]), + ] + ), .target( name: "copencc", exclude: [ @@ -79,7 +82,8 @@ let package = Package( .headerSearchPath("deps/marisa-0.2.6/include"), .headerSearchPath("deps/marisa-0.2.6/lib"), .define("ENABLE_DARTS"), - ]), + ] + ), ], cxxLanguageStandard: .cxx14 ) diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/ChineseConverter.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/ChineseConverter.swift index 10cea288..81678048 100644 --- a/Packages/SwiftyOpenCC/Sources/OpenCC/ChineseConverter.swift +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/ChineseConverter.swift @@ -22,10 +22,8 @@ import copencc /// However, the string on which it is operating should not be mutated /// during the course of a conversion. public class ChineseConverter { - /// These constants define the ChineseConverter options. public struct Options: OptionSet { - public let rawValue: Int public init(rawValue: Int) { @@ -62,7 +60,7 @@ public class ChineseConverter { private init(loader: DictionaryLoader, options: Options) throws { seg = try loader.segmentation(options: options) chain = try loader.conversionChain(options: options) - var rawChain = chain.map { $0.dict } + var rawChain = chain.map(\.dict) converter = CCConverterCreate("SwiftyOpenCC", seg.dict, &rawChain, rawChain.count) } @@ -85,5 +83,4 @@ public class ChineseConverter { defer { STLStringDestroy(stlStr) } return String(utf8String: STLStringGetUTF8String(stlStr))! } - } diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionDictionary.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionDictionary.swift index 824a744c..e508948d 100644 --- a/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionDictionary.swift +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionDictionary.swift @@ -9,7 +9,6 @@ import Foundation import copencc class ConversionDictionary { - let group: [ConversionDictionary] let dict: CCDictRef @@ -23,7 +22,7 @@ class ConversionDictionary { } init(group: [ConversionDictionary]) { - var rawGroup = group.map { $0.dict } + var rawGroup = group.map(\.dict) self.group = group dict = CCDictCreateWithGroup(&rawGroup, rawGroup.count) } diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionError.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionError.swift index d24f1f21..e84edb0b 100644 --- a/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionError.swift +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/ConversionError.swift @@ -9,7 +9,6 @@ import Foundation import copencc public enum ConversionError: Error { - case fileNotFound case invalidFormat diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryLoader.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryLoader.swift index 35937e35..bc63693d 100644 --- a/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryLoader.swift +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryLoader.swift @@ -9,9 +9,7 @@ import Foundation import copencc extension ChineseConverter { - struct DictionaryLoader { - private static let subdirectory = "Dictionary" private static let dictCache = WeakValueCache() @@ -25,7 +23,8 @@ extension ChineseConverter { guard let path = bundle.path( forResource: name.description, ofType: "ocd2", - inDirectory: DictionaryLoader.subdirectory) + inDirectory: DictionaryLoader.subdirectory + ) else { throw ConversionError.fileNotFound } @@ -37,7 +36,6 @@ extension ChineseConverter { } extension ChineseConverter.DictionaryLoader { - func segmentation(options: ChineseConverter.Options) throws -> ConversionDictionary { let dictName = options.segmentationDictName return try dict(dictName) diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryName.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryName.swift index 3629bbcc..a1768b7e 100644 --- a/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryName.swift +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/DictionaryName.swift @@ -8,9 +8,7 @@ import Foundation extension ChineseConverter { - enum DictionaryName: CustomStringConvertible { - case hkVariants case hkVariantsRev case hkVariantsRevPhrases @@ -46,7 +44,6 @@ extension ChineseConverter { } extension ChineseConverter.Options { - var segmentationDictName: ChineseConverter.DictionaryName { if contains(.traditionalize) { return .stPhrases diff --git a/Packages/SwiftyOpenCC/Sources/OpenCC/WeakValueCache.swift b/Packages/SwiftyOpenCC/Sources/OpenCC/WeakValueCache.swift index 59a5a78c..489e2c55 100644 --- a/Packages/SwiftyOpenCC/Sources/OpenCC/WeakValueCache.swift +++ b/Packages/SwiftyOpenCC/Sources/OpenCC/WeakValueCache.swift @@ -8,7 +8,6 @@ import Foundation class WeakBox { - private(set) weak var value: Value? init(_ value: Value) { @@ -17,7 +16,6 @@ class WeakBox { } class WeakValueCache { - private var storage: [Key: WeakBox] = [:] private var lock = NSLock() diff --git a/Packages/SwiftyOpenCC/Tests/OpenCCTests/OpenCCTests.swift b/Packages/SwiftyOpenCC/Tests/OpenCCTests/OpenCCTests.swift index 9377cf55..93f3670c 100644 --- a/Packages/SwiftyOpenCC/Tests/OpenCCTests/OpenCCTests.swift +++ b/Packages/SwiftyOpenCC/Tests/OpenCCTests/OpenCCTests.swift @@ -14,7 +14,6 @@ let testCases: [(String, ChineseConverter.Options)] = [ ] class OpenCCTests: XCTestCase { - func converter(option: ChineseConverter.Options) throws -> ChineseConverter { try ChineseConverter(options: option) } @@ -22,7 +21,8 @@ class OpenCCTests: XCTestCase { func testConversion() throws { func testCase(name: String, ext: String) -> String { let url = Bundle.module.url( - forResource: name, withExtension: ext, subdirectory: "testcases")! + forResource: name, withExtension: ext, subdirectory: "testcases" + )! return try! String(contentsOf: url) } for (name, opt) in testCases { @@ -47,7 +47,7 @@ class OpenCCTests: XCTestCase { let options: ChineseConverter.Options = [.traditionalize, .twStandard, .twIdiom] let holder = try! ChineseConverter(options: options) measure { - for _ in 0..<1_000 { + for _ in 0..<1000 { _ = try! ChineseConverter(options: options) } } @@ -57,7 +57,8 @@ class OpenCCTests: XCTestCase { func testConversionPerformance() throws { let cov = try converter(option: [.traditionalize, .twStandard, .twIdiom]) let url = Bundle.module.url( - forResource: "zuozhuan", withExtension: "txt", subdirectory: "benchmark")! + forResource: "zuozhuan", withExtension: "txt", subdirectory: "benchmark" + )! // 1.9 MB, 624k word let str = try String(contentsOf: url) measure { diff --git a/Source/3rdParty/OpenCCBridge/OpenCCBridge.swift b/Source/3rdParty/OpenCCBridge/OpenCCBridge.swift index 9d8d209b..e7133cd4 100644 --- a/Source/3rdParty/OpenCCBridge/OpenCCBridge.swift +++ b/Source/3rdParty/OpenCCBridge/OpenCCBridge.swift @@ -36,7 +36,7 @@ public class OpenCCBridge: NSObject { private var simplify: ChineseConverter? private var traditionalize: ChineseConverter? - private override init() { + override private init() { try? simplify = ChineseConverter(options: .simplify) try? traditionalize = ChineseConverter(options: [.traditionalize, .twStandard]) super.init() diff --git a/Source/3rdParty/SindreSorhus/Preferences/Container.swift b/Source/3rdParty/SindreSorhus/Preferences/Container.swift index d9ba172b..acf4a546 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/Container.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/Container.swift @@ -26,7 +26,7 @@ extension Preferences { Function builder for `Preferences` components used in order to restrict types of child views to be of type `Section`. */ @resultBuilder - public struct SectionBuilder { + public enum SectionBuilder { public static func buildBlock(_ sections: Section...) -> [Section] { sections } @@ -78,7 +78,7 @@ extension Preferences { @ViewBuilder private func viewForSection(_ sections: [Section], index: Int) -> some View { sections[index] - if index != sections.count - 1 && sections[index].bottomDivider { + if index != sections.count - 1, sections[index].bottomDivider { Divider() // Strangely doesn't work without width being specified. Probably because of custom alignment. .frame(width: CGFloat(contentWidth), height: 20) diff --git a/Source/3rdParty/SindreSorhus/Preferences/Pane.swift b/Source/3rdParty/SindreSorhus/Preferences/Pane.swift index beb4f518..8bff9f68 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/Pane.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/Pane.swift @@ -93,7 +93,7 @@ extension Preferences { @available(*, unavailable) @objc - dynamic required init?(coder: NSCoder) { + dynamic required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } diff --git a/Source/3rdParty/SindreSorhus/Preferences/PreferencesTabViewController.swift b/Source/3rdParty/SindreSorhus/Preferences/PreferencesTabViewController.swift index 18c9b177..61cefb84 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/PreferencesTabViewController.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/PreferencesTabViewController.swift @@ -112,7 +112,7 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont } } - private func updateWindowTitle(tabIndex: Int) { + private func updateWindowTitle(tabIndex _: Int) { window.title = { // if preferencePanes.count > 1 { // return preferencePanes[tabIndex].preferencePaneTitle @@ -200,7 +200,8 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont options: options, completionHandler: completion ) - }, completionHandler: nil) + }, completionHandler: nil + ) } else { super.transition( from: fromViewController, @@ -234,22 +235,22 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont } extension PreferencesTabViewController: NSToolbarDelegate { - func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + func toolbarDefaultItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] { toolbarItemIdentifiers } - func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + func toolbarAllowedItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] { toolbarItemIdentifiers } - func toolbarSelectableItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + func toolbarSelectableItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] { style == .segmentedControl ? [] : toolbarItemIdentifiers } public func toolbar( - _ toolbar: NSToolbar, + _: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, - willBeInsertedIntoToolbar flag: Bool + willBeInsertedIntoToolbar _: Bool ) -> NSToolbarItem? { if itemIdentifier == .flexibleSpace { return nil diff --git a/Source/3rdParty/SindreSorhus/Preferences/PreferencesWindowController.swift b/Source/3rdParty/SindreSorhus/Preferences/PreferencesWindowController.swift index 2ada7810..488a514f 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/PreferencesWindowController.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/PreferencesWindowController.swift @@ -87,12 +87,12 @@ public final class PreferencesWindowController: NSWindowController { } @available(*, unavailable) - override public init(window: NSWindow?) { + override public init(window _: NSWindow?) { fatalError("init(window:) is not supported, use init(preferences:style:animated:)") } @available(*, unavailable) - public required init?(coder: NSCoder) { + public required init?(coder _: NSCoder) { fatalError("init(coder:) is not supported, use init(preferences:style:animated:)") } @@ -140,7 +140,7 @@ public final class PreferencesWindowController: NSWindowController { extension PreferencesWindowController { /// Returns the active pane if it responds to the given action. - override public func supplementalTarget(forAction action: Selector, sender: Any?) -> Any? { + public override func supplementalTarget(forAction action: Selector, sender: Any?) -> Any? { if let target = super.supplementalTarget(forAction: action, sender: sender) { return target } diff --git a/Source/3rdParty/SindreSorhus/Preferences/SegmentedControlStyleViewController.swift b/Source/3rdParty/SindreSorhus/Preferences/SegmentedControlStyleViewController.swift index d16bd748..c1aba49a 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/SegmentedControlStyleViewController.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/SegmentedControlStyleViewController.swift @@ -48,7 +48,7 @@ final class SegmentedControlStyleViewController: NSViewController, PreferencesSt } @available(*, unavailable) - required init?(coder: NSCoder) { + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/Source/3rdParty/SindreSorhus/Preferences/Utilities.swift b/Source/3rdParty/SindreSorhus/Preferences/Utilities.swift index 849e65b4..eaa3b415 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/Utilities.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/Utilities.swift @@ -36,11 +36,13 @@ extension NSView { result.append( contentsOf: NSLayoutConstraint.constraints( withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, - views: ["subview": self])) + views: ["subview": self] + )) result.append( contentsOf: NSLayoutConstraint.constraints( withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, - views: ["subview": self])) + views: ["subview": self] + )) translatesAutoresizingMaskIntoConstraints = false superview.addConstraints(result) @@ -104,7 +106,7 @@ extension Bundle { /// A window that allows you to disable all user interactions via `isUserInteractionEnabled`. /// /// Used to avoid breaking animations when the user clicks too fast. Disable user interactions during animations and you're set. -class UserInteractionPausableWindow: NSWindow { // swiftlint:disable:this final_class +class UserInteractionPausableWindow: NSWindow { var isUserInteractionEnabled = true override func sendEvent(_ event: NSEvent) { diff --git a/Source/3rdParty/VDKComboBox/VDKComboBox.swift b/Source/3rdParty/VDKComboBox/VDKComboBox.swift index 7f7ae3a0..ddc8f055 100644 --- a/Source/3rdParty/VDKComboBox/VDKComboBox.swift +++ b/Source/3rdParty/VDKComboBox/VDKComboBox.swift @@ -6,6 +6,7 @@ import SwiftUI // MARK: - NSComboBox + // Ref: https://stackoverflow.com/a/71058587/4162914 @available(macOS 11.0, *) struct ComboBox: NSViewRepresentable { diff --git a/Source/Modules/AppDelegate.swift b/Source/Modules/AppDelegate.swift index 724b3806..a99dc6f4 100644 --- a/Source/Modules/AppDelegate.swift +++ b/Source/Modules/AppDelegate.swift @@ -31,7 +31,7 @@ import InputMethodKit class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelegate, FSEventStreamHelperDelegate { - func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event]) { + func helper(_: FSEventStreamHelper, didReceive _: [FSEventStreamHelper.Event]) { // 拖 100ms 再重載,畢竟有些有特殊需求的使用者可能會想使用巨型自訂語彙檔案。 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { if mgrPrefs.shouldAutoReloadUserDataFiles { @@ -42,14 +42,15 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega // let vChewingKeyLayoutBundle = Bundle.init(path: URL(fileURLWithPath: Bundle.main.resourcePath ?? "").appendingPathComponent("vChewingKeyLayout.bundle").path) - @IBOutlet weak var window: NSWindow? + @IBOutlet var window: NSWindow? private var ctlPrefWindowInstance: ctlPrefWindow? private var ctlAboutWindowInstance: ctlAboutWindow? // New About Window private var checkTask: URLSessionTask? private var updateNextStepURL: URL? private var fsStreamHelper = FSEventStreamHelper( path: mgrLangModel.dataFolderPath(isDefaultFolder: false), - queue: DispatchQueue(label: "vChewing User Phrases")) + queue: DispatchQueue(label: "vChewing User Phrases") + ) private var currentAlertType: String = "" // 補上 dealloc @@ -62,7 +63,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega fsStreamHelper.delegate = nil } - func applicationDidFinishLaunching(_ notification: Notification) { + func applicationDidFinishLaunching(_: Notification) { IME.initLangModels(userOnly: false) fsStreamHelper.delegate = self _ = fsStreamHelper.start() @@ -104,7 +105,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega @objc(checkForUpdateForced:) func checkForUpdate(forced: Bool) { - if checkTask != nil { // busy return @@ -137,24 +137,30 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega let content = String( format: NSLocalizedString( "You're currently using vChewing %@ (%@), a new version %@ (%@) is now available. Do you want to visit vChewing's website to download the version?%@", - comment: ""), + comment: "" + ), report.currentShortVersion, report.currentVersion, report.remoteShortVersion, report.remoteVersion, - report.versionDescription) + report.versionDescription + ) IME.prtDebugIntel("vChewingDebug: \(content)") currentAlertType = "Update" ctlNonModalAlertWindow.shared.show( title: NSLocalizedString( - "New Version Available", comment: ""), + "New Version Available", comment: "" + ), content: content, confirmButtonTitle: NSLocalizedString( - "Visit Website", comment: ""), + "Visit Website", comment: "" + ), cancelButtonTitle: NSLocalizedString( - "Not Now", comment: ""), + "Not Now", comment: "" + ), cancelAsDefault: false, - delegate: self) + delegate: self + ) NSApp.setActivationPolicy(.accessory) case .noNeedToUpdate, .ignored: break @@ -163,11 +169,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega switch error { case VersionUpdateApiError.connectionError(let message): let title = NSLocalizedString( - "Update Check Failed", comment: "") + "Update Check Failed", comment: "" + ) let content = String( format: NSLocalizedString( "There may be no internet connection or the server failed to respond.\n\nError message: %@", - comment: ""), message) + comment: "" + ), message + ) let buttonTitle = NSLocalizedString("Dismiss", comment: "") IME.prtDebugIntel("vChewingDebug: \(content)") currentAlertType = "Update" @@ -175,7 +184,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega title: title, content: content, confirmButtonTitle: buttonTitle, cancelButtonTitle: nil, - cancelAsDefault: false, delegate: nil) + cancelAsDefault: false, delegate: nil + ) NSApp.setActivationPolicy(.accessory) default: break @@ -189,20 +199,23 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega let content = String( format: NSLocalizedString( "This will remove vChewing Input Method from this user account, requiring your confirmation.", - comment: "")) + comment: "" + )) ctlNonModalAlertWindow.shared.show( title: NSLocalizedString("Uninstallation", comment: ""), content: content, confirmButtonTitle: NSLocalizedString("OK", comment: ""), cancelButtonTitle: NSLocalizedString("Not Now", comment: ""), cancelAsDefault: false, - delegate: self) + delegate: self + ) NSApp.setActivationPolicy(.accessory) } - func ctlNonModalAlertWindowDidConfirm(_ controller: ctlNonModalAlertWindow) { + func ctlNonModalAlertWindowDidConfirm(_: ctlNonModalAlertWindow) { switch currentAlertType { case "Uninstall": NSWorkspace.shared.openFile( - mgrLangModel.dataFolderPath(isDefaultFolder: true), withApplication: "Finder") + mgrLangModel.dataFolderPath(isDefaultFolder: true), withApplication: "Finder" + ) IME.uninstall(isSudo: false, selfKill: true) case "Update": if let updateNextStepURL = updateNextStepURL { @@ -214,7 +227,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega } } - func ctlNonModalAlertWindowDidCancel(_ controller: ctlNonModalAlertWindow) { + func ctlNonModalAlertWindowDidCancel(_: ctlNonModalAlertWindow) { switch currentAlertType { case "Update": updateNextStepURL = nil @@ -224,7 +237,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega } // New About Window - @IBAction func about(_ sender: Any) { + @IBAction func about(_: Any) { (NSApp.delegate as? AppDelegate)?.showAbout() NSApplication.shared.activate(ignoringOtherApps: true) } diff --git a/Source/Modules/ControllerModules/AppleKeyboardConverter.swift b/Source/Modules/ControllerModules/AppleKeyboardConverter.swift index 887b2c24..41db1d45 100644 --- a/Source/Modules/ControllerModules/AppleKeyboardConverter.swift +++ b/Source/Modules/ControllerModules/AppleKeyboardConverter.swift @@ -42,6 +42,7 @@ class AppleKeyboardConverter: NSObject { @objc class func isDynamicBasicKeyboardLayoutEnabled() -> Bool { AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(mgrPrefs.basicKeyboardLayout) } + // 處理 Apple 注音鍵盤佈局類型。 @objc class func cnvApple2ABC(_ charCode: UniChar) -> UniChar { var charCode = charCode diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index f52c149a..02a58250 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -58,7 +58,6 @@ import Cocoa /// - Choosing Candidate: The candidate window is open to let the user to choose /// one among the candidates. class InputState: NSObject { - /// Represents that the input controller is deactivated. @objc(InputStateDeactivated) class Deactivated: InputState { @@ -89,6 +88,7 @@ class InputState: NSObject { @objc var composingBuffer: String { "" } + override var description: String { "" } @@ -147,7 +147,8 @@ class InputState: NSObject { attributes: [ .underlineStyle: NSUnderlineStyle.single.rawValue, .markedClauseSegment: 0, - ]) + ] + ) return attributedSting } @@ -164,18 +165,18 @@ class InputState: NSObject { /// Represents that the user is marking a range in the composing buffer. @objc(InputStateMarking) class Marking: NotEmpty { - @objc private(set) var markerIndex: UInt @objc private(set) var markedRange: NSRange @objc private var deleteTargetExists = false @objc var tooltip: String { - if composingBuffer.count != readings.count { TooltipController.backgroundColor = NSColor( - red: 0.55, green: 0.00, blue: 0.00, alpha: 1.00) + red: 0.55, green: 0.00, blue: 0.00, alpha: 1.00 + ) TooltipController.textColor = NSColor.white return NSLocalizedString( - "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match.", comment: "") + "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match.", comment: "" + ) } if mgrPrefs.phraseReplacementEnabled { @@ -192,21 +193,29 @@ class InputState: NSObject { let text = (composingBuffer as NSString).substring(with: markedRange) if markedRange.length < kMinMarkRangeLength { TooltipController.backgroundColor = NSColor( - red: 0.18, green: 0.18, blue: 0.18, alpha: 1.00) + red: 0.18, green: 0.18, blue: 0.18, alpha: 1.00 + ) TooltipController.textColor = NSColor( - red: 0.86, green: 0.86, blue: 0.86, alpha: 1.00) + red: 0.86, green: 0.86, blue: 0.86, alpha: 1.00 + ) return String( format: NSLocalizedString( - "\"%@\" length must ≥ 2 for a user phrase.", comment: ""), text) + "\"%@\" length must ≥ 2 for a user phrase.", comment: "" + ), text + ) } else if markedRange.length > kMaxMarkRangeLength { TooltipController.backgroundColor = NSColor( - red: 0.26, green: 0.16, blue: 0.00, alpha: 1.00) + red: 0.26, green: 0.16, blue: 0.00, alpha: 1.00 + ) TooltipController.textColor = NSColor( - red: 1.00, green: 0.60, blue: 0.00, alpha: 1.00) + red: 1.00, green: 0.60, blue: 0.00, alpha: 1.00 + ) return String( format: NSLocalizedString( - "\"%@\" length should ≤ %d for a user phrase.", comment: ""), - text, kMaxMarkRangeLength) + "\"%@\" length should ≤ %d for a user phrase.", comment: "" + ), + text, kMaxMarkRangeLength + ) } let (exactBegin, _) = (composingBuffer as NSString).characterIndex( @@ -216,24 +225,30 @@ class InputState: NSObject { let selectedReadings = readings[exactBegin.. kMaxMarkRangeLength { return false } - if ctlInputMethod.areWeDeleting && !deleteTargetExists { + if ctlInputMethod.areWeDeleting, !deleteTargetExists { return false } return markedRange.length >= kMinMarkRangeLength @@ -313,7 +332,8 @@ class InputState: NSObject { let selectedReadings = readings[exactBegin.." } } - } class SymbolNode: NSObject { @@ -457,7 +478,7 @@ class SymbolNode: NSObject { @objc static let catLineSegments = String( format: NSLocalizedString("catLineSegments", comment: "")) - @objc static let root: SymbolNode = SymbolNode( + @objc static let root: SymbolNode = .init( "/", [ SymbolNode("`"), @@ -465,18 +486,21 @@ class SymbolNode: NSObject { SymbolNode(catHoriBrackets, symbols: "()「」〔〕{}〈〉『』《》【】﹙﹚﹝﹞﹛﹜"), SymbolNode(catVertBrackets, symbols: "︵︶﹁﹂︹︺︷︸︿﹀﹃﹄︽︾︻︼"), SymbolNode( - catGreekLetters, symbols: "αβγδεζηθικλμνξοπρστυφχψωΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ"), + catGreekLetters, symbols: "αβγδεζηθικλμνξοπρστυφχψωΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ" + ), SymbolNode(catMathSymbols, symbols: "+-×÷=≠≒∞±√<>﹤﹥≦≧∩∪ˇ⊥∠∟⊿㏒㏑∫∮∵∴╳﹢"), SymbolNode(catCurrencyUnits, symbols: "$€¥¢£₽₨₩฿₺₮₱₭₴₦৲৳૱௹﷼₹₲₪₡₫៛₵₢₸₤₳₥₠₣₰₧₯₶₷"), SymbolNode(catSpecialSymbols, symbols: "↑↓←→↖↗↙↘↺⇧⇩⇦⇨⇄⇆⇅⇵↻◎○●⊕⊙※△▲☆★◇◆□■▽▼§¥〒¢£♀♂↯"), SymbolNode(catUnicodeSymbols, symbols: "♨☀☁☂☃♠♥♣♦♩♪♫♬☺☻"), SymbolNode(catCircledKanjis, symbols: "㊟㊞㊚㊛㊊㊋㊌㊍㊎㊏㊐㊑㊒㊓㊔㊕㊖㊗︎㊘㊙︎㊜㊝㊠㊡㊢㊣㊤㊥㊦㊧㊨㊩㊪㊫㊬㊭㊮㊯㊰🈚︎🈯︎"), SymbolNode( - catCircledKataKana, symbols: "㋐㋑㋒㋓㋔㋕㋖㋗㋘㋙㋚㋛㋜㋝㋞㋟㋠㋡㋢㋣㋤㋥㋦㋧㋨㋩㋪㋫㋬㋭㋮㋯㋰㋱㋲㋳㋴㋵㋶㋷㋸㋹㋺㋻㋼㋾"), + catCircledKataKana, symbols: "㋐㋑㋒㋓㋔㋕㋖㋗㋘㋙㋚㋛㋜㋝㋞㋟㋠㋡㋢㋣㋤㋥㋦㋧㋨㋩㋪㋫㋬㋭㋮㋯㋰㋱㋲㋳㋴㋵㋶㋷㋸㋹㋺㋻㋼㋾" + ), SymbolNode(catBracketKanjis, symbols: "㈪㈫㈬㈭㈮㈯㈰㈱㈲㈳㈴㈵㈶㈷㈸㈹㈺㈻㈼㈽㈾㈿㉀㉁㉂㉃"), SymbolNode(catSingleTableLines, symbols: "├─┼┴┬┤┌┐╞═╪╡│▕└┘╭╮╰╯"), SymbolNode(catDoubleTableLines, symbols: "╔╦╗╠═╬╣╓╥╖╒╤╕║╚╩╝╟╫╢╙╨╜╞╪╡╘╧╛"), SymbolNode(catFillingBlocks, symbols: "_ˍ▁▂▃▄▅▆▇█▏▎▍▌▋▊▉◢◣◥◤"), SymbolNode(catLineSegments, symbols: "﹣﹦≡|∣∥–︱—︳╴¯ ̄﹉﹊﹍﹎﹋﹌﹏︴∕﹨╱╲/\"), - ]) + ] + ) } diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift index 5f9857ae..7d3e5916 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift @@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa // MARK: - § Handle Candidate State. + @objc extension KeyHandler { func _handleCandidateState( _ state: InputState, @@ -75,7 +76,8 @@ import Cocoa delegate!.keyHandler( self, didSelectCandidateAt: Int(ctlCandidateCurrent.selectedCandidateIndex), - ctlCandidate: ctlCandidateCurrent) + ctlCandidate: ctlCandidateCurrent + ) return true } @@ -232,17 +234,18 @@ import Cocoa candidates = (state as! InputState.AssociatedPhrases).candidates } - if candidates.isEmpty { return false } - - if (input.isEnd || input.emacsKey == vChewingEmacsKey.end) && candidates.count > 0 { - if ctlCandidateCurrent.selectedCandidateIndex == UInt(candidates.count - 1) { - IME.prtDebugIntel("9B69AAAD") - errorCallback() - } else { - ctlCandidateCurrent.selectedCandidateIndex = UInt(candidates.count - 1) + if candidates.isEmpty { + return false + } else { // 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。 + if input.isEnd || input.emacsKey == vChewingEmacsKey.end { + if ctlCandidateCurrent.selectedCandidateIndex == UInt(candidates.count - 1) { + IME.prtDebugIntel("9B69AAAD") + errorCallback() + } else { + ctlCandidateCurrent.selectedCandidateIndex = UInt(candidates.count - 1) + } + return true } - - return true } if state is InputState.AssociatedPhrases { @@ -300,7 +303,7 @@ import Cocoa chkKeyValidity(charCode) || ifLangModelHasUnigrams(forKey: customPunctuation) || ifLangModelHasUnigrams(forKey: punctuation) - if !shouldAutoSelectCandidate && input.isUpperCaseASCIILetterKey { + if !shouldAutoSelectCandidate, input.isUpperCaseASCIILetterKey { let letter: String! = String(format: "%@%c", "_letter_", CChar(charCode)) if ifLangModelHasUnigrams(forKey: letter) { shouldAutoSelectCandidate = true } } @@ -311,12 +314,14 @@ import Cocoa delegate!.keyHandler( self, didSelectCandidateAt: Int(candidateIndex), - ctlCandidate: ctlCandidateCurrent) + ctlCandidate: ctlCandidateCurrent + ) clear() let empty = InputState.EmptyIgnoringPreviousState() stateCallback(empty) return handle( - input: input, state: empty, stateCallback: stateCallback, errorCallback: errorCallback) + input: input, state: empty, stateCallback: stateCallback, errorCallback: errorCallback + ) } return true } diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift index 71cdea47..cc4ce2fe 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift @@ -43,7 +43,7 @@ import Cocoa // Ignore the input if its inputText is empty. // Reason: such inputs may be functional key combinations. - if (inputText).isEmpty { + if inputText.isEmpty { return false } @@ -56,6 +56,7 @@ import Cocoa } // MARK: Caps Lock processing. + // If Caps Lock is ON, temporarily disable bopomofo. // Note: Alphanumerical mode processing. if input.isBackSpace || input.isEnter || input.isAbsorbedArrowKey || input.isExtraChooseCandidateKey @@ -75,7 +76,7 @@ import Cocoa // If ASCII but not printable, don't use insertText:replacementRange: // Certain apps don't handle non-ASCII char insertions. - if charCode < 0x80 && !isPrintable(charCode) { + if charCode < 0x80, !isPrintable(charCode) { return false } @@ -88,9 +89,10 @@ import Cocoa } // MARK: Numeric Pad Processing. + if input.isNumericPad { - if !input.isLeft && !input.isRight && !input.isDown - && !input.isUp && !input.isSpace && isPrintable(charCode) + if !input.isLeft, !input.isRight, !input.isDown, + !input.isUp, !input.isSpace, isPrintable(charCode) { clear() stateCallback(emptyState) @@ -102,15 +104,19 @@ import Cocoa } // MARK: Handle Candidates. + if state is InputState.ChoosingCandidate { return _handleCandidateState( - state, input: input, stateCallback: stateCallback, errorCallback: errorCallback) + state, input: input, stateCallback: stateCallback, errorCallback: errorCallback + ) } // MARK: Handle Associated Phrases. + if state is InputState.AssociatedPhrases { let result = _handleCandidateState( - state, input: input, stateCallback: stateCallback, errorCallback: errorCallback) + state, input: input, stateCallback: stateCallback, errorCallback: errorCallback + ) if result { return true } else { @@ -119,13 +125,14 @@ import Cocoa } // MARK: Handle Marking. + if state is InputState.Marking { let marking = state as! InputState.Marking if _handleMarkingState( state as! InputState.Marking, input: input, stateCallback: stateCallback, - errorCallback: errorCallback) - { + errorCallback: errorCallback + ) { return true } @@ -134,7 +141,8 @@ import Cocoa } // MARK: Handle BPMF Keys. - var composeReading: Bool = false + + var composeReading = false let skipPhoneticHandling = input.isReservedKey || input.isControlHold || input.isOptionHold // See if Phonetic reading is valid. @@ -150,7 +158,6 @@ import Cocoa stateCallback(inputting) return true } - } // See if we have composition if Enter/Space is hit and buffer is not empty. @@ -187,7 +194,8 @@ import Cocoa if mgrPrefs.useSCPCTypingMode { let choosingCandidates: InputState.ChoosingCandidate = _buildCandidateState( inputting, - useVerticalMode: input.useVerticalMode) + useVerticalMode: input.useVerticalMode + ) if choosingCandidates.candidates.count == 1 { clear() let text: String = choosingCandidates.candidates.first ?? "" @@ -200,7 +208,8 @@ import Cocoa let associatedPhrases = buildAssociatePhraseState( withKey: text, - useVerticalMode: input.useVerticalMode) as? InputState.AssociatedPhrases + useVerticalMode: input.useVerticalMode + ) as? InputState.AssociatedPhrases if let associatedPhrases = associatedPhrases { stateCallback(associatedPhrases) } else { @@ -247,7 +256,8 @@ import Cocoa } let choosingCandidates = _buildCandidateState( state as! InputState.NotEmpty, - useVerticalMode: input.useVerticalMode) + useVerticalMode: input.useVerticalMode + ) stateCallback(choosingCandidates) return true } @@ -255,59 +265,72 @@ import Cocoa // MARK: - // MARK: Esc + if input.isESC { return _handleEscWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Cursor backward + if input.isCursorBackward || input.emacsKey == vChewingEmacsKey.backward { return _handleBackwardWithState( state, input: input, stateCallback: stateCallback, - errorCallback: errorCallback) + errorCallback: errorCallback + ) } // MARK: Cursor forward + if input.isCursorForward || input.emacsKey == vChewingEmacsKey.forward { return _handleForwardWithState( - state, input: input, stateCallback: stateCallback, errorCallback: errorCallback) + state, input: input, stateCallback: stateCallback, errorCallback: errorCallback + ) } // MARK: Home + if input.isHome || input.emacsKey == vChewingEmacsKey.home { return _handleHomeWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: End + if input.isEnd || input.emacsKey == vChewingEmacsKey.end { return _handleEndWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Ctrl+PgLf or Shift+PgLf + if (input.isControlHold || input.isShiftHold) && (input.isOptionHold && input.isLeft) { return _handleHomeWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Ctrl+PgRt or Shift+PgRt + if (input.isControlHold || input.isShiftHold) && (input.isOptionHold && input.isRight) { return _handleEndWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: AbsorbedArrowKey + if input.isAbsorbedArrowKey || input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse { return _handleAbsorbedArrowKeyWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Backspace + if input.isBackSpace { return _handleBackspaceWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Delete + if input.isDelete || input.emacsKey == vChewingEmacsKey.delete { return _handleDeleteWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) } // MARK: Enter + if input.isEnter { return (input.isCommandHold && input.isControlHold) ? _handleCtrlCommandEnterWithState(state, stateCallback: stateCallback, errorCallback: errorCallback) @@ -317,6 +340,7 @@ import Cocoa // MARK: - // MARK: Punctuation list + if input.isSymbolMenuPhysicalKey && !input.isShiftHold { if !input.isOptionHold { if ifLangModelHasUnigrams(forKey: "_punctuation_list") { @@ -349,6 +373,7 @@ import Cocoa } // MARK: Punctuation + // if nothing is matched, see if it's a punctuation key for current layout. var punctuationNamePrefix = "" @@ -373,8 +398,8 @@ import Cocoa state: state, usingVerticalMode: input.useVerticalMode, stateCallback: stateCallback, - errorCallback: errorCallback) - { + errorCallback: errorCallback + ) { return true } @@ -387,8 +412,8 @@ import Cocoa state: state, usingVerticalMode: input.useVerticalMode, stateCallback: stateCallback, - errorCallback: errorCallback) - { + errorCallback: errorCallback + ) { return true } @@ -400,13 +425,14 @@ import Cocoa state: state, usingVerticalMode: input.useVerticalMode, stateCallback: stateCallback, - errorCallback: errorCallback) - { + errorCallback: errorCallback + ) { return true } } // MARK: - Still Nothing. + // Still nothing? Then we update the composing buffer. // Note that some app has strange behavior if we don't do this, // "thinking" that the key is not actually consumed. diff --git a/Source/Modules/ControllerModules/KeyHandler_Misc.swift b/Source/Modules/ControllerModules/KeyHandler_Misc.swift index a28d5219..9abf05b2 100644 --- a/Source/Modules/ControllerModules/KeyHandler_Misc.swift +++ b/Source/Modules/ControllerModules/KeyHandler_Misc.swift @@ -27,10 +27,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa // MARK: - § Misc functions. -@objc extension KeyHandler { +@objc extension KeyHandler { func getCurrentMandarinParser() -> String { - return (mgrPrefs.mandarinParserName + "_") + mgrPrefs.mandarinParserName + "_" } func _actualCandidateCursorIndex() -> Int { diff --git a/Source/Modules/ControllerModules/KeyHandler_States.swift b/Source/Modules/ControllerModules/KeyHandler_States.swift index df970152..15fe7a65 100644 --- a/Source/Modules/ControllerModules/KeyHandler_States.swift +++ b/Source/Modules/ControllerModules/KeyHandler_States.swift @@ -27,9 +27,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa // MARK: - § State managements. -@objc extension KeyHandler { +@objc extension KeyHandler { // MARK: - 構築狀態(State Building) + func buildInputtingState() -> InputState.Inputting { // 觸發資料封裝更新,否則下文拿到的數據會是錯的。 packageBufferStateMaterials() @@ -44,16 +45,17 @@ import Cocoa // 組建提示文本 var tooltip = "" - if (resultOfBefore == "") && (resultOfAfter != "") { + if resultOfBefore == "", resultOfAfter != "" { tooltip = String(format: NSLocalizedString("Cursor is after \"%@\".", comment: ""), resultOfAfter) } - if (resultOfBefore != "") && (resultOfAfter == "") { + if resultOfBefore != "", resultOfAfter == "" { tooltip = String(format: NSLocalizedString("Cursor is before \"%@\".", comment: ""), resultOfBefore) } - if (resultOfBefore != "") && (resultOfAfter != "") { + if resultOfBefore != "", resultOfAfter != "" { tooltip = String( format: NSLocalizedString("Cursor is between \"%@\" and \"%@\".", comment: ""), - resultOfAfter, resultOfBefore) + resultOfAfter, resultOfBefore + ) } // 給新狀態安插配置好的提示文本、且送出新狀態 @@ -62,6 +64,7 @@ import Cocoa } // MARK: - 用以生成候選詞數組 + func _buildCandidateState( _ currentState: InputState.NotEmpty, useVerticalMode: Bool @@ -72,18 +75,19 @@ import Cocoa composingBuffer: currentState.composingBuffer, cursorIndex: currentState.cursorIndex, candidates: candidatesArray, - useVerticalMode: useVerticalMode) + useVerticalMode: useVerticalMode + ) return state } // MARK: - 用以處理就地新增自訂語彙時的行為 + func _handleMarkingState( _ state: InputState.Marking, input: keyParser, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void ) -> Bool { - if input.isESC { let inputting = buildInputtingState() stateCallback(inputting) @@ -106,7 +110,7 @@ import Cocoa } // Shift + Left - if (input.isCursorBackward || input.emacsKey == vChewingEmacsKey.backward) && (input.isShiftHold) { + if input.isCursorBackward || input.emacsKey == vChewingEmacsKey.backward, input.isShiftHold { var index = state.markerIndex if index > 0 { index = UInt((state.composingBuffer as NSString).previousUtf16Position(for: Int(index))) @@ -114,7 +118,8 @@ import Cocoa composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex, markerIndex: index, - readings: state.readings) + readings: state.readings + ) marking.tooltipForInputting = state.tooltipForInputting if marking.markedRange.length == 0 { @@ -132,7 +137,7 @@ import Cocoa } // Shift + Right - if (input.isCursorForward || input.emacsKey == vChewingEmacsKey.forward) && (input.isShiftHold) { + if input.isCursorForward || input.emacsKey == vChewingEmacsKey.forward, input.isShiftHold { var index = state.markerIndex // 這裡繼續用 NSString 是為了與 Zonble 之前引入的 NSStringUtils 相容。 // 不然的話,這行判斷會失敗、引發「9B51408D」錯誤。 @@ -142,7 +147,8 @@ import Cocoa composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex, markerIndex: index, - readings: state.readings) + readings: state.readings + ) marking.tooltipForInputting = state.tooltipForInputting if marking.markedRange.length == 0 { let inputting = marking.convertToInputting() @@ -161,6 +167,7 @@ import Cocoa } // MARK: - 標點輸入處理 + func _handlePunctuation( _ customPunctuation: String, state: InputState, @@ -179,9 +186,10 @@ import Cocoa inputting.poppedText = poppedText stateCallback(inputting) - if mgrPrefs.useSCPCTypingMode && isPhoneticReadingBufferEmpty() { + if mgrPrefs.useSCPCTypingMode, isPhoneticReadingBufferEmpty() { let candidateState = _buildCandidateState( - inputting, useVerticalMode: useVerticalMode) + inputting, useVerticalMode: useVerticalMode + ) if candidateState.candidates.count == 1 { clear() if let strPoppedText: String = candidateState.candidates.first { @@ -208,10 +216,11 @@ import Cocoa } // MARK: - Enter 鍵處理 + @discardableResult func _handleEnterWithState( _ state: InputState, stateCallback: @escaping (InputState) -> Void, - errorCallback: @escaping () -> Void + errorCallback _: @escaping () -> Void ) -> Bool { if !(state is InputState.Inputting) { return false @@ -230,10 +239,11 @@ import Cocoa } // MARK: - CMD+Enter 鍵處理 + func _handleCtrlCommandEnterWithState( _ state: InputState, stateCallback: @escaping (InputState) -> Void, - errorCallback: @escaping () -> Void + errorCallback _: @escaping () -> Void ) -> Bool { if !(state is InputState.Inputting) { return false @@ -255,6 +265,7 @@ import Cocoa } // MARK: - 處理 Backspace (macOS Delete) 按鍵行為 + func _handleBackspaceWithState( _ state: InputState, stateCallback: @escaping (InputState) -> Void, @@ -278,7 +289,7 @@ import Cocoa doBackSpaceToPhoneticReadingBuffer() } - if isPhoneticReadingBufferEmpty() && (getBuilderLength() == 0) { + if isPhoneticReadingBufferEmpty(), getBuilderLength() == 0 { let empty = InputState.EmptyIgnoringPreviousState() stateCallback(empty) } else { @@ -289,6 +300,7 @@ import Cocoa } // MARK: - 處理 PC Delete (macOS Fn+BackSpace) 按鍵行為 + func _handleDeleteWithState( _ state: InputState, stateCallback: @escaping (InputState) -> Void, @@ -303,7 +315,8 @@ import Cocoa deleteBuilderReadingAfterCursor() _walk() let inputting = buildInputtingState() - if inputting.composingBuffer.count == 0 { + // 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。 + if !inputting.composingBuffer.isEmpty { let empty = InputState.EmptyIgnoringPreviousState() stateCallback(empty) } else { @@ -324,6 +337,7 @@ import Cocoa } // MARK: - 處理與當前文字輸入排版前後方向呈 90 度的那兩個方向鍵的按鍵行為 + func _handleAbsorbedArrowKeyWithState( _ state: InputState, stateCallback: @escaping (InputState) -> Void, @@ -341,6 +355,7 @@ import Cocoa } // MARK: - 處理 Home 鍵行為 + func _handleHomeWithState( _ state: InputState, stateCallback: @escaping (InputState) -> Void, @@ -371,6 +386,7 @@ import Cocoa } // MARK: - 處理 End 鍵行為 + func _handleEndWithState( _ state: InputState, stateCallback: @escaping (InputState) -> Void, @@ -401,10 +417,11 @@ import Cocoa } // MARK: - 處理 Esc 鍵行為 + func _handleEscWithState( _ state: InputState, stateCallback: @escaping (InputState) -> Void, - errorCallback: @escaping () -> Void + errorCallback _: @escaping () -> Void ) -> Bool { if !(state is InputState.Inputting) { return false } @@ -433,14 +450,15 @@ import Cocoa } return true } + // MARK: - 處理向前方向鍵的行為 + func _handleForwardWithState( _ state: InputState, input: keyParser, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void ) -> Bool { - if !(state is InputState.Inputting) { return false } if !isPhoneticReadingBufferEmpty() { @@ -461,7 +479,8 @@ import Cocoa composingBuffer: currentState.composingBuffer, cursorIndex: currentState.cursorIndex, markerIndex: UInt(nextPosition), - readings: _currentReadings()) + readings: _currentReadings() + ) marking.tooltipForInputting = currentState.tooltip stateCallback(marking) } else { @@ -484,13 +503,13 @@ import Cocoa } // MARK: - 處理向後方向鍵的行為 + func _handleBackwardWithState( _ state: InputState, input: keyParser, stateCallback: @escaping (InputState) -> Void, errorCallback: @escaping () -> Void ) -> Bool { - if !(state is InputState.Inputting) { return false } if !isPhoneticReadingBufferEmpty() { @@ -511,7 +530,8 @@ import Cocoa composingBuffer: currentState.composingBuffer, cursorIndex: currentState.cursorIndex, markerIndex: UInt(previousPosition), - readings: _currentReadings()) + readings: _currentReadings() + ) marking.tooltipForInputting = currentState.tooltip stateCallback(marking) } else { diff --git a/Source/Modules/ControllerModules/KeyParser.swift b/Source/Modules/ControllerModules/KeyParser.swift index bd06ec0a..d08547db 100644 --- a/Source/Modules/ControllerModules/KeyParser.swift +++ b/Source/Modules/ControllerModules/KeyParser.swift @@ -83,8 +83,8 @@ import Cocoa } // CharCodes: https://theasciicode.com.ar/ascii-control-characters/horizontal-tab-ascii-code-9.html -enum CharCode: UInt /*16*/ { - case yajuusenpai = 114_514_19_19_810_893 +enum CharCode: UInt /* 16 */ { + case yajuusenpai = 114_514_191_191_810_893 // CharCode is not reliable at all. KeyCode is the most appropriate choice due to its accuracy. // KeyCode doesn't give a phuque about the character sent through macOS keyboard layouts ... // ... but only focuses on which physical key is pressed. @@ -121,7 +121,8 @@ class keyParser: NSObject { self.keyCode = keyCode self.charCode = AppleKeyboardConverter.cnvApple2ABC(charCode) emacsKey = EmacsKeyHelper.detect( - charCode: AppleKeyboardConverter.cnvApple2ABC(charCode), flags: flags) + charCode: AppleKeyboardConverter.cnvApple2ABC(charCode), flags: flags + ) // Define Arrow Keys cursorForwardKey = useVerticalMode ? .kDownArrow : .kRightArrow cursorBackwardKey = useVerticalMode ? .kUpArrow : .kLeftArrow @@ -141,7 +142,8 @@ class keyParser: NSObject { isFlagChanged = (event.type == .flagsChanged) ? true : false useVerticalMode = isVerticalMode let charCode: UInt16 = { - guard let inputText = event.characters, inputText.count > 0 else { + // 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。 + guard let inputText = event.characters, !inputText.isEmpty else { return 0 } let first = inputText[inputText.startIndex].utf16.first! @@ -149,7 +151,8 @@ class keyParser: NSObject { }() self.charCode = AppleKeyboardConverter.cnvApple2ABC(charCode) emacsKey = EmacsKeyHelper.detect( - charCode: AppleKeyboardConverter.cnvApple2ABC(charCode), flags: flags) + charCode: AppleKeyboardConverter.cnvApple2ABC(charCode), flags: flags + ) // Define Arrow Keys in the same way above. cursorForwardKey = useVerticalMode ? .kDownArrow : .kRightArrow cursorBackwardKey = useVerticalMode ? .kUpArrow : .kLeftArrow @@ -303,7 +306,6 @@ class keyParser: NSObject { // 只是必須得與 ![input isShift] 搭配使用才可以(也就是僅判定 Shift 沒被摁下的情形)。 KeyCode(rawValue: keyCode) == KeyCode.kSymbolMenuPhysicalKey } - } @objc enum vChewingEmacsKey: UInt16 { diff --git a/Source/Modules/ControllerModules/NSStringUtils.swift b/Source/Modules/ControllerModules/NSStringUtils.swift index 20394f81..b2cf0944 100644 --- a/Source/Modules/ControllerModules/NSStringUtils.swift +++ b/Source/Modules/ControllerModules/NSStringUtils.swift @@ -27,7 +27,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa extension NSString { - /// Converts the index in an NSString to the index in a Swift string. /// /// An Emoji might be compose by more than one UTF-16 code points, however diff --git a/Source/Modules/ControllerModules/vChewingKanjiConverter.swift b/Source/Modules/ControllerModules/vChewingKanjiConverter.swift index 0504d382..3d84cd9b 100644 --- a/Source/Modules/ControllerModules/vChewingKanjiConverter.swift +++ b/Source/Modules/ControllerModules/vChewingKanjiConverter.swift @@ -26,7 +26,7 @@ import Cocoa extension String { fileprivate mutating func selfReplace(_ strOf: String, _ strWith: String = "") { - self = self.replacingOccurrences(of: strOf, with: strWith) + self = replacingOccurrences(of: strOf, with: strWith) } } diff --git a/Source/Modules/FileHandlers/FSEventStreamHelper.swift b/Source/Modules/FileHandlers/FSEventStreamHelper.swift index 406a018c..14d19dab 100644 --- a/Source/Modules/FileHandlers/FSEventStreamHelper.swift +++ b/Source/Modules/FileHandlers/FSEventStreamHelper.swift @@ -31,7 +31,6 @@ public protocol FSEventStreamHelperDelegate: AnyObject { } public class FSEventStreamHelper: NSObject { - public struct Event { var path: String var flags: FSEventStreamEventFlags @@ -59,7 +58,7 @@ public class FSEventStreamHelper: NSObject { let stream = FSEventStreamCreate( nil, { - (_, clientCallBackInfo, eventCount, eventPaths, eventFlags, eventIds) in + _, clientCallBackInfo, eventCount, eventPaths, eventFlags, eventIds in let helper = Unmanaged.fromOpaque(clientCallBackInfo!) .takeUnretainedValue() let pathsBase = eventPaths.assumingMemoryBound(to: UnsafePointer.self) @@ -70,7 +69,8 @@ public class FSEventStreamHelper: NSObject { FSEventStreamHelper.Event( path: String(cString: pathsPtr[$0]), flags: flagsPtr[$0], - id: eventIDsPtr[$0]) + id: eventIDsPtr[$0] + ) } helper.delegate?.helper(helper, didReceive: events) }, diff --git a/Source/Modules/IMEModules/IME.swift b/Source/Modules/IMEModules/IME.swift index f137073f..6abcd603 100644 --- a/Source/Modules/IMEModules/IME.swift +++ b/Source/Modules/IMEModules/IME.swift @@ -30,14 +30,17 @@ public class IME: NSObject { static let dlgOpenPath = NSOpenPanel() // MARK: - 開關判定當前應用究竟是? + @objc static var areWeUsingOurOwnPhraseEditor: Bool = false // MARK: - 自 ctlInputMethod 讀取當前輸入法的簡繁體模式 + static func getInputMode() -> InputMode { ctlInputMethod.currentKeyHandler.inputMode } // MARK: - Print debug information to the console. + @objc static func prtDebugIntel(_ strPrint: String) { if mgrPrefs.isDebugModeEnabled { NSLog("vChewingErrorCallback: %@", strPrint) @@ -45,11 +48,13 @@ public class IME: NSObject { } // MARK: - Tell whether this IME is running with Root privileges. + @objc static var isSudoMode: Bool { NSUserName() == "root" } // MARK: - Initializing Language Models. + @objc static func initLangModels(userOnly: Bool) { if !userOnly { mgrLangModel.loadDataModels() // 這句還是不要砍了。 @@ -63,6 +68,7 @@ public class IME: NSObject { } // MARK: - System Dark Mode Status Detector. + @objc static func isDarkMode() -> Bool { if #available(macOS 10.15, *) { let appearanceDescription = NSApplication.shared.effectiveAppearance.debugDescription @@ -83,6 +89,7 @@ public class IME: NSObject { } // MARK: - Open a phrase data file. + static func openPhraseFile(userFileAt path: String) { func checkIfUserFilesExist() -> Bool { if !mgrLangModel.chkUserLMFilesExist(InputMode.imeModeCHS) @@ -90,12 +97,15 @@ public class IME: NSObject { { let content = String( format: NSLocalizedString( - "Please check the permission at \"%@\".", comment: ""), - mgrLangModel.dataFolderPath(isDefaultFolder: false)) + "Please check the permission at \"%@\".", comment: "" + ), + mgrLangModel.dataFolderPath(isDefaultFolder: false) + ) ctlNonModalAlertWindow.shared.show( title: NSLocalizedString("Unable to create the user phrase file.", comment: ""), content: content, confirmButtonTitle: NSLocalizedString("OK", comment: ""), - cancelButtonTitle: nil, cancelAsDefault: false, delegate: nil) + cancelButtonTitle: nil, cancelAsDefault: false, delegate: nil + ) NSApp.setActivationPolicy(.accessory) return false } @@ -109,12 +119,14 @@ public class IME: NSObject { } // MARK: - Trash a file if it exists. + @discardableResult static func trashTargetIfExists(_ path: String) -> Bool { do { if FileManager.default.fileExists(atPath: path) { // 塞入垃圾桶 try FileManager.default.trashItem( - at: URL(fileURLWithPath: path), resultingItemURL: nil) + at: URL(fileURLWithPath: path), resultingItemURL: nil + ) } else { NSLog("Item doesn't exist: \(path)") } @@ -126,6 +138,7 @@ public class IME: NSObject { } // MARK: - Uninstall the input method. + @discardableResult static func uninstall(isSudo: Bool = false, selfKill: Bool = true) -> Int32 { // 輸入法自毀處理。這裡不用「Bundle.main.bundleURL」是為了方便使用者以 sudo 身分來移除被錯誤安裝到系統目錄內的輸入法。 guard let bundleID = Bundle.main.bundleIdentifier else { @@ -155,8 +168,8 @@ public class IME: NSObject { let objFullPath = pathLibrary + pathUnitKeyboardLayouts + objPath if !IME.trashTargetIfExists(objFullPath) { return -1 } } - if CommandLine.arguments.count > 2 && CommandLine.arguments[2] == "--all" - && CommandLine.arguments[1] == "uninstall" + if CommandLine.arguments.count > 2, CommandLine.arguments[2] == "--all", + CommandLine.arguments[1] == "uninstall" { // 再處理是否需要移除放在預設使用者資料夾內的檔案的情況。 // 如果使用者有在輸入法偏好設定內將該目錄改到別的地方(而不是用 symbol link)的話,則不處理。 @@ -177,6 +190,7 @@ public class IME: NSObject { } // MARK: - Registering the input method. + @discardableResult static func registerInputMethod() -> Int32 { guard let bundleID = Bundle.main.bundleIdentifier else { return -1 @@ -217,7 +231,7 @@ public class IME: NSObject { } } - if CommandLine.arguments.count > 2 && CommandLine.arguments[2] == "--all" { + if CommandLine.arguments.count > 2, CommandLine.arguments[2] == "--all" { let enabled = InputSourceHelper.enableAllInputMode(for: bundleID) NSLog( enabled @@ -228,10 +242,12 @@ public class IME: NSObject { } // MARK: - 準備枚舉系統內所有的 ASCII 鍵盤佈局 + struct CarbonKeyboardLayout { var strName: String = "" var strValue: String = "" } + static let arrWhitelistedKeyLayoutsASCII: [String] = [ "com.apple.keylayout.ABC", "com.apple.keylayout.ABC-AZERTY", @@ -247,12 +263,14 @@ public class IME: NSObject { // 提前塞入 macOS 內建的兩款動態鍵盤佈局 var arrKeyLayouts: [IME.CarbonKeyboardLayout] = [] arrKeyLayouts += [ - IME.CarbonKeyboardLayout.init( + IME.CarbonKeyboardLayout( strName: NSLocalizedString("Apple Chewing - Dachen", comment: ""), - strValue: "com.apple.keylayout.ZhuyinBopomofo"), - IME.CarbonKeyboardLayout.init( + strValue: "com.apple.keylayout.ZhuyinBopomofo" + ), + IME.CarbonKeyboardLayout( strName: NSLocalizedString("Apple Chewing - Eten Traditional", comment: ""), - strValue: "com.apple.keylayout.ZhuyinEten"), + strValue: "com.apple.keylayout.ZhuyinEten" + ), ] // 準備枚舉系統內所有的 ASCII 鍵盤佈局 @@ -270,8 +288,8 @@ public class IME: NSObject { } if let ptrASCIICapable = TISGetInputSourceProperty( - source, kTISPropertyInputSourceIsASCIICapable) - { + source, kTISPropertyInputSourceIsASCIICapable + ) { let asciiCapable = Unmanaged.fromOpaque(ptrASCIICapable) .takeUnretainedValue() if asciiCapable != kCFBooleanTrue { @@ -302,13 +320,13 @@ public class IME: NSObject { if sourceID.contains("vChewing") { arrKeyLayoutsMACV += [ - IME.CarbonKeyboardLayout.init(strName: localizedName, strValue: sourceID) + IME.CarbonKeyboardLayout(strName: localizedName, strValue: sourceID) ] } if IME.arrWhitelistedKeyLayoutsASCII.contains(sourceID) { arrKeyLayoutsASCII += [ - IME.CarbonKeyboardLayout.init(strName: localizedName, strValue: sourceID) + IME.CarbonKeyboardLayout(strName: localizedName, strValue: sourceID) ] } } @@ -316,7 +334,6 @@ public class IME: NSObject { arrKeyLayouts += arrKeyLayoutsASCII return arrKeyLayouts } - } // MARK: - Root Extensions @@ -331,6 +348,7 @@ extension RangeReplaceableCollection where Element: Hashable { } // MARK: - Error Extension + extension String: Error {} extension String: LocalizedError { public var errorDescription: String? { @@ -339,6 +357,7 @@ extension String: LocalizedError { } // MARK: - Ensuring trailing slash of a string: + extension String { mutating func ensureTrailingSlash() { if !hasSuffix("/") { diff --git a/Source/Modules/IMEModules/InputSourceHelper.swift b/Source/Modules/IMEModules/InputSourceHelper.swift index f045d4cf..d2f6c98b 100644 --- a/Source/Modules/IMEModules/InputSourceHelper.swift +++ b/Source/Modules/IMEModules/InputSourceHelper.swift @@ -28,9 +28,8 @@ import Carbon import Cocoa public class InputSourceHelper: NSObject { - @available(*, unavailable) - public override init() { + override public init() { super.init() } @@ -89,7 +88,7 @@ public class InputSourceHelper: NSObject { } let bundleID = Unmanaged.fromOpaque(bundleIDPtr).takeUnretainedValue() if String(bundleID) == inputSourceBundleD { - let modeEnabled = self.enable(inputSource: source) + let modeEnabled = enable(inputSource: source) if !modeEnabled { return false } @@ -111,18 +110,16 @@ public class InputSourceHelper: NSObject { let inputsSourceBundleID = Unmanaged.fromOpaque(bundleIDPtr) .takeUnretainedValue() let inputsSourceModeID = Unmanaged.fromOpaque(modePtr).takeUnretainedValue() - if modeID == String(inputsSourceModeID) && bundleID == String(inputsSourceBundleID) { + if modeID == String(inputsSourceModeID), bundleID == String(inputsSourceBundleID) { let enabled = enable(inputSource: source) print( "Attempt to enable input source of mode: \(modeID), bundle ID: \(bundleID), result: \(enabled)" ) return enabled } - } print("Failed to find any matching input source of mode: \(modeID), bundle ID: \(bundleID)") return false - } @objc(disableInputSource:) @@ -136,5 +133,4 @@ public class InputSourceHelper: NSObject { let status = TISRegisterInputSource(url as CFURL) return status == noErr } - } diff --git a/Source/Modules/IMEModules/apiUpdate.swift b/Source/Modules/IMEModules/apiUpdate.swift index 6827ff50..d4d0b4a0 100644 --- a/Source/Modules/IMEModules/apiUpdate.swift +++ b/Source/Modules/IMEModules/apiUpdate.swift @@ -50,12 +50,14 @@ enum VersionUpdateApiError: Error, LocalizedError { return String( format: NSLocalizedString( "There may be no internet connection or the server failed to respond.\n\nError message: %@", - comment: ""), message) + comment: "" + ), message + ) } } } -struct VersionUpdateApi { +enum VersionUpdateApi { static let kCheckUpdateAutomatically = "CheckUpdateAutomatically" static let kNextUpdateCheckDateKey = "NextUpdateCheckDate" static let kUpdateInfoEndpointKey = "UpdateInfoEndpoint" @@ -75,7 +77,8 @@ struct VersionUpdateApi { let request = URLRequest( url: updateInfoURL, cachePolicy: .reloadIgnoringLocalCacheData, - timeoutInterval: kTimeoutInterval) + timeoutInterval: kTimeoutInterval + ) let task = URLSession.shared.dataTask(with: request) { data, _, error in if let error = error { DispatchQueue.main.async { @@ -92,7 +95,8 @@ struct VersionUpdateApi { do { guard let plist = try PropertyListSerialization.propertyList( - from: data ?? Data(), options: [], format: nil) as? [AnyHashable: Any], + from: data ?? Data(), options: [], format: nil + ) as? [AnyHashable: Any], let remoteVersion = plist[kCFBundleVersionKey] as? String, let infoDict = Bundle.main.infoDictionary else { @@ -109,7 +113,8 @@ struct VersionUpdateApi { let currentVersion = infoDict[kCFBundleVersionKey as String] as? String ?? "" let result = currentVersion.compare( - remoteVersion, options: .numeric, range: nil, locale: nil) + remoteVersion, options: .numeric, range: nil, locale: nil + ) if result != .orderedAscending { DispatchQueue.main.async { diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index d3cea4a8..206aa51a 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -38,7 +38,6 @@ extension ctlCandidate { @objc(ctlInputMethod) class ctlInputMethod: IMKInputController { - @objc static let kIMEModeCHS = "org.atelierInmu.inputmethod.vChewing.IMECHS" @objc static let kIMEModeCHT = "org.atelierInmu.inputmethod.vChewing.IMECHT" @objc static let kIMEModeNULL = "org.atelierInmu.inputmethod.vChewing.IMENULL" @@ -51,15 +50,15 @@ class ctlInputMethod: IMKInputController { private var currentClient: Any? - private var keyHandler: KeyHandler = KeyHandler() - private var state: InputState = InputState.Empty() + private var keyHandler: KeyHandler = .init() + private var state: InputState = .Empty() // 想讓 keyHandler 能夠被外界調查狀態與參數的話,就得對 keyHandler 做常態處理。 // 這樣 InputState 可以藉由這個 ctlInputMethod 了解到當前的輸入模式是簡體中文還是繁體中文。 // 然而,要是直接對 keyHandler 做常態處理的話,反而會導致 keyParser 無法協同處理。 // 所以才需要「currentKeyHandler」這個假 keyHandler。 // 這個「currentKeyHandler」僅用來讓其他模組知道當前的輸入模式是什麼模式,除此之外別無屌用。 - static var currentKeyHandler: KeyHandler = KeyHandler() + static var currentKeyHandler: KeyHandler = .init() @objc static var currentInputMode = mgrPrefs.mostRecentInputMode // MARK: - Keyboard Layout Specifier @@ -85,7 +84,7 @@ class ctlInputMethod: IMKInputController { func resetKeyHandler() { if let currentClient = currentClient { keyHandler.clear() - self.handle(state: InputState.Empty(), client: currentClient) + handle(state: InputState.Empty(), client: currentClient) } } @@ -103,7 +102,7 @@ class ctlInputMethod: IMKInputController { if bundleCheckID != Bundle.main.bundleIdentifier { // Override the keyboard layout to the basic one. setKeyLayout() - self.handle(state: .Empty(), client: client) + handle(state: .Empty(), client: client) } } (NSApp.delegate as? AppDelegate)?.checkForUpdate() @@ -112,11 +111,11 @@ class ctlInputMethod: IMKInputController { override func deactivateServer(_ client: Any!) { keyHandler.clear() currentClient = nil - self.handle(state: .Empty(), client: client) - self.handle(state: .Deactivated(), client: client) + handle(state: .Empty(), client: client) + handle(state: .Deactivated(), client: client) } - override func setValue(_ value: Any!, forTag tag: Int, client: Any!) { + override func setValue(_ value: Any!, forTag _: Int, client: Any!) { var newInputMode = InputMode(rawValue: value as? String ?? InputMode.imeModeNULL.rawValue) switch newInputMode { case InputMode.imeModeCHS: @@ -129,7 +128,6 @@ class ctlInputMethod: IMKInputController { mgrLangModel.loadDataModel(newInputMode) if keyHandler.inputMode != newInputMode { - UserDefaults.standard.synchronize() keyHandler.clear() keyHandler.inputMode = newInputMode @@ -137,7 +135,7 @@ class ctlInputMethod: IMKInputController { if bundleCheckID != Bundle.main.bundleIdentifier { // Remember to override the keyboard layout again -- treat this as an activate event. setKeyLayout() - self.handle(state: .Empty(), client: client) + handle(state: .Empty(), client: client) } } } @@ -148,13 +146,12 @@ class ctlInputMethod: IMKInputController { // MARK: - IMKServerInput protocol methods - override func recognizedEvents(_ sender: Any!) -> Int { + override func recognizedEvents(_: Any!) -> Int { let events: NSEvent.EventTypeMask = [.keyDown, .flagsChanged] return Int(events.rawValue) } override func handle(_ event: NSEvent!, client: Any!) -> Bool { - // 這裡仍舊需要判斷 flags。之前使輸入法狀態卡住無法敲漢字的問題已在 KeyHandler 內修復。 // 這裡不判斷 flags 的話,用方向鍵前後定位光標之後,再次試圖觸發組字區時、反而會在首次按鍵時失敗。 // 同時注意:必須在 event.type == .flagsChanged 結尾插入 return false, @@ -168,7 +165,8 @@ class ctlInputMethod: IMKInputController { var textFrame = NSRect.zero let attributes: [AnyHashable: Any]? = (client as? IMKTextInput)?.attributes( - forCharacterIndex: 0, lineHeightRectangle: &textFrame) + forCharacterIndex: 0, lineHeightRectangle: &textFrame + ) let useVerticalMode = (attributes?["IMKTextOrientation"] as? NSNumber)?.intValue == 0 || false @@ -194,7 +192,6 @@ class ctlInputMethod: IMKInputController { // MARK: - State Handling extension ctlInputMethod { - private func handle(state newState: InputState, client: Any?) { let previous = state state = newState @@ -219,17 +216,16 @@ extension ctlInputMethod { } private func commit(text: String, client: Any!) { - func kanjiConversionIfRequired(_ text: String) -> String { if keyHandler.inputMode == InputMode.imeModeCHT { - if !mgrPrefs.chineseConversionEnabled && mgrPrefs.shiftJISShinjitaiOutputEnabled { + if !mgrPrefs.chineseConversionEnabled, mgrPrefs.shiftJISShinjitaiOutputEnabled { return vChewingKanjiConverter.cnvTradToJIS(text) } - if mgrPrefs.chineseConversionEnabled && !mgrPrefs.shiftJISShinjitaiOutputEnabled { + if mgrPrefs.chineseConversionEnabled, !mgrPrefs.shiftJISShinjitaiOutputEnabled { return vChewingKanjiConverter.cnvTradToKangXi(text) } // 本來這兩個開關不該同時開啟的,但萬一被開啟了的話就這樣處理: - if mgrPrefs.chineseConversionEnabled && mgrPrefs.shiftJISShinjitaiOutputEnabled { + if mgrPrefs.chineseConversionEnabled, mgrPrefs.shiftJISShinjitaiOutputEnabled { return vChewingKanjiConverter.cnvTradToJIS(text) } // if (!mgrPrefs.chineseConversionEnabled && !mgrPrefs.shiftJISShinjitaiOutputEnabled) || (keyHandler.inputMode != InputMode.imeModeCHT); @@ -243,10 +239,11 @@ extension ctlInputMethod { return } (client as? IMKTextInput)?.insertText( - buffer, replacementRange: NSRange(location: NSNotFound, length: NSNotFound)) + buffer, replacementRange: NSRange(location: NSNotFound, length: NSNotFound) + ) } - private func handle(state: InputState.Deactivated, previous: InputState, client: Any?) { + private func handle(state _: InputState.Deactivated, previous: InputState, client: Any?) { currentClient = nil ctlCandidateCurrent?.delegate = nil @@ -258,10 +255,11 @@ extension ctlInputMethod { } (client as? IMKTextInput)?.setMarkedText( "", selectionRange: NSRange(location: 0, length: 0), - replacementRange: NSRange(location: NSNotFound, length: NSNotFound)) + replacementRange: NSRange(location: NSNotFound, length: NSNotFound) + ) } - private func handle(state: InputState.Empty, previous: InputState, client: Any?) { + private func handle(state _: InputState.Empty, previous: InputState, client: Any?) { ctlCandidateCurrent?.visible = false hideTooltip() @@ -274,11 +272,12 @@ extension ctlInputMethod { } client.setMarkedText( "", selectionRange: NSRange(location: 0, length: 0), - replacementRange: NSRange(location: NSNotFound, length: NSNotFound)) + replacementRange: NSRange(location: NSNotFound, length: NSNotFound) + ) } private func handle( - state: InputState.EmptyIgnoringPreviousState, previous: InputState, client: Any! + state _: InputState.EmptyIgnoringPreviousState, previous _: InputState, client: Any! ) { ctlCandidateCurrent?.visible = false hideTooltip() @@ -289,10 +288,11 @@ extension ctlInputMethod { client.setMarkedText( "", selectionRange: NSRange(location: 0, length: 0), - replacementRange: NSRange(location: NSNotFound, length: NSNotFound)) + replacementRange: NSRange(location: NSNotFound, length: NSNotFound) + ) } - private func handle(state: InputState.Committing, previous: InputState, client: Any?) { + private func handle(state: InputState.Committing, previous _: InputState, client: Any?) { ctlCandidateCurrent?.visible = false hideTooltip() @@ -306,10 +306,11 @@ extension ctlInputMethod { } client.setMarkedText( "", selectionRange: NSRange(location: 0, length: 0), - replacementRange: NSRange(location: NSNotFound, length: NSNotFound)) + replacementRange: NSRange(location: NSNotFound, length: NSNotFound) + ) } - private func handle(state: InputState.Inputting, previous: InputState, client: Any?) { + private func handle(state: InputState.Inputting, previous _: InputState, client: Any?) { ctlCandidateCurrent?.visible = false hideTooltip() @@ -326,15 +327,17 @@ extension ctlInputMethod { // i.e. the client app needs to take care of where to put this composing buffer client.setMarkedText( state.attributedString, selectionRange: NSRange(location: Int(state.cursorIndex), length: 0), - replacementRange: NSRange(location: NSNotFound, length: NSNotFound)) + replacementRange: NSRange(location: NSNotFound, length: NSNotFound) + ) if !state.tooltip.isEmpty { show( tooltip: state.tooltip, composingBuffer: state.composingBuffer, - cursorIndex: state.cursorIndex, client: client) + cursorIndex: state.cursorIndex, client: client + ) } } - private func handle(state: InputState.Marking, previous: InputState, client: Any?) { + private func handle(state: InputState.Marking, previous _: InputState, client: Any?) { ctlCandidateCurrent?.visible = false guard let client = client as? IMKTextInput else { hideTooltip() @@ -345,18 +348,20 @@ extension ctlInputMethod { // i.e. the client app needs to take care of where to put this composing buffer client.setMarkedText( state.attributedString, selectionRange: NSRange(location: Int(state.cursorIndex), length: 0), - replacementRange: NSRange(location: NSNotFound, length: NSNotFound)) + replacementRange: NSRange(location: NSNotFound, length: NSNotFound) + ) if state.tooltip.isEmpty { hideTooltip() } else { show( tooltip: state.tooltip, composingBuffer: state.composingBuffer, - cursorIndex: state.markerIndex, client: client) + cursorIndex: state.markerIndex, client: client + ) } } - private func handle(state: InputState.ChoosingCandidate, previous: InputState, client: Any?) { + private func handle(state: InputState.ChoosingCandidate, previous _: InputState, client: Any?) { hideTooltip() guard let client = client as? IMKTextInput else { ctlCandidateCurrent?.visible = false @@ -367,11 +372,12 @@ extension ctlInputMethod { // i.e. the client app needs to take care of where to put this composing buffer client.setMarkedText( state.attributedString, selectionRange: NSRange(location: Int(state.cursorIndex), length: 0), - replacementRange: NSRange(location: NSNotFound, length: NSNotFound)) + replacementRange: NSRange(location: NSNotFound, length: NSNotFound) + ) show(candidateWindowWith: state, client: client) } - private func handle(state: InputState.AssociatedPhrases, previous: InputState, client: Any?) { + private func handle(state: InputState.AssociatedPhrases, previous _: InputState, client: Any?) { hideTooltip() guard let client = client as? IMKTextInput else { ctlCandidateCurrent?.visible = false @@ -379,7 +385,8 @@ extension ctlInputMethod { } client.setMarkedText( "", selectionRange: NSRange(location: 0, length: 0), - replacementRange: NSRange(location: NSNotFound, length: NSNotFound)) + replacementRange: NSRange(location: NSNotFound, length: NSNotFound) + ) show(candidateWindowWith: state, client: client) } } @@ -387,7 +394,6 @@ extension ctlInputMethod { // MARK: - extension ctlInputMethod { - private func show(candidateWindowWith state: InputState, client: Any!) { let useVerticalMode: Bool = { var useVerticalMode = false @@ -449,9 +455,11 @@ extension ctlInputMethod { } ctlCandidateCurrent?.keyLabelFont = labelFont( - name: mgrPrefs.candidateKeyLabelFontName, size: keyLabelSize) + name: mgrPrefs.candidateKeyLabelFontName, size: keyLabelSize + ) ctlCandidateCurrent?.candidateFont = candidateFont( - name: mgrPrefs.candidateTextFontName, size: textSize) + name: mgrPrefs.candidateTextFontName, size: textSize + ) let candidateKeys = mgrPrefs.candidateKeys let keyLabels = @@ -468,42 +476,47 @@ extension ctlInputMethod { ctlCandidateCurrent?.visible = true var lineHeightRect = NSRect(x: 0.0, y: 0.0, width: 16.0, height: 16.0) - var cursor: Int = 0 + var cursor = 0 if let state = state as? InputState.ChoosingCandidate { cursor = Int(state.cursorIndex) - if cursor == state.composingBuffer.count && cursor != 0 { + if cursor == state.composingBuffer.count, cursor != 0 { cursor -= 1 } } - while lineHeightRect.origin.x == 0 && lineHeightRect.origin.y == 0 && cursor >= 0 { + while lineHeightRect.origin.x == 0, lineHeightRect.origin.y == 0, cursor >= 0 { (client as? IMKTextInput)?.attributes( - forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect) + forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect + ) cursor -= 1 } if useVerticalMode { ctlCandidateCurrent?.set( windowTopLeftPoint: NSPoint( - x: lineHeightRect.origin.x + lineHeightRect.size.width + 4.0, y: lineHeightRect.origin.y - 4.0), - bottomOutOfScreenAdjustmentHeight: lineHeightRect.size.height + 4.0) + x: lineHeightRect.origin.x + lineHeightRect.size.width + 4.0, y: lineHeightRect.origin.y - 4.0 + ), + bottomOutOfScreenAdjustmentHeight: lineHeightRect.size.height + 4.0 + ) } else { ctlCandidateCurrent?.set( windowTopLeftPoint: NSPoint(x: lineHeightRect.origin.x, y: lineHeightRect.origin.y - 4.0), - bottomOutOfScreenAdjustmentHeight: lineHeightRect.size.height + 4.0) + bottomOutOfScreenAdjustmentHeight: lineHeightRect.size.height + 4.0 + ) } } private func show(tooltip: String, composingBuffer: String, cursorIndex: UInt, client: Any!) { var lineHeightRect = NSRect(x: 0.0, y: 0.0, width: 16.0, height: 16.0) - var cursor: Int = Int(cursorIndex) - if cursor == composingBuffer.count && cursor != 0 { + var cursor = Int(cursorIndex) + if cursor == composingBuffer.count, cursor != 0 { cursor -= 1 } - while lineHeightRect.origin.x == 0 && lineHeightRect.origin.y == 0 && cursor >= 0 { + while lineHeightRect.origin.x == 0, lineHeightRect.origin.y == 0, cursor >= 0 { (client as? IMKTextInput)?.attributes( - forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect) + forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect + ) cursor -= 1 } ctlInputMethod.tooltipController.show(tooltip: tooltip, at: lineHeightRect.origin) @@ -517,16 +530,16 @@ extension ctlInputMethod { // MARK: - extension ctlInputMethod: KeyHandlerDelegate { - func ctlCandidate(for keyHandler: KeyHandler) -> Any { + func ctlCandidate(for _: KeyHandler) -> Any { ctlCandidateCurrent ?? .vertical } func keyHandler( - _ keyHandler: KeyHandler, didSelectCandidateAt index: Int, + _: KeyHandler, didSelectCandidateAt index: Int, ctlCandidate controller: Any ) { if let controller = controller as? ctlCandidate { - self.ctlCandidate(controller, didSelectCandidateAtIndex: UInt(index)) + ctlCandidate(controller, didSelectCandidateAtIndex: UInt(index)) } } @@ -545,11 +558,13 @@ extension ctlInputMethod: KeyHandlerDelegate { if !mgrLangModel.writeUserPhrase( state.userPhrase, inputMode: keyHandler.inputMode, areWeDuplicating: state.chkIfUserPhraseExists, - areWeDeleting: ctlInputMethod.areWeDeleting) + areWeDeleting: ctlInputMethod.areWeDeleting + ) || !mgrLangModel.writeUserPhrase( state.userPhraseConverted, inputMode: refInputModeReversed, areWeDuplicating: false, - areWeDeleting: ctlInputMethod.areWeDeleting) + areWeDeleting: ctlInputMethod.areWeDeleting + ) { return false } @@ -560,7 +575,7 @@ extension ctlInputMethod: KeyHandlerDelegate { // MARK: - extension ctlInputMethod: ctlCandidateDelegate { - func candidateCountForController(_ controller: ctlCandidate) -> UInt { + func candidateCountForController(_: ctlCandidate) -> UInt { if let state = state as? InputState.ChoosingCandidate { return UInt(state.candidates.count) } else if let state = state as? InputState.AssociatedPhrases { @@ -569,7 +584,7 @@ extension ctlInputMethod: ctlCandidateDelegate { return 0 } - func ctlCandidate(_ controller: ctlCandidate, candidateAtIndex index: UInt) + func ctlCandidate(_: ctlCandidate, candidateAtIndex index: UInt) -> String { if let state = state as? InputState.ChoosingCandidate { @@ -580,19 +595,20 @@ extension ctlInputMethod: ctlCandidateDelegate { return "" } - func ctlCandidate(_ controller: ctlCandidate, didSelectCandidateAtIndex index: UInt) { + func ctlCandidate(_: ctlCandidate, didSelectCandidateAtIndex index: UInt) { let client = currentClient if let state = state as? InputState.SymbolTable, let node = state.node.children?[Int(index)] { if let children = node.children, !children.isEmpty { - self.handle( + handle( state: .SymbolTable(node: node, useVerticalMode: state.useVerticalMode), - client: currentClient) + client: currentClient + ) } else { - self.handle(state: .Committing(poppedText: node.title), client: client) - self.handle(state: .Empty(), client: client) + handle(state: .Committing(poppedText: node.title), client: client) + handle(state: .Empty(), client: client) } return } @@ -609,10 +625,11 @@ extension ctlInputMethod: ctlCandidateDelegate { handle(state: .Committing(poppedText: composingBuffer), client: client) if mgrPrefs.associatedPhrasesEnabled, let associatePhrases = keyHandler.buildAssociatePhraseState( - withKey: composingBuffer, useVerticalMode: state.useVerticalMode) + withKey: composingBuffer, useVerticalMode: state.useVerticalMode + ) as? InputState.AssociatedPhrases { - self.handle(state: associatePhrases, client: client) + handle(state: associatePhrases, client: client) } else { handle(state: .Empty(), client: client) } @@ -627,10 +644,11 @@ extension ctlInputMethod: ctlCandidateDelegate { handle(state: .Committing(poppedText: selectedValue), client: currentClient) if mgrPrefs.associatedPhrasesEnabled, let associatePhrases = keyHandler.buildAssociatePhraseState( - withKey: selectedValue, useVerticalMode: state.useVerticalMode) + withKey: selectedValue, useVerticalMode: state.useVerticalMode + ) as? InputState.AssociatedPhrases { - self.handle(state: associatePhrases, client: client) + handle(state: associatePhrases, client: client) } else { handle(state: .Empty(), client: client) } diff --git a/Source/Modules/IMEModules/ctlInputMethod_Menu.swift b/Source/Modules/IMEModules/ctlInputMethod_Menu.swift index d2cd711d..2e29b813 100644 --- a/Source/Modules/IMEModules/ctlInputMethod_Menu.swift +++ b/Source/Modules/IMEModules/ctlInputMethod_Menu.swift @@ -33,6 +33,7 @@ extension Bool { } // MARK: - IME Menu Manager + // 因為選單部分的內容又臭又長,所以就單獨拉到一個檔案內管理了。 extension ctlInputMethod { @@ -43,51 +44,59 @@ extension ctlInputMethod { let useSCPCTypingModeItem = menu.addItem( withTitle: NSLocalizedString("Per-Char Select Mode", comment: ""), - action: #selector(toggleSCPCTypingMode(_:)), keyEquivalent: "P") + action: #selector(toggleSCPCTypingMode(_:)), keyEquivalent: "P" + ) useSCPCTypingModeItem.keyEquivalentModifierMask = [.command, .control] useSCPCTypingModeItem.state = mgrPrefs.useSCPCTypingMode.state let userAssociatedPhrasesItem = menu.addItem( withTitle: NSLocalizedString("Per-Char Associated Phrases", comment: ""), - action: #selector(toggleAssociatedPhrasesEnabled(_:)), keyEquivalent: "O") + action: #selector(toggleAssociatedPhrasesEnabled(_:)), keyEquivalent: "O" + ) userAssociatedPhrasesItem.keyEquivalentModifierMask = [.command, .control] userAssociatedPhrasesItem.state = mgrPrefs.associatedPhrasesEnabled.state let useCNS11643SupportItem = menu.addItem( withTitle: NSLocalizedString("CNS11643 Mode", comment: ""), - action: #selector(toggleCNS11643Enabled(_:)), keyEquivalent: "L") + action: #selector(toggleCNS11643Enabled(_:)), keyEquivalent: "L" + ) useCNS11643SupportItem.keyEquivalentModifierMask = [.command, .control] useCNS11643SupportItem.state = mgrPrefs.cns11643Enabled.state if IME.getInputMode() == InputMode.imeModeCHT { let chineseConversionItem = menu.addItem( withTitle: NSLocalizedString("Force KangXi Writing", comment: ""), - action: #selector(toggleChineseConverter(_:)), keyEquivalent: "K") + action: #selector(toggleChineseConverter(_:)), keyEquivalent: "K" + ) chineseConversionItem.keyEquivalentModifierMask = [.command, .control] chineseConversionItem.state = mgrPrefs.chineseConversionEnabled.state let shiftJISConversionItem = menu.addItem( withTitle: NSLocalizedString("JIS Shinjitai Output", comment: ""), - action: #selector(toggleShiftJISShinjitaiOutput(_:)), keyEquivalent: "J") + action: #selector(toggleShiftJISShinjitaiOutput(_:)), keyEquivalent: "J" + ) shiftJISConversionItem.keyEquivalentModifierMask = [.command, .control] shiftJISConversionItem.state = mgrPrefs.shiftJISShinjitaiOutputEnabled.state } let halfWidthPunctuationItem = menu.addItem( withTitle: NSLocalizedString("Half-Width Punctuation Mode", comment: ""), - action: #selector(toggleHalfWidthPunctuation(_:)), keyEquivalent: "H") + action: #selector(toggleHalfWidthPunctuation(_:)), keyEquivalent: "H" + ) halfWidthPunctuationItem.keyEquivalentModifierMask = [.command, .control] halfWidthPunctuationItem.state = mgrPrefs.halfWidthPunctuationEnabled.state if optionKeyPressed { let phaseReplacementItem = menu.addItem( withTitle: NSLocalizedString("Use Phrase Replacement", comment: ""), - action: #selector(togglePhraseReplacement(_:)), keyEquivalent: "") + action: #selector(togglePhraseReplacement(_:)), keyEquivalent: "" + ) phaseReplacementItem.state = mgrPrefs.phraseReplacementEnabled.state let toggleSymbolInputItem = menu.addItem( withTitle: NSLocalizedString("Symbol & Emoji Input", comment: ""), - action: #selector(toggleSymbolEnabled(_:)), keyEquivalent: "") + action: #selector(toggleSymbolEnabled(_:)), keyEquivalent: "" + ) toggleSymbolInputItem.state = mgrPrefs.symbolInputEnabled.state } @@ -95,30 +104,37 @@ extension ctlInputMethod { menu.addItem( withTitle: NSLocalizedString("Open User Data Folder", comment: ""), - action: #selector(openUserDataFolder(_:)), keyEquivalent: "") + action: #selector(openUserDataFolder(_:)), keyEquivalent: "" + ) menu.addItem( withTitle: NSLocalizedString("Edit User Phrases…", comment: ""), - action: #selector(openUserPhrases(_:)), keyEquivalent: "") + action: #selector(openUserPhrases(_:)), keyEquivalent: "" + ) menu.addItem( withTitle: NSLocalizedString("Edit Excluded Phrases…", comment: ""), - action: #selector(openExcludedPhrases(_:)), keyEquivalent: "") + action: #selector(openExcludedPhrases(_:)), keyEquivalent: "" + ) if optionKeyPressed { menu.addItem( withTitle: NSLocalizedString("Edit Phrase Replacement Table…", comment: ""), - action: #selector(openPhraseReplacement(_:)), keyEquivalent: "") + action: #selector(openPhraseReplacement(_:)), keyEquivalent: "" + ) menu.addItem( withTitle: NSLocalizedString("Edit Associated Phrases…", comment: ""), - action: #selector(openAssociatedPhrases(_:)), keyEquivalent: "") + action: #selector(openAssociatedPhrases(_:)), keyEquivalent: "" + ) menu.addItem( withTitle: NSLocalizedString("Edit User Symbol & Emoji Data…", comment: ""), - action: #selector(openUserSymbols(_:)), keyEquivalent: "") + action: #selector(openUserSymbols(_:)), keyEquivalent: "" + ) } if optionKeyPressed || !mgrPrefs.shouldAutoReloadUserDataFiles { menu.addItem( withTitle: NSLocalizedString("Reload User Phrases", comment: ""), - action: #selector(reloadUserPhrases(_:)), keyEquivalent: "") + action: #selector(reloadUserPhrases(_:)), keyEquivalent: "" + ) } menu.addItem(NSMenuItem.separator()) // --------------------- @@ -126,25 +142,31 @@ extension ctlInputMethod { if optionKeyPressed { menu.addItem( withTitle: NSLocalizedString("vChewing Preferences…", comment: ""), - action: #selector(showLegacyPreferences(_:)), keyEquivalent: "") + action: #selector(showLegacyPreferences(_:)), keyEquivalent: "" + ) } else { menu.addItem( withTitle: NSLocalizedString("vChewing Preferences…", comment: ""), - action: #selector(showPreferences(_:)), keyEquivalent: "") + action: #selector(showPreferences(_:)), keyEquivalent: "" + ) menu.addItem( withTitle: NSLocalizedString("Check for Updates…", comment: ""), - action: #selector(checkForUpdate(_:)), keyEquivalent: "") + action: #selector(checkForUpdate(_:)), keyEquivalent: "" + ) } menu.addItem( withTitle: NSLocalizedString("Reboot vChewing…", comment: ""), - action: #selector(selfTerminate(_:)), keyEquivalent: "") + action: #selector(selfTerminate(_:)), keyEquivalent: "" + ) menu.addItem( withTitle: NSLocalizedString("About vChewing…", comment: ""), - action: #selector(showAbout(_:)), keyEquivalent: "") + action: #selector(showAbout(_:)), keyEquivalent: "" + ) if optionKeyPressed { menu.addItem( withTitle: NSLocalizedString("Uninstall vChewing…", comment: ""), - action: #selector(selfUninstall(_:)), keyEquivalent: "") + action: #selector(selfUninstall(_:)), keyEquivalent: "" + ) } // NSMenu 會阻止任何 modified key 相關的訊號傳回輸入法,所以咱們在此重設鍵盤佈局 @@ -155,7 +177,7 @@ extension ctlInputMethod { // MARK: - IME Menu Items - @objc override func showPreferences(_ sender: Any?) { + @objc override func showPreferences(_: Any?) { if #available(macOS 11.0, *) { NSApp.setActivationPolicy(.accessory) ctlPrefUI.shared.controller.show(preferencePane: Preferences.PaneIdentifier(rawValue: "General")) @@ -165,7 +187,7 @@ extension ctlInputMethod { } } - @objc func showLegacyPreferences(_ sender: Any?) { + @objc func showLegacyPreferences(_: Any?) { showPrefWindowTraditional() } @@ -174,135 +196,144 @@ extension ctlInputMethod { NSApp.activate(ignoringOtherApps: true) } - @objc func toggleSCPCTypingMode(_ sender: Any?) { + @objc func toggleSCPCTypingMode(_: Any?) { NotifierController.notify( message: String( format: "%@%@%@", NSLocalizedString("Per-Char Select Mode", comment: ""), "\n", mgrPrefs.toggleSCPCTypingModeEnabled() ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + : NSLocalizedString("NotificationSwitchOFF", comment: "") + )) resetKeyHandler() } - @objc func toggleChineseConverter(_ sender: Any?) { + @objc func toggleChineseConverter(_: Any?) { NotifierController.notify( message: String( format: "%@%@%@", NSLocalizedString("Force KangXi Writing", comment: ""), "\n", mgrPrefs.toggleChineseConversionEnabled() ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + : NSLocalizedString("NotificationSwitchOFF", comment: "") + )) resetKeyHandler() } - @objc func toggleShiftJISShinjitaiOutput(_ sender: Any?) { + @objc func toggleShiftJISShinjitaiOutput(_: Any?) { NotifierController.notify( message: String( format: "%@%@%@", NSLocalizedString("JIS Shinjitai Output", comment: ""), "\n", mgrPrefs.toggleShiftJISShinjitaiOutputEnabled() ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + : NSLocalizedString("NotificationSwitchOFF", comment: "") + )) resetKeyHandler() } - @objc func toggleHalfWidthPunctuation(_ sender: Any?) { + @objc func toggleHalfWidthPunctuation(_: Any?) { NotifierController.notify( message: String( format: "%@%@%@", NSLocalizedString("Half-Width Punctuation Mode", comment: ""), "\n", mgrPrefs.toggleHalfWidthPunctuationEnabled() ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + : NSLocalizedString("NotificationSwitchOFF", comment: "") + )) resetKeyHandler() } - @objc func toggleCNS11643Enabled(_ sender: Any?) { + @objc func toggleCNS11643Enabled(_: Any?) { NotifierController.notify( message: String( format: "%@%@%@", NSLocalizedString("CNS11643 Mode", comment: ""), "\n", mgrPrefs.toggleCNS11643Enabled() ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + : NSLocalizedString("NotificationSwitchOFF", comment: "") + )) resetKeyHandler() } - @objc func toggleSymbolEnabled(_ sender: Any?) { + @objc func toggleSymbolEnabled(_: Any?) { NotifierController.notify( message: String( format: "%@%@%@", NSLocalizedString("Symbol & Emoji Input", comment: ""), "\n", mgrPrefs.toggleSymbolInputEnabled() ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + : NSLocalizedString("NotificationSwitchOFF", comment: "") + )) resetKeyHandler() } - @objc func toggleAssociatedPhrasesEnabled(_ sender: Any?) { + @objc func toggleAssociatedPhrasesEnabled(_: Any?) { NotifierController.notify( message: String( format: "%@%@%@", NSLocalizedString("Per-Char Associated Phrases", comment: ""), "\n", mgrPrefs.toggleAssociatedPhrasesEnabled() ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + : NSLocalizedString("NotificationSwitchOFF", comment: "") + )) resetKeyHandler() } - @objc func togglePhraseReplacement(_ sender: Any?) { + @objc func togglePhraseReplacement(_: Any?) { NotifierController.notify( message: String( format: "%@%@%@", NSLocalizedString("Use Phrase Replacement", comment: ""), "\n", mgrPrefs.togglePhraseReplacementEnabled() ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + : NSLocalizedString("NotificationSwitchOFF", comment: "") + )) resetKeyHandler() } - @objc func selfUninstall(_ sender: Any?) { + @objc func selfUninstall(_: Any?) { (NSApp.delegate as? AppDelegate)?.selfUninstall() } - @objc func selfTerminate(_ sender: Any?) { + @objc func selfTerminate(_: Any?) { NSApp.activate(ignoringOtherApps: true) NSApp.terminate(nil) } - @objc func checkForUpdate(_ sender: Any?) { + @objc func checkForUpdate(_: Any?) { (NSApp.delegate as? AppDelegate)?.checkForUpdate(forced: true) } - @objc func openUserPhrases(_ sender: Any?) { + @objc func openUserPhrases(_: Any?) { IME.openPhraseFile(userFileAt: mgrLangModel.userPhrasesDataPath(IME.getInputMode())) } - @objc func openUserDataFolder(_ sender: Any?) { + @objc func openUserDataFolder(_: Any?) { if !mgrLangModel.checkIfUserDataFolderExists() { return } NSWorkspace.shared.openFile( - mgrLangModel.dataFolderPath(isDefaultFolder: false), withApplication: "Finder") + mgrLangModel.dataFolderPath(isDefaultFolder: false), withApplication: "Finder" + ) } - @objc func openExcludedPhrases(_ sender: Any?) { + @objc func openExcludedPhrases(_: Any?) { IME.openPhraseFile(userFileAt: mgrLangModel.excludedPhrasesDataPath(IME.getInputMode())) } - @objc func openUserSymbols(_ sender: Any?) { + @objc func openUserSymbols(_: Any?) { IME.openPhraseFile(userFileAt: mgrLangModel.userSymbolDataPath(IME.getInputMode())) } - @objc func openPhraseReplacement(_ sender: Any?) { + @objc func openPhraseReplacement(_: Any?) { IME.openPhraseFile(userFileAt: mgrLangModel.phraseReplacementDataPath(IME.getInputMode())) } - @objc func openAssociatedPhrases(_ sender: Any?) { + @objc func openAssociatedPhrases(_: Any?) { IME.openPhraseFile(userFileAt: mgrLangModel.userAssociatedPhrasesDataPath(IME.getInputMode())) } - @objc func reloadUserPhrases(_ sender: Any?) { + @objc func reloadUserPhrases(_: Any?) { mgrLangModel.loadUserPhrases() mgrLangModel.loadUserPhraseReplacement() } - @objc func showAbout(_ sender: Any?) { + @objc func showAbout(_: Any?) { (NSApp.delegate as? AppDelegate)?.showAbout() NSApp.activate(ignoringOtherApps: true) } diff --git a/Source/Modules/IMEModules/mgrPrefs.swift b/Source/Modules/IMEModules/mgrPrefs.swift index 9651963a..f3c602dc 100644 --- a/Source/Modules/IMEModules/mgrPrefs.swift +++ b/Source/Modules/IMEModules/mgrPrefs.swift @@ -83,7 +83,7 @@ private let kDefaultKeys = "123456789" @objc extension UserDefaults { func setDefault(_ value: Any?, forKey defaultName: String) { if object(forKey: defaultName) == nil { - self.set(value, forKey: defaultName) + set(value, forKey: defaultName) } } } @@ -110,9 +110,7 @@ struct UserDefault { struct CandidateListTextSize { let key: String let defaultValue: CGFloat = kDefaultCandidateListTextSize - lazy var container: UserDefault = { - UserDefault(key: key, defaultValue: defaultValue) - }() + lazy var container: UserDefault = .init(key: key, defaultValue: defaultValue) var wrappedValue: CGFloat { mutating get { @@ -140,9 +138,7 @@ struct CandidateListTextSize { struct ComposingBufferSize { let key: String let defaultValue: Int = kDefaultComposingBufferSize - lazy var container: UserDefault = { - UserDefault(key: key, defaultValue: defaultValue) - }() + lazy var container: UserDefault = .init(key: key, defaultValue: defaultValue) var wrappedValue: Int { mutating get { @@ -201,6 +197,7 @@ struct ComposingBufferSize { } // MARK: - + public class mgrPrefs: NSObject { static var allKeys: [String] { [ @@ -238,33 +235,42 @@ public class mgrPrefs: NSObject { } // MARK: - 既然 Preferences Module 的預設屬性不自動寫入 plist,那這邊就先寫入了。 + @objc public static func setMissingDefaults() { UserDefaults.standard.setDefault(mgrPrefs.isDebugModeEnabled, forKey: UserDef.kIsDebugModeEnabled) UserDefaults.standard.setDefault(mgrPrefs.mostRecentInputMode, forKey: UserDef.kMostRecentInputMode) UserDefaults.standard.setDefault(mgrPrefs.checkUpdateAutomatically, forKey: UserDef.kCheckUpdateAutomatically) UserDefaults.standard.setDefault( - mgrPrefs.showPageButtonsInCandidateWindow, forKey: UserDef.kShowPageButtonsInCandidateWindow) + mgrPrefs.showPageButtonsInCandidateWindow, forKey: UserDef.kShowPageButtonsInCandidateWindow + ) UserDefaults.standard.setDefault(mgrPrefs.symbolInputEnabled, forKey: UserDef.kSymbolInputEnabled) UserDefaults.standard.setDefault(mgrPrefs.candidateListTextSize, forKey: UserDef.kCandidateListTextSize) UserDefaults.standard.setDefault(mgrPrefs.chooseCandidateUsingSpace, forKey: UserDef.kChooseCandidateUsingSpace) UserDefaults.standard.setDefault( - mgrPrefs.shouldAutoReloadUserDataFiles, forKey: UserDef.kShouldAutoReloadUserDataFiles) + mgrPrefs.shouldAutoReloadUserDataFiles, forKey: UserDef.kShouldAutoReloadUserDataFiles + ) UserDefaults.standard.setDefault( - mgrPrefs.specifyShiftTabKeyBehavior, forKey: UserDef.kSpecifyShiftTabKeyBehavior) + mgrPrefs.specifyShiftTabKeyBehavior, forKey: UserDef.kSpecifyShiftTabKeyBehavior + ) UserDefaults.standard.setDefault( - mgrPrefs.specifyShiftSpaceKeyBehavior, forKey: UserDef.kSpecifyShiftSpaceKeyBehavior) + mgrPrefs.specifyShiftSpaceKeyBehavior, forKey: UserDef.kSpecifyShiftSpaceKeyBehavior + ) UserDefaults.standard.setDefault(mgrPrefs.useSCPCTypingMode, forKey: UserDef.kUseSCPCTypingMode) UserDefaults.standard.setDefault(mgrPrefs.associatedPhrasesEnabled, forKey: UserDef.kAssociatedPhrasesEnabled) UserDefaults.standard.setDefault( - mgrPrefs.selectPhraseAfterCursorAsCandidate, forKey: UserDef.kSelectPhraseAfterCursorAsCandidate) + mgrPrefs.selectPhraseAfterCursorAsCandidate, forKey: UserDef.kSelectPhraseAfterCursorAsCandidate + ) UserDefaults.standard.setDefault( - mgrPrefs.moveCursorAfterSelectingCandidate, forKey: UserDef.kMoveCursorAfterSelectingCandidate) + mgrPrefs.moveCursorAfterSelectingCandidate, forKey: UserDef.kMoveCursorAfterSelectingCandidate + ) UserDefaults.standard.setDefault( - mgrPrefs.useHorizontalCandidateList, forKey: UserDef.kUseHorizontalCandidateList) + mgrPrefs.useHorizontalCandidateList, forKey: UserDef.kUseHorizontalCandidateList + ) UserDefaults.standard.setDefault(mgrPrefs.cns11643Enabled, forKey: UserDef.kCNS11643Enabled) UserDefaults.standard.setDefault(mgrPrefs.chineseConversionEnabled, forKey: UserDef.kChineseConversionEnabled) UserDefaults.standard.setDefault( - mgrPrefs.shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled) + mgrPrefs.shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled + ) UserDefaults.standard.setDefault(mgrPrefs.phraseReplacementEnabled, forKey: UserDef.kPhraseReplacementEnabled) UserDefaults.standard.setDefault(mgrPrefs.shouldNotFartInLieuOfBeep, forKey: UserDef.kShouldNotFartInLieuOfBeep) @@ -303,7 +309,8 @@ public class mgrPrefs: NSObject { } @UserDefault( - key: UserDef.kBasicKeyboardLayout, defaultValue: "com.apple.keylayout.ZhuyinBopomofo") + key: UserDef.kBasicKeyboardLayout, defaultValue: "com.apple.keylayout.ZhuyinBopomofo" + ) @objc static var basicKeyboardLayout: String @UserDefault(key: UserDef.kShowPageButtonsInCandidateWindow, defaultValue: true) @@ -377,10 +384,11 @@ public class mgrPrefs: NSObject { @objc @discardableResult static func toggleChineseConversionEnabled() -> Bool { chineseConversionEnabled = !chineseConversionEnabled // 康熙轉換與 JIS 轉換不能同時開啟,否則會出現某些奇奇怪怪的情況 - if chineseConversionEnabled && shiftJISShinjitaiOutputEnabled { + if chineseConversionEnabled, shiftJISShinjitaiOutputEnabled { toggleShiftJISShinjitaiOutputEnabled() UserDefaults.standard.set( - shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled) + shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled + ) } UserDefaults.standard.set(chineseConversionEnabled, forKey: UserDef.kChineseConversionEnabled) return chineseConversionEnabled @@ -392,11 +400,12 @@ public class mgrPrefs: NSObject { @objc @discardableResult static func toggleShiftJISShinjitaiOutputEnabled() -> Bool { shiftJISShinjitaiOutputEnabled = !shiftJISShinjitaiOutputEnabled // 康熙轉換與 JIS 轉換不能同時開啟,否則會出現某些奇奇怪怪的情況 - if shiftJISShinjitaiOutputEnabled && chineseConversionEnabled { + if shiftJISShinjitaiOutputEnabled, chineseConversionEnabled { toggleChineseConversionEnabled() } UserDefaults.standard.set( - shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled) + shiftJISShinjitaiOutputEnabled, forKey: UserDef.kShiftJISShinjitaiOutputEnabled + ) return shiftJISShinjitaiOutputEnabled } @@ -418,6 +427,7 @@ public class mgrPrefs: NSObject { @objc static var specifyShiftSpaceKeyBehavior: Bool // MARK: - Optional settings + @UserDefault(key: UserDef.kCandidateTextFontName, defaultValue: nil) @objc static var candidateTextFontName: String? @@ -430,6 +440,7 @@ public class mgrPrefs: NSObject { @objc static var defaultCandidateKeys: String { kDefaultKeys } + @objc static var suggestedCandidateKeys: [String] { [kDefaultKeys, "234567890", "QWERTYUIO", "QWERTASDF", "ASDFGHJKL", "ASDFZXCVB"] } @@ -472,19 +483,20 @@ public class mgrPrefs: NSObject { case .invalidCharacters: return NSLocalizedString( "Candidate keys can only contain ASCII characters like alphanumericals.", - comment: "") + comment: "" + ) case .containSpace: return NSLocalizedString("Candidate keys cannot contain space.", comment: "") case .duplicatedCharacters: return NSLocalizedString("There should not be duplicated keys.", comment: "") case .tooShort: return NSLocalizedString( - "Please specify at least 4 candidate keys.", comment: "") + "Please specify at least 4 candidate keys.", comment: "" + ) case .tooLong: return NSLocalizedString("Maximum 15 candidate keys allowed.", comment: "") } } - } @UserDefault(key: UserDef.kPhraseReplacementEnabled, defaultValue: false) @@ -505,5 +517,4 @@ public class mgrPrefs: NSObject { UserDefaults.standard.set(associatedPhrasesEnabled, forKey: UserDef.kAssociatedPhrasesEnabled) return associatedPhrasesEnabled } - } diff --git a/Source/Modules/LangModelRelated/mgrLangModel.swift b/Source/Modules/LangModelRelated/mgrLangModel.swift index 140a0a5c..c82329d6 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel.swift +++ b/Source/Modules/LangModelRelated/mgrLangModel.swift @@ -25,13 +25,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa @objc extension mgrLangModel { - // MARK: - 獲取當前輸入法封包內的原廠核心語彙檔案所在路徑 + static func getBundleDataPath(_ filenameSansExt: String) -> String { Bundle.main.path(forResource: filenameSansExt, ofType: "txt")! } // MARK: - 使用者語彙檔案的具體檔案名稱路徑定義 + // Swift 的 appendingPathComponent 需要藉由 URL 完成,最後再用 .path 轉為路徑。 static func userPhrasesDataPath(_ mode: InputMode) -> String { @@ -134,12 +135,12 @@ import Cocoa // 發現目標路徑不是目錄的話: // 如果要找的目標路徑是原廠目標路徑的話,先將這個路徑的所指對象更名、再認為目錄不存在。 // 如果要找的目標路徑不是原廠目標路徑的話,則直接報錯。 - if folderExist && !isFolder.boolValue { + if folderExist, !isFolder.boolValue { do { if dataFolderPath(isDefaultFolder: false) == dataFolderPath(isDefaultFolder: true) { - let formatter = DateFormatter.init() + let formatter = DateFormatter() formatter.dateFormat = "YYYYMMDD-HHMM'Hrs'-ss's'" let dirAlternative = folderPath + formatter.string(from: Date()) try FileManager.default.moveItem(atPath: folderPath, toPath: dirAlternative) @@ -157,7 +158,8 @@ import Cocoa try FileManager.default.createDirectory( atPath: folderPath, withIntermediateDirectories: true, - attributes: nil) + attributes: nil + ) } catch { print("Failed to create folder: \(error)") return false @@ -167,6 +169,7 @@ import Cocoa } // MARK: - 用以讀取使用者語彙檔案目錄的函數,會自動對 mgrPrefs 當中的參數糾偏。 + // 當且僅當 mgrPrefs 當中的參數不合規(比如非實在路徑、或者無權限寫入)時,才會糾偏。 static func dataFolderPath(isDefaultFolder: Bool) -> String { @@ -195,6 +198,7 @@ import Cocoa } // MARK: - 寫入使用者檔案 + static func writeUserPhrase( _ userPhrase: String?, inputMode mode: InputMode, areWeDuplicating: Bool, areWeDeleting: Bool ) -> Bool { @@ -207,7 +211,7 @@ import Cocoa let path = areWeDeleting ? excludedPhrasesDataPath(mode) : userPhrasesDataPath(mode) - if areWeDuplicating && !areWeDeleting { + if areWeDuplicating, !areWeDeleting { // Do not use ASCII characters to comment here. // Otherwise, it will be scrambled by cnvHYPYtoBPMF // module shipped in the vChewing Phrase Editor. @@ -238,5 +242,4 @@ import Cocoa } return false } - } diff --git a/Source/Modules/SFX/clsSFX.swift b/Source/Modules/SFX/clsSFX.swift index faf5e5c6..e6d42546 100644 --- a/Source/Modules/SFX/clsSFX.swift +++ b/Source/Modules/SFX/clsSFX.swift @@ -28,9 +28,10 @@ import Cocoa public class clsSFX: NSObject, NSSoundDelegate { private static let shared = clsSFX() - private override init() { + override private init() { super.init() } + private var currentBeep: NSSound? private func beep() { // Stop existing beep @@ -57,9 +58,11 @@ public class clsSFX: NSObject, NSSoundDelegate { beep.play() currentBeep = beep } - @objc public func sound(_ sound: NSSound, didFinishPlaying flag: Bool) { + + @objc public func sound(_: NSSound, didFinishPlaying _: Bool) { currentBeep = nil } + @objc static func beep() { shared.beep() } diff --git a/Source/UI/CandidateUI/ctlCandidate.swift b/Source/UI/CandidateUI/ctlCandidate.swift index 3ec8337f..699c1c78 100644 --- a/Source/UI/CandidateUI/ctlCandidate.swift +++ b/Source/UI/CandidateUI/ctlCandidate.swift @@ -44,7 +44,8 @@ public protocol ctlCandidateDelegate: AnyObject { func ctlCandidate(_ controller: ctlCandidate, candidateAtIndex index: UInt) -> String func ctlCandidate( - _ controller: ctlCandidate, didSelectCandidateAtIndex index: UInt) + _ controller: ctlCandidate, didSelectCandidateAtIndex index: UInt + ) } @objc(ctlCandidate) @@ -54,7 +55,8 @@ public class ctlCandidate: NSWindowController { reloadData() } } - @objc public var selectedCandidateIndex: UInt = UInt.max + + @objc public var selectedCandidateIndex: UInt = .max @objc public var visible: Bool = false { didSet { NSObject.cancelPreviousPerformRequests(withTarget: self) @@ -65,6 +67,7 @@ public class ctlCandidate: NSWindowController { } } } + @objc public var windowTopLeftPoint: NSPoint { get { guard let frameRect = window?.frame else { @@ -83,13 +86,14 @@ public class ctlCandidate: NSWindowController { .map { CandidateKeyLabel(key: $0, displayedText: $0) } + @objc public var keyLabelFont: NSFont = NSFont.monospacedDigitSystemFont( - ofSize: 14, weight: .medium) + ofSize: 14, weight: .medium + ) @objc public var candidateFont: NSFont = NSFont.systemFont(ofSize: 18) @objc public var tooltip: String = "" - @objc public func reloadData() { - } + @objc public func reloadData() {} @objc public func showNextPage() -> Bool { false @@ -107,7 +111,7 @@ public class ctlCandidate: NSWindowController { false } - @objc public func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt { + @objc public func candidateIndexAtKeyLabelIndex(_: UInt) -> UInt { UInt.max } @@ -125,7 +129,8 @@ public class ctlCandidate: NSWindowController { public func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight height: CGFloat) { DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) { self.doSet( - windowTopLeftPoint: windowTopLeftPoint, bottomOutOfScreenAdjustmentHeight: height) + windowTopLeftPoint: windowTopLeftPoint, bottomOutOfScreenAdjustmentHeight: height + ) } } @@ -136,8 +141,8 @@ public class ctlCandidate: NSWindowController { var screenFrame = NSScreen.main?.visibleFrame ?? NSRect.zero for screen in NSScreen.screens { let frame = screen.visibleFrame - if windowTopLeftPoint.x >= frame.minX && windowTopLeftPoint.x <= frame.maxX - && windowTopLeftPoint.y >= frame.minY && windowTopLeftPoint.y <= frame.maxY + if windowTopLeftPoint.x >= frame.minX, windowTopLeftPoint.x <= frame.maxX, + windowTopLeftPoint.y >= frame.minY, windowTopLeftPoint.y <= frame.maxY { screenFrame = frame break @@ -172,5 +177,4 @@ public class ctlCandidate: NSWindowController { window?.setFrameTopLeftPoint(adjustedPoint) } - } diff --git a/Source/UI/CandidateUI/ctlCandidateHorizontal.swift b/Source/UI/CandidateUI/ctlCandidateHorizontal.swift index 687b012b..88ef3fde 100644 --- a/Source/UI/CandidateUI/ctlCandidateHorizontal.swift +++ b/Source/UI/CandidateUI/ctlCandidateHorizontal.swift @@ -42,7 +42,7 @@ private class HorizontalCandidateView: NSView { private var candidateAttrDict: [NSAttributedString.Key: AnyObject] = [:] private var candidateWithLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:] private var elementWidths: [CGFloat] = [] - private var trackingHighlightedIndex: UInt = UInt.max + private var trackingHighlightedIndex: UInt = .max override var isFlipped: Bool { true @@ -71,7 +71,8 @@ private class HorizontalCandidateView: NSView { for index in 0..= accuWidth && location.x <= accuWidth + currentWidth { + if location.x >= accuWidth, location.x <= accuWidth + currentWidth { return UInt(index) } accuWidth += currentWidth + 1.0 } return nil - } override func mouseUp(with event: NSEvent) { @@ -246,7 +254,8 @@ public class ctlCandidateHorizontal: ctlCandidate { var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0) let styleMask: NSWindow.StyleMask = [.nonactivatingPanel] let panel = NSPanel( - contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false) + contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false + ) panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1) panel.hasShadow = true panel.isOpaque = false @@ -279,7 +288,8 @@ public class ctlCandidateHorizontal: ctlCandidate { nextPageButton.bezelStyle = .disclosure nextPageButton.userInterfaceLayoutDirection = .leftToRight nextPageButton.attributedTitle = NSMutableAttributedString( - string: " ", attributes: buttonAttribute) // Next Page Arrow + string: " ", attributes: buttonAttribute + ) // Next Page Arrow prevPageButton = NSButton(frame: contentRect) NSColor.controlBackgroundColor.setFill() NSBezierPath.fill(prevPageButton.bounds) @@ -291,7 +301,8 @@ public class ctlCandidateHorizontal: ctlCandidate { prevPageButton.bezelStyle = .disclosure prevPageButton.userInterfaceLayoutDirection = .rightToLeft prevPageButton.attributedTitle = NSMutableAttributedString( - string: " ", attributes: buttonAttribute) // Previous Page Arrow + string: " ", attributes: buttonAttribute + ) // Previous Page Arrow panel.contentView?.addSubview(nextPageButton) panel.contentView?.addSubview(prevPageButton) @@ -307,17 +318,18 @@ public class ctlCandidateHorizontal: ctlCandidate { prevPageButton.action = #selector(pageButtonAction(_:)) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - public override func reloadData() { + override public func reloadData() { candidateView.highlightedIndex = 0 currentPage = 0 layoutCandidateView() } - public override func showNextPage() -> Bool { + override public func showNextPage() -> Bool { guard delegate != nil else { return false } if pageCount == 1 { return highlightNextCandidate() } currentPage = (currentPage + 1 >= pageCount) ? 0 : currentPage + 1 @@ -326,7 +338,7 @@ public class ctlCandidateHorizontal: ctlCandidate { return true } - public override func showPreviousPage() -> Bool { + override public func showPreviousPage() -> Bool { guard delegate != nil else { return false } if pageCount == 1 { return highlightPreviousCandidate() } currentPage = (currentPage == 0) ? pageCount - 1 : currentPage - 1 @@ -335,7 +347,7 @@ public class ctlCandidateHorizontal: ctlCandidate { return true } - public override func highlightNextCandidate() -> Bool { + override public func highlightNextCandidate() -> Bool { guard let delegate = delegate else { return false } selectedCandidateIndex = (selectedCandidateIndex + 1 >= delegate.candidateCountForController(self)) @@ -343,7 +355,7 @@ public class ctlCandidateHorizontal: ctlCandidate { return true } - public override func highlightPreviousCandidate() -> Bool { + override public func highlightPreviousCandidate() -> Bool { guard let delegate = delegate else { return false } selectedCandidateIndex = (selectedCandidateIndex == 0) @@ -351,7 +363,7 @@ public class ctlCandidateHorizontal: ctlCandidate { return true } - public override func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt { + override public func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt { guard let delegate = delegate else { return UInt.max } @@ -360,7 +372,7 @@ public class ctlCandidateHorizontal: ctlCandidate { return result < delegate.candidateCountForController(self) ? result : UInt.max } - public override var selectedCandidateIndex: UInt { + override public var selectedCandidateIndex: UInt { get { currentPage * UInt(keyLabels.count) + candidateView.highlightedIndex } @@ -379,7 +391,6 @@ public class ctlCandidateHorizontal: ctlCandidate { } extension ctlCandidateHorizontal { - private var pageCount: UInt { guard let delegate = delegate else { return 0 @@ -405,13 +416,14 @@ extension ctlCandidateHorizontal { candidates.append(candidate) } candidateView.set( - keyLabels: keyLabels.map { $0.displayedText }, displayedCandidates: candidates) + keyLabels: keyLabels.map(\.displayedText), displayedCandidates: candidates + ) var newSize = candidateView.sizeForView var frameRect = candidateView.frame frameRect.size = newSize candidateView.frame = frameRect - if pageCount > 1 && mgrPrefs.showPageButtonsInCandidateWindow { + if pageCount > 1, mgrPrefs.showPageButtonsInCandidateWindow { var buttonRect = nextPageButton.frame let spacing: CGFloat = 0.0 @@ -422,7 +434,8 @@ extension ctlCandidateHorizontal { nextPageButton.frame = buttonRect buttonRect.origin = NSPoint( - x: newSize.width, y: buttonOriginY + buttonRect.size.height + spacing) + x: newSize.width, y: buttonOriginY + buttonRect.size.height + spacing + ) prevPageButton.frame = buttonRect newSize.width += 20 @@ -442,7 +455,7 @@ extension ctlCandidateHorizontal { candidateView.setNeedsDisplay(candidateView.bounds) } - @objc fileprivate func pageButtonAction(_ sender: Any) { + @objc private func pageButtonAction(_ sender: Any) { guard let sender = sender as? NSButton else { return } @@ -453,8 +466,7 @@ extension ctlCandidateHorizontal { } } - @objc fileprivate func candidateViewMouseDidClick(_ sender: Any) { + @objc private func candidateViewMouseDidClick(_: Any) { delegate?.ctlCandidate(self, didSelectCandidateAtIndex: selectedCandidateIndex) } - } diff --git a/Source/UI/CandidateUI/ctlCandidateVertical.swift b/Source/UI/CandidateUI/ctlCandidateVertical.swift index 69de51a8..b2ed0601 100644 --- a/Source/UI/CandidateUI/ctlCandidateVertical.swift +++ b/Source/UI/CandidateUI/ctlCandidateVertical.swift @@ -44,7 +44,7 @@ private class VerticalCandidateView: NSView { private var windowWidth: CGFloat = 0 private var elementWidths: [CGFloat] = [] private var elementHeights: [CGFloat] = [] - private var trackingHighlightedIndex: UInt = UInt.max + private var trackingHighlightedIndex: UInt = .max override var isFlipped: Bool { true @@ -74,7 +74,8 @@ private class VerticalCandidateView: NSView { for index in 0..= accuHeight && location.y <= accuHeight + currentHeight { + if location.y >= accuHeight, location.y <= accuHeight + currentHeight { return UInt(index) } accuHeight += currentHeight } return nil - } override func mouseUp(with event: NSEvent) { @@ -251,7 +258,8 @@ public class ctlCandidateVertical: ctlCandidate { var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0) let styleMask: NSWindow.StyleMask = [.nonactivatingPanel] let panel = NSPanel( - contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false) + contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false + ) panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1) panel.hasShadow = true panel.isOpaque = false @@ -284,7 +292,8 @@ public class ctlCandidateVertical: ctlCandidate { nextPageButton.bezelStyle = .disclosure nextPageButton.userInterfaceLayoutDirection = .leftToRight nextPageButton.attributedTitle = NSMutableAttributedString( - string: " ", attributes: buttonAttribute) // Next Page Arrow + string: " ", attributes: buttonAttribute + ) // Next Page Arrow prevPageButton = NSButton(frame: contentRect) NSColor.controlBackgroundColor.setFill() NSBezierPath.fill(prevPageButton.bounds) @@ -296,7 +305,8 @@ public class ctlCandidateVertical: ctlCandidate { prevPageButton.bezelStyle = .disclosure prevPageButton.userInterfaceLayoutDirection = .rightToLeft prevPageButton.attributedTitle = NSMutableAttributedString( - string: " ", attributes: buttonAttribute) // Previous Page Arrow + string: " ", attributes: buttonAttribute + ) // Previous Page Arrow panel.contentView?.addSubview(nextPageButton) panel.contentView?.addSubview(prevPageButton) @@ -312,17 +322,18 @@ public class ctlCandidateVertical: ctlCandidate { prevPageButton.action = #selector(pageButtonAction(_:)) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - public override func reloadData() { + override public func reloadData() { candidateView.highlightedIndex = 0 currentPage = 0 layoutCandidateView() } - public override func showNextPage() -> Bool { + override public func showNextPage() -> Bool { guard delegate != nil else { return false } if pageCount == 1 { return highlightNextCandidate() } currentPage = (currentPage + 1 >= pageCount) ? 0 : currentPage + 1 @@ -331,7 +342,7 @@ public class ctlCandidateVertical: ctlCandidate { return true } - public override func showPreviousPage() -> Bool { + override public func showPreviousPage() -> Bool { guard delegate != nil else { return false } if pageCount == 1 { return highlightPreviousCandidate() } currentPage = (currentPage == 0) ? pageCount - 1 : currentPage - 1 @@ -340,7 +351,7 @@ public class ctlCandidateVertical: ctlCandidate { return true } - public override func highlightNextCandidate() -> Bool { + override public func highlightNextCandidate() -> Bool { guard let delegate = delegate else { return false } selectedCandidateIndex = (selectedCandidateIndex + 1 >= delegate.candidateCountForController(self)) @@ -348,7 +359,7 @@ public class ctlCandidateVertical: ctlCandidate { return true } - public override func highlightPreviousCandidate() -> Bool { + override public func highlightPreviousCandidate() -> Bool { guard let delegate = delegate else { return false } selectedCandidateIndex = (selectedCandidateIndex == 0) @@ -356,7 +367,7 @@ public class ctlCandidateVertical: ctlCandidate { return true } - public override func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt { + override public func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt { guard let delegate = delegate else { return UInt.max } @@ -365,7 +376,7 @@ public class ctlCandidateVertical: ctlCandidate { return result < delegate.candidateCountForController(self) ? result : UInt.max } - public override var selectedCandidateIndex: UInt { + override public var selectedCandidateIndex: UInt { get { currentPage * UInt(keyLabels.count) + candidateView.highlightedIndex } @@ -384,7 +395,6 @@ public class ctlCandidateVertical: ctlCandidate { } extension ctlCandidateVertical { - private var pageCount: UInt { guard let delegate = delegate else { return 0 @@ -410,13 +420,14 @@ extension ctlCandidateVertical { candidates.append(candidate) } candidateView.set( - keyLabels: keyLabels.map { $0.displayedText }, displayedCandidates: candidates) + keyLabels: keyLabels.map(\.displayedText), displayedCandidates: candidates + ) var newSize = candidateView.sizeForView var frameRect = candidateView.frame frameRect.size = newSize candidateView.frame = frameRect - if pageCount > 1 && mgrPrefs.showPageButtonsInCandidateWindow { + if pageCount > 1, mgrPrefs.showPageButtonsInCandidateWindow { var buttonRect = nextPageButton.frame let spacing: CGFloat = 0.0 @@ -427,7 +438,8 @@ extension ctlCandidateVertical { nextPageButton.frame = buttonRect buttonRect.origin = NSPoint( - x: newSize.width, y: buttonOriginY + buttonRect.size.height + spacing) + x: newSize.width, y: buttonOriginY + buttonRect.size.height + spacing + ) prevPageButton.frame = buttonRect newSize.width += 20 @@ -447,7 +459,7 @@ extension ctlCandidateVertical { candidateView.setNeedsDisplay(candidateView.bounds) } - @objc fileprivate func pageButtonAction(_ sender: Any) { + @objc private func pageButtonAction(_ sender: Any) { guard let sender = sender as? NSButton else { return } @@ -458,8 +470,7 @@ extension ctlCandidateVertical { } } - @objc fileprivate func candidateViewMouseDidClick(_ sender: Any) { + @objc private func candidateViewMouseDidClick(_: Any) { delegate?.ctlCandidate(self, didSelectCandidateAtIndex: selectedCandidateIndex) } - } diff --git a/Source/UI/NotifierUI/NotifierController.swift b/Source/UI/NotifierUI/NotifierController.swift index 4ca8f3a0..6dff0825 100644 --- a/Source/UI/NotifierUI/NotifierController.swift +++ b/Source/UI/NotifierUI/NotifierController.swift @@ -33,7 +33,7 @@ private protocol NotifierWindowDelegate: AnyObject { private class NotifierWindow: NSWindow { weak var clickDelegate: NotifierWindowDelegate? - override func mouseDown(with event: NSEvent) { + override func mouseDown(with _: NSEvent) { clickDelegate?.windowDidBecomeClicked(self) } } @@ -58,7 +58,8 @@ public class NotifierController: NSWindowController, NotifierWindowDelegate { messageTextField.attributedStringValue = attrString let width = window?.frame.width ?? kWindowWidth let rect = attrString.boundingRect( - with: NSSize(width: width, height: 1600), options: .usesLineFragmentOrigin) + with: NSSize(width: width, height: 1600), options: .usesLineFragmentOrigin + ) let height = rect.height let x = messageTextField.frame.origin.x let y = ((window?.frame.height ?? kWindowHeight) - height) / 2 @@ -66,17 +67,20 @@ public class NotifierController: NSWindowController, NotifierWindowDelegate { messageTextField.frame = newFrame } } + private var shouldStay: Bool = false private var backgroundColor: NSColor = .textBackgroundColor { didSet { window?.backgroundColor = backgroundColor } } + private var foregroundColor: NSColor = .controlTextColor { didSet { messageTextField.textColor = foregroundColor } } + private var waitTimer: Timer? private var fadeTimer: Timer? @@ -114,7 +118,8 @@ public class NotifierController: NSWindowController, NotifierWindowDelegate { transparentVisualEffect.state = .active let panel = NotifierWindow( - contentRect: windowRect, styleMask: styleMask, backing: .buffered, defer: false) + contentRect: windowRect, styleMask: styleMask, backing: .buffered, defer: false + ) panel.contentView = transparentVisualEffect panel.isMovableByWindowBackground = true panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel)) @@ -144,7 +149,8 @@ public class NotifierController: NSWindowController, NotifierWindowDelegate { panel.clickDelegate = self } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -182,10 +188,11 @@ public class NotifierController: NSWindowController, NotifierWindowDelegate { waitTimer = Timer.scheduledTimer( timeInterval: shouldStay ? 5 : 1, target: self, selector: #selector(fadeOut), userInfo: nil, - repeats: false) + repeats: false + ) } - @objc private func doFadeOut(_ timer: Timer) { + @objc private func doFadeOut(_: Timer) { let opacity = window?.alphaValue ?? 0 if opacity <= 0 { close() @@ -200,10 +207,11 @@ public class NotifierController: NSWindowController, NotifierWindowDelegate { NotifierController.decreaseInstanceCount() fadeTimer = Timer.scheduledTimer( timeInterval: 0.01, target: self, selector: #selector(doFadeOut(_:)), userInfo: nil, - repeats: true) + repeats: true + ) } - public override func close() { + override public func close() { waitTimer?.invalidate() waitTimer = nil fadeTimer?.invalidate() @@ -211,7 +219,7 @@ public class NotifierController: NSWindowController, NotifierWindowDelegate { super.close() } - fileprivate func windowDidBecomeClicked(_ window: NotifierWindow) { + fileprivate func windowDidBecomeClicked(_: NotifierWindow) { fadeOut() } } diff --git a/Source/UI/PrefUI/ctlPrefUI.swift b/Source/UI/PrefUI/ctlPrefUI.swift index 048f43f4..e1d59bdc 100644 --- a/Source/UI/PrefUI/ctlPrefUI.swift +++ b/Source/UI/PrefUI/ctlPrefUI.swift @@ -32,7 +32,8 @@ class ctlPrefUI { identifier: Preferences.PaneIdentifier(rawValue: "General"), title: NSLocalizedString("General", comment: ""), toolbarIcon: NSImage( - systemSymbolName: "wrench.and.screwdriver.fill", accessibilityDescription: "General Preferences") + systemSymbolName: "wrench.and.screwdriver.fill", accessibilityDescription: "General Preferences" + ) ?? NSImage(named: NSImage.homeTemplateName)! ) { suiPrefPaneGeneral() @@ -41,7 +42,8 @@ class ctlPrefUI { identifier: Preferences.PaneIdentifier(rawValue: "Experiences"), title: NSLocalizedString("Experience", comment: ""), toolbarIcon: NSImage( - systemSymbolName: "person.fill.questionmark", accessibilityDescription: "Experiences Preferences") + systemSymbolName: "person.fill.questionmark", accessibilityDescription: "Experiences Preferences" + ) ?? NSImage(named: NSImage.listViewTemplateName)! ) { suiPrefPaneExperience() @@ -50,7 +52,8 @@ class ctlPrefUI { identifier: Preferences.PaneIdentifier(rawValue: "Dictionary"), title: NSLocalizedString("Dictionary", comment: ""), toolbarIcon: NSImage( - systemSymbolName: "character.book.closed.fill", accessibilityDescription: "Dictionary Preferences") + systemSymbolName: "character.book.closed.fill", accessibilityDescription: "Dictionary Preferences" + ) ?? NSImage(named: NSImage.bookmarksTemplateName)! ) { suiPrefPaneDictionary() @@ -59,7 +62,8 @@ class ctlPrefUI { identifier: Preferences.PaneIdentifier(rawValue: "Keyboard"), title: NSLocalizedString("Keyboard", comment: ""), toolbarIcon: NSImage( - systemSymbolName: "keyboard.macwindow", accessibilityDescription: "Keyboard Preferences") + systemSymbolName: "keyboard.macwindow", accessibilityDescription: "Keyboard Preferences" + ) ?? NSImage(named: NSImage.actionTemplateName)! ) { suiPrefPaneKeyboard() diff --git a/Source/UI/PrefUI/suiPrefPaneDictionary.swift b/Source/UI/PrefUI/suiPrefPaneDictionary.swift index fe9d0405..f42860df 100644 --- a/Source/UI/PrefUI/suiPrefPaneDictionary.swift +++ b/Source/UI/PrefUI/suiPrefPaneDictionary.swift @@ -57,7 +57,8 @@ struct suiPrefPaneDictionary: View { .help(tbxUserDataPathSpecified) Button { IME.dlgOpenPath.title = NSLocalizedString( - "Choose your desired user data folder.", comment: "") + "Choose your desired user data folder.", comment: "" + ) IME.dlgOpenPath.showsResizeIndicator = true IME.dlgOpenPath.showsHiddenFiles = true IME.dlgOpenPath.canChooseFiles = false @@ -103,27 +104,25 @@ struct suiPrefPaneDictionary: View { } label: { Text("↻") } - } Toggle( LocalizedStringKey("Automatically reload user data files if changes detected"), isOn: $selAutoReloadUserData - ).controlSize(.small).onChange(of: selAutoReloadUserData) { (value) in + ).controlSize(.small).onChange(of: selAutoReloadUserData) { value in mgrPrefs.shouldAutoReloadUserDataFiles = value } Divider() Toggle(LocalizedStringKey("Enable CNS11643 Support (2022-01-27)"), isOn: $selEnableCNS11643) - .onChange(of: selEnableCNS11643) { (value) in + .onChange(of: selEnableCNS11643) { value in mgrPrefs.cns11643Enabled = value } Toggle( LocalizedStringKey("Enable symbol input support (incl. certain emoji symbols)"), isOn: $selEnableSymbolInputSupport ) - .onChange(of: selEnableSymbolInputSupport) { (value) in + .onChange(of: selEnableSymbolInputSupport) { value in mgrPrefs.symbolInputEnabled = value } - } } } diff --git a/Source/UI/PrefUI/suiPrefPaneExperience.swift b/Source/UI/PrefUI/suiPrefPaneExperience.swift index c91b6a80..8113b549 100644 --- a/Source/UI/PrefUI/suiPrefPaneExperience.swift +++ b/Source/UI/PrefUI/suiPrefPaneExperience.swift @@ -63,7 +63,7 @@ struct suiPrefPaneExperience: View { Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Selection Keys:")) }) { ComboBox(items: mgrPrefs.suggestedCandidateKeys, text: $selSelectionKeys).frame(width: 180).onChange( of: selSelectionKeys - ) { (value) in + ) { value in let keys: String = (value.trimmingCharacters(in: .whitespacesAndNewlines) as String).charDeDuplicate do { try mgrPrefs.validate(candidateKeys: keys) @@ -92,7 +92,7 @@ struct suiPrefPaneExperience: View { Picker("", selection: $selCursorPosition) { Text(LocalizedStringKey("to the front of the phrase (like Matsushita Hanin IME)")).tag(0) Text(LocalizedStringKey("to the rear of the phrase (like MS New-Phonetic IME)")).tag(1) - }.onChange(of: selCursorPosition) { (value) in + }.onChange(of: selCursorPosition) { value in mgrPrefs.selectPhraseAfterCursorAsCandidate = (value == 1) ? true : false } .labelsHidden() @@ -102,7 +102,7 @@ struct suiPrefPaneExperience: View { Toggle( LocalizedStringKey("Push the cursor to the front of the phrase after selection"), isOn: $selPushCursorAfterSelection - ).onChange(of: selPushCursorAfterSelection) { (value) in + ).onChange(of: selPushCursorAfterSelection) { value in mgrPrefs.moveCursorAfterSelectingCandidate = value }.controlSize(.small) } @@ -110,7 +110,7 @@ struct suiPrefPaneExperience: View { Picker("", selection: $selKeyBehaviorShiftTab) { Text(LocalizedStringKey("for cycling candidates")).tag(0) Text(LocalizedStringKey("for cycling pages")).tag(1) - }.onChange(of: selKeyBehaviorShiftTab) { (value) in + }.onChange(of: selKeyBehaviorShiftTab) { value in mgrPrefs.specifyShiftTabKeyBehavior = (value == 1) ? true : false } .labelsHidden() @@ -123,7 +123,7 @@ struct suiPrefPaneExperience: View { Picker("", selection: $selKeyBehaviorShiftSpace) { Text(LocalizedStringKey("Space to +cycle candidates, Shift+Space to +cycle pages")).tag(0) Text(LocalizedStringKey("Space to +cycle pages, Shift+Space to +cycle candidates")).tag(1) - }.onChange(of: selKeyBehaviorShiftSpace) { (value) in + }.onChange(of: selKeyBehaviorShiftSpace) { value in mgrPrefs.specifyShiftSpaceKeyBehavior = (value == 1) ? true : false } .labelsHidden() @@ -135,20 +135,20 @@ struct suiPrefPaneExperience: View { Toggle( LocalizedStringKey("Enable Space key for calling candidate window"), isOn: $selKeyBehaviorSpaceForCallingCandidate - ).onChange(of: selKeyBehaviorSpaceForCallingCandidate) { (value) in + ).onChange(of: selKeyBehaviorSpaceForCallingCandidate) { value in mgrPrefs.chooseCandidateUsingSpace = value } Toggle( LocalizedStringKey("Use ESC key to clear the entire input buffer"), isOn: $selKeyBehaviorESCForClearingTheBuffer - ).onChange(of: selKeyBehaviorESCForClearingTheBuffer) { (value) in + ).onChange(of: selKeyBehaviorESCForClearingTheBuffer) { value in mgrPrefs.escToCleanInputBuffer = value } } Preferences.Section(label: { Text(LocalizedStringKey("Typing Style:")) }) { Toggle( LocalizedStringKey("Emulating select-candidate-per-character mode"), isOn: $selEnableSCPCTypingMode - ).onChange(of: selEnableSCPCTypingMode) { (value) in + ).onChange(of: selEnableSCPCTypingMode) { value in mgrPrefs.useSCPCTypingMode = value } Text(LocalizedStringKey("An accomodation for elder computer users.")) diff --git a/Source/UI/PrefUI/suiPrefPaneGeneral.swift b/Source/UI/PrefUI/suiPrefPaneGeneral.swift index bf105adc..822cf8e2 100644 --- a/Source/UI/PrefUI/suiPrefPaneGeneral.swift +++ b/Source/UI/PrefUI/suiPrefPaneGeneral.swift @@ -71,7 +71,7 @@ struct suiPrefPaneGeneral: View { Text("32").tag(32) Text("64").tag(64) Text("96").tag(96) - }.onChange(of: selCandidateUIFontSize) { (value) in + }.onChange(of: selCandidateUIFontSize) { value in mgrPrefs.candidateListTextSize = CGFloat(value) } .labelsHidden() @@ -86,7 +86,7 @@ struct suiPrefPaneGeneral: View { Text(LocalizedStringKey("Traditional Chinese")).tag(["zh-Hant"]) Text(LocalizedStringKey("Japanese")).tag(["ja"]) Text(LocalizedStringKey("English")).tag(["en"]) - }.onChange(of: selUILanguage) { (value) in + }.onChange(of: selUILanguage) { value in IME.prtDebugIntel(value[0]) if selUILanguage == mgrPrefs.appleLanguages || (selUILanguage[0] == "auto" @@ -112,7 +112,7 @@ struct suiPrefPaneGeneral: View { Picker("", selection: $selEnableHorizontalCandidateLayout) { Text(LocalizedStringKey("Vertical")).tag(false) Text(LocalizedStringKey("Horizontal")).tag(true) - }.onChange(of: selEnableHorizontalCandidateLayout) { (value) in + }.onChange(of: selEnableHorizontalCandidateLayout) { value in mgrPrefs.useHorizontalCandidateList = value } .labelsHidden() @@ -128,31 +128,31 @@ struct suiPrefPaneGeneral: View { Toggle( LocalizedStringKey("Auto-convert traditional Chinese glyphs to KangXi characters"), isOn: $selEnableKanjiConvToKangXi - ).onChange(of: selEnableKanjiConvToKangXi) { (value) in + ).onChange(of: selEnableKanjiConvToKangXi) { value in mgrPrefs.chineseConversionEnabled = value } Toggle( LocalizedStringKey("Auto-convert traditional Chinese glyphs to JIS Shinjitai characters"), isOn: $selEnableKanjiConvToJIS - ).onChange(of: selEnableKanjiConvToJIS) { (value) in + ).onChange(of: selEnableKanjiConvToJIS) { value in mgrPrefs.shiftJISShinjitaiOutputEnabled = value } Toggle( LocalizedStringKey("Stop farting (when typed phonetic combination is invalid, etc.)"), isOn: $selEnableFartSuppressor - ).onChange(of: selEnableFartSuppressor) { (value) in + ).onChange(of: selEnableFartSuppressor) { value in mgrPrefs.shouldNotFartInLieuOfBeep = value clsSFX.beep() } } Preferences.Section(label: { Text(LocalizedStringKey("Misc Settings:")).controlSize(.small) }) { Toggle(LocalizedStringKey("Check for updates automatically"), isOn: $selEnableAutoUpdateCheck) - .onChange(of: selEnableAutoUpdateCheck) { (value) in + .onChange(of: selEnableAutoUpdateCheck) { value in mgrPrefs.checkUpdateAutomatically = value } .controlSize(.small) Toggle(LocalizedStringKey("Debug Mode"), isOn: $selEnableDebugMode).controlSize(.small) - .onChange(of: selEnableDebugMode) { (value) in + .onChange(of: selEnableDebugMode) { value in mgrPrefs.isDebugModeEnabled = value } } diff --git a/Source/UI/PrefUI/suiPrefPaneKeyboard.swift b/Source/UI/PrefUI/suiPrefPaneKeyboard.swift index 896faee5..6c2ae23d 100644 --- a/Source/UI/PrefUI/suiPrefPaneKeyboard.swift +++ b/Source/UI/PrefUI/suiPrefPaneKeyboard.swift @@ -54,7 +54,7 @@ struct suiPrefPaneKeyboard: View { Text(LocalizedStringKey("MiTAC")).tag(5) Text(LocalizedStringKey("Fake Seigyou")).tag(6) Text(LocalizedStringKey("Hanyu Pinyin with Numeral Intonation")).tag(10) - }.onChange(of: selMandarinParser) { (value) in + }.onChange(of: selMandarinParser) { value in mgrPrefs.mandarinParser = value } .labelsHidden() @@ -69,7 +69,7 @@ struct suiPrefPaneKeyboard: View { Text(IME.arrEnumerateSystemKeyboardLayouts[id].strName).tag( IME.arrEnumerateSystemKeyboardLayouts[id].strValue) }.id(UUID()) - }.onChange(of: selBasicKeyboardLayout) { (value) in + }.onChange(of: selBasicKeyboardLayout) { value in mgrPrefs.basicKeyboardLayout = value } .labelsHidden() diff --git a/Source/UI/TooltipUI/TooltipController.swift b/Source/UI/TooltipUI/TooltipController.swift index b7dbdbed..70ad4db9 100644 --- a/Source/UI/TooltipUI/TooltipController.swift +++ b/Source/UI/TooltipUI/TooltipController.swift @@ -41,7 +41,8 @@ public class TooltipController: NSWindowController { let contentRect = NSRect(x: 128.0, y: 128.0, width: 300.0, height: 20.0) let styleMask: NSWindow.StyleMask = [.borderless, .nonactivatingPanel] let panel = NSPanel( - contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false) + contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false + ) panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1) panel.hasShadow = true @@ -58,7 +59,8 @@ public class TooltipController: NSWindowController { super.init(window: panel) } - public required init?(coder: NSCoder) { + @available(*, unavailable) + public required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -77,15 +79,14 @@ public class TooltipController: NSWindowController { } private func set(windowLocation windowTopLeftPoint: NSPoint) { - var adjustedPoint = windowTopLeftPoint adjustedPoint.y -= 5 var screenFrame = NSScreen.main?.visibleFrame ?? NSRect.zero for screen in NSScreen.screens { let frame = screen.visibleFrame - if windowTopLeftPoint.x >= frame.minX && windowTopLeftPoint.x <= frame.maxX - && windowTopLeftPoint.y >= frame.minY && windowTopLeftPoint.y <= frame.maxY + if windowTopLeftPoint.x >= frame.minX, windowTopLeftPoint.x <= frame.maxX, + windowTopLeftPoint.y >= frame.minY, windowTopLeftPoint.y <= frame.maxY { screenFrame = frame break @@ -115,16 +116,15 @@ public class TooltipController: NSWindowController { } window?.setFrameTopLeftPoint(adjustedPoint) - } private func adjustSize() { let attrString = messageTextField.attributedStringValue var rect = attrString.boundingRect( - with: NSSize(width: 1600.0, height: 1600.0), options: .usesLineFragmentOrigin) + with: NSSize(width: 1600.0, height: 1600.0), options: .usesLineFragmentOrigin + ) rect.size.width += 10 messageTextField.frame = rect window?.setFrame(rect, display: true) } - } diff --git a/Source/WindowControllers/ctlAboutWindow.swift b/Source/WindowControllers/ctlAboutWindow.swift index e38945b5..54ca1d16 100644 --- a/Source/WindowControllers/ctlAboutWindow.swift +++ b/Source/WindowControllers/ctlAboutWindow.swift @@ -27,8 +27,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa @objc(AboutWindow) class ctlAboutWindow: NSWindowController { - @IBOutlet weak var appVersionLabel: NSTextField! - @IBOutlet weak var appCopyrightLabel: NSTextField! + @IBOutlet var appVersionLabel: NSTextField! + @IBOutlet var appCopyrightLabel: NSTextField! @IBOutlet var appEULAContent: NSTextView! override func windowDidLoad() { @@ -53,10 +53,11 @@ import Cocoa appEULAContent.string = eulaContent } appVersionLabel.stringValue = String( - format: "%@ Build %@", versionString, installingVersion) + format: "%@ Build %@", versionString, installingVersion + ) } - @IBAction func btnWiki(_ sender: NSButton) { + @IBAction func btnWiki(_: NSButton) { if let url = URL(string: "https://gitee.com/vchewing/vChewing-macOS/wikis") { NSWorkspace.shared.open(url) } diff --git a/Source/WindowControllers/ctlNonModalAlertWindow.swift b/Source/WindowControllers/ctlNonModalAlertWindow.swift index ec38f9a1..7e654da7 100644 --- a/Source/WindowControllers/ctlNonModalAlertWindow.swift +++ b/Source/WindowControllers/ctlNonModalAlertWindow.swift @@ -35,10 +35,10 @@ class ctlNonModalAlertWindow: NSWindowController { @objc(sharedInstance) static let shared = ctlNonModalAlertWindow(windowNibName: "frmNonModalAlertWindow") - @IBOutlet weak var titleTextField: NSTextField! - @IBOutlet weak var contentTextField: NSTextField! - @IBOutlet weak var confirmButton: NSButton! - @IBOutlet weak var cancelButton: NSButton! + @IBOutlet var titleTextField: NSTextField! + @IBOutlet var contentTextField: NSTextField! + @IBOutlet var confirmButton: NSButton! + @IBOutlet var cancelButton: NSButton! weak var delegate: ctlNonModalAlertWindowDelegate? @objc func show( @@ -96,7 +96,8 @@ class ctlNonModalAlertWindow: NSWindowController { infiniteHeightFrame.size.height = 10240 newFrame = (content as NSString).boundingRect( with: infiniteHeightFrame.size, options: [.usesLineFragmentOrigin], - attributes: [.font: contentTextField.font!]) + attributes: [.font: contentTextField.font!] + ) newFrame.size.width = max(newFrame.size.width, oldFrame.size.width) newFrame.size.height += 4.0 newFrame.origin = oldFrame.origin @@ -112,7 +113,7 @@ class ctlNonModalAlertWindow: NSWindowController { NSApp.activate(ignoringOtherApps: true) } - @IBAction func confirmButtonAction(_ sender: Any) { + @IBAction func confirmButtonAction(_: Any) { delegate?.ctlNonModalAlertWindowDidConfirm(self) window?.orderOut(self) } @@ -121,10 +122,9 @@ class ctlNonModalAlertWindow: NSWindowController { cancel(sender) } - func cancel(_ sender: Any) { + func cancel(_: Any) { delegate?.ctlNonModalAlertWindowDidCancel(self) delegate = nil window?.orderOut(self) } - } diff --git a/Source/WindowControllers/ctlPrefWindow.swift b/Source/WindowControllers/ctlPrefWindow.swift index 3152bbfa..b0e68b29 100644 --- a/Source/WindowControllers/ctlPrefWindow.swift +++ b/Source/WindowControllers/ctlPrefWindow.swift @@ -31,13 +31,13 @@ import Cocoa // in Objective-C in order to let IMK to see the same class name as // the "InputMethodServerPreferencesWindowControllerClass" in Info.plist. @objc(ctlPrefWindow) class ctlPrefWindow: NSWindowController { - @IBOutlet weak var fontSizePopUpButton: NSPopUpButton! - @IBOutlet weak var uiLanguageButton: NSPopUpButton! - @IBOutlet weak var basicKeyboardLayoutButton: NSPopUpButton! - @IBOutlet weak var selectionKeyComboBox: NSComboBox! - @IBOutlet weak var chkTrad2KangXi: NSButton! - @IBOutlet weak var chkTrad2JISShinjitai: NSButton! - @IBOutlet weak var lblCurrentlySpecifiedUserDataFolder: NSTextFieldCell! + @IBOutlet var fontSizePopUpButton: NSPopUpButton! + @IBOutlet var uiLanguageButton: NSPopUpButton! + @IBOutlet var basicKeyboardLayoutButton: NSPopUpButton! + @IBOutlet var selectionKeyComboBox: NSComboBox! + @IBOutlet var chkTrad2KangXi: NSButton! + @IBOutlet var chkTrad2JISShinjitai: NSButton! + @IBOutlet var lblCurrentlySpecifiedUserDataFolder: NSTextFieldCell! var currentLanguageSelectItem: NSMenuItem? @@ -55,7 +55,7 @@ import Cocoa let appleLanguages = mgrPrefs.appleLanguages for language in languages { let menuItem = NSMenuItem() - menuItem.title = NSLocalizedString(language, comment: "") + menuItem.title = NSLocalizedString(language, comment: language) menuItem.representedObject = language if language == "auto" { @@ -105,8 +105,8 @@ import Cocoa } if let asciiCapablePtr = TISGetInputSourceProperty( - source, kTISPropertyInputSourceIsASCIICapable) - { + source, kTISPropertyInputSourceIsASCIICapable + ) { let asciiCapable = Unmanaged.fromOpaque(asciiCapablePtr) .takeUnretainedValue() if asciiCapable != kCFBooleanTrue { @@ -175,33 +175,33 @@ import Cocoa // 這裡有必要加上這段處理,用來確保藉由偏好設定介面動過的 CNS 開關能夠立刻生效。 // 所有涉及到語言模型開關的內容均需要這樣處理。 - @IBAction func toggleCNSSupport(_ sender: Any) { + @IBAction func toggleCNSSupport(_: Any) { mgrLangModel.setCNSEnabled(mgrPrefs.cns11643Enabled) } - @IBAction func toggleSymbolInputEnabled(_ sender: Any) { + @IBAction func toggleSymbolInputEnabled(_: Any) { mgrLangModel.setSymbolEnabled(mgrPrefs.symbolInputEnabled) } - @IBAction func toggleTrad2KangXiAction(_ sender: Any) { - if chkTrad2KangXi.state == .on && chkTrad2JISShinjitai.state == .on { + @IBAction func toggleTrad2KangXiAction(_: Any) { + if chkTrad2KangXi.state == .on, chkTrad2JISShinjitai.state == .on { mgrPrefs.toggleShiftJISShinjitaiOutputEnabled() } } - @IBAction func toggleTrad2JISShinjitaiAction(_ sender: Any) { - if chkTrad2KangXi.state == .on && chkTrad2JISShinjitai.state == .on { + @IBAction func toggleTrad2JISShinjitaiAction(_: Any) { + if chkTrad2KangXi.state == .on, chkTrad2JISShinjitai.state == .on { mgrPrefs.toggleChineseConversionEnabled() } } - @IBAction func updateBasicKeyboardLayoutAction(_ sender: Any) { + @IBAction func updateBasicKeyboardLayoutAction(_: Any) { if let sourceID = basicKeyboardLayoutButton.selectedItem?.representedObject as? String { mgrPrefs.basicKeyboardLayout = sourceID } } - @IBAction func updateUiLanguageAction(_ sender: Any) { + @IBAction func updateUiLanguageAction(_: Any) { if let selectItem = uiLanguageButton.selectedItem { if currentLanguageSelectItem == selectItem { return @@ -219,7 +219,7 @@ import Cocoa } } - @IBAction func clickedWhetherIMEShouldNotFartToggleAction(_ sender: Any) { + @IBAction func clickedWhetherIMEShouldNotFartToggleAction(_: Any) { clsSFX.beep() } @@ -249,13 +249,14 @@ import Cocoa } } - @IBAction func resetSpecifiedUserDataFolder(_ sender: Any) { + @IBAction func resetSpecifiedUserDataFolder(_: Any) { mgrPrefs.resetSpecifiedUserDataFolder() } - @IBAction func chooseUserDataFolderToSpecify(_ sender: Any) { + @IBAction func chooseUserDataFolderToSpecify(_: Any) { IME.dlgOpenPath.title = NSLocalizedString( - "Choose your desired user data folder.", comment: "") + "Choose your desired user data folder.", comment: "" + ) IME.dlgOpenPath.showsResizeIndicator = true IME.dlgOpenPath.showsHiddenFiles = true IME.dlgOpenPath.canChooseFiles = false @@ -292,5 +293,4 @@ import Cocoa } } // End If self.window != nil } // End IBAction - } diff --git a/UserPhraseEditor/AppDelegate.swift b/UserPhraseEditor/AppDelegate.swift index 32b4f840..5662a1e9 100644 --- a/UserPhraseEditor/AppDelegate.swift +++ b/UserPhraseEditor/AppDelegate.swift @@ -26,20 +26,20 @@ import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - private var ctlAboutWindowInstance: ctlAboutWindow? // New About Window - func applicationDidFinishLaunching(_ aNotification: Notification) { + func applicationDidFinishLaunching(_: Notification) { // Insert code here to initialize your application } - func applicationWillTerminate(_ aNotification: Notification) { + func applicationWillTerminate(_: Notification) { // Insert code here to tear down your application } - func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { + func applicationShouldTerminate(_: NSApplication) -> NSApplication.TerminateReply { .terminateNow } + // New About Window @objc func showAbout() { if ctlAboutWindowInstance == nil { @@ -49,8 +49,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { ctlAboutWindowInstance?.window?.orderFrontRegardless() // 逼著關於視窗往最前方顯示 ctlAboutWindowInstance?.window?.level = .statusBar } + // Call the New About Window - @IBAction func about(_ sender: Any) { + @IBAction func about(_: Any) { (NSApp.delegate as? AppDelegate)?.showAbout() NSApplication.shared.activate(ignoringOtherApps: true) } diff --git a/UserPhraseEditor/Content.swift b/UserPhraseEditor/Content.swift index d32656fd..2988eebb 100644 --- a/UserPhraseEditor/Content.swift +++ b/UserPhraseEditor/Content.swift @@ -31,11 +31,9 @@ class Content: NSObject { public init(contentString: String) { self.contentString = contentString } - } extension Content { - func read(from data: Data) { contentString = String(bytes: data, encoding: .utf8)! } @@ -43,5 +41,4 @@ extension Content { func data() -> Data? { contentString.data(using: .utf8) } - } diff --git a/UserPhraseEditor/Document.swift b/UserPhraseEditor/Document.swift index e455f186..ce81cb88 100644 --- a/UserPhraseEditor/Document.swift +++ b/UserPhraseEditor/Document.swift @@ -25,7 +25,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa class Document: NSDocument { - @objc var content = Content(contentString: "") var contentViewController: ViewController! @@ -43,7 +42,7 @@ class Document: NSDocument { // This enables asynchronous-writing. override func canAsynchronouslyWrite( - to url: URL, ofType typeName: String, for saveOperation: NSDocument.SaveOperationType + to _: URL, ofType _: String, for _: NSDocument.SaveOperationType ) -> Bool { true } @@ -77,7 +76,7 @@ class Document: NSDocument { // MARK: - Reading and Writing /// - Tag: readExample - override func read(from data: Data, ofType typeName: String) throws { + override func read(from data: Data, ofType _: String) throws { var strToDealWith = String(decoding: data, as: UTF8.self) strToDealWith.formatConsolidate(cnvHYPYtoBPMF: false) let processedIncomingData = Data(strToDealWith.utf8) @@ -85,7 +84,7 @@ class Document: NSDocument { } /// - Tag: writeExample - override func data(ofType typeName: String) throws -> Data { + override func data(ofType _: String) throws -> Data { var strToDealWith = content.contentString strToDealWith.formatConsolidate(cnvHYPYtoBPMF: true) let outputData = Data(strToDealWith.utf8) @@ -108,24 +107,26 @@ class Document: NSDocument { printInfo.dictionary().setObject( NSNumber(value: true), - forKey: NSPrintInfo.AttributeKey.headerAndFooter as NSCopying) + forKey: NSPrintInfo.AttributeKey.headerAndFooter as NSCopying + ) return thePrintInfo } @objc func printOperationDidRun( - _ printOperation: NSPrintOperation, success: Bool, contextInfo: UnsafeMutableRawPointer? + _: NSPrintOperation, success _: Bool, contextInfo _: UnsafeMutableRawPointer? ) { // Printing finished... } - @IBAction override func printDocument(_ sender: Any?) { + @IBAction override func printDocument(_: Any?) { // Print the NSTextView. // Create a copy to manipulate for printing. let pageSize = NSSize( - width: (printInfo.paperSize.width), height: (printInfo.paperSize.height)) + width: printInfo.paperSize.width, height: printInfo.paperSize.height + ) let textView = NSTextView( frame: NSRect(x: 0.0, y: 0.0, width: pageSize.width, height: pageSize.height)) @@ -139,7 +140,7 @@ class Document: NSDocument { printOperation.runModal( for: windowControllers[0].window!, delegate: self, - didRun: #selector(printOperationDidRun(_:success:contextInfo:)), contextInfo: nil) + didRun: #selector(printOperationDidRun(_:success:contextInfo:)), contextInfo: nil + ) } - } diff --git a/UserPhraseEditor/StringExtension.swift b/UserPhraseEditor/StringExtension.swift index e6a226c3..ca81a44b 100644 --- a/UserPhraseEditor/StringExtension.swift +++ b/UserPhraseEditor/StringExtension.swift @@ -29,15 +29,19 @@ extension String { // Ref: https://stackoverflow.com/a/40993403/4162914 && https://stackoverflow.com/a/71291137/4162914 do { let regex = try NSRegularExpression( - pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines]) + pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines] + ) let range = NSRange(startIndex..., in: self) self = regex.stringByReplacingMatches( - in: self, options: [], range: range, withTemplate: replaceWith) + in: self, options: [], range: range, withTemplate: replaceWith + ) } catch { return } } + mutating func selfReplace(_ strOf: String, _ strWith: String = "") { - self = self.replacingOccurrences(of: strOf, with: strWith) + self = replacingOccurrences(of: strOf, with: strWith) } + mutating func formatConsolidate(cnvHYPYtoBPMF: Bool) { // Step 1: Consolidating formats per line. var strProcessed = self diff --git a/UserPhraseEditor/ViewController.swift b/UserPhraseEditor/ViewController.swift index 84c8e345..40b68b02 100644 --- a/UserPhraseEditor/ViewController.swift +++ b/UserPhraseEditor/ViewController.swift @@ -25,7 +25,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa class ViewController: NSViewController, NSTextViewDelegate { - /// - Tag: setRepresentedObjectExample override var representedObject: Any? { didSet { @@ -54,12 +53,11 @@ class ViewController: NSViewController, NSTextViewDelegate { // MARK: - NSTextViewDelegate - func textDidBeginEditing(_ notification: Notification) { + func textDidBeginEditing(_: Notification) { document?.objectDidBeginEditing(self) } - func textDidEndEditing(_ notification: Notification) { + func textDidEndEditing(_: Notification) { document?.objectDidEndEditing(self) } - } diff --git a/UserPhraseEditor/WindowController.swift b/UserPhraseEditor/WindowController.swift index 12a8b6cb..7af24322 100644 --- a/UserPhraseEditor/WindowController.swift +++ b/UserPhraseEditor/WindowController.swift @@ -25,7 +25,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa class WindowController: NSWindowController, NSWindowDelegate { - override func windowDidLoad() { super.windowDidLoad() } @@ -37,5 +36,4 @@ class WindowController: NSWindowController, NSWindowDelegate { */ shouldCascadeWindows = true } - } diff --git a/UserPhraseEditor/ctlAboutWindow.swift b/UserPhraseEditor/ctlAboutWindow.swift index e38945b5..54ca1d16 100644 --- a/UserPhraseEditor/ctlAboutWindow.swift +++ b/UserPhraseEditor/ctlAboutWindow.swift @@ -27,8 +27,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa @objc(AboutWindow) class ctlAboutWindow: NSWindowController { - @IBOutlet weak var appVersionLabel: NSTextField! - @IBOutlet weak var appCopyrightLabel: NSTextField! + @IBOutlet var appVersionLabel: NSTextField! + @IBOutlet var appCopyrightLabel: NSTextField! @IBOutlet var appEULAContent: NSTextView! override func windowDidLoad() { @@ -53,10 +53,11 @@ import Cocoa appEULAContent.string = eulaContent } appVersionLabel.stringValue = String( - format: "%@ Build %@", versionString, installingVersion) + format: "%@ Build %@", versionString, installingVersion + ) } - @IBAction func btnWiki(_ sender: NSButton) { + @IBAction func btnWiki(_: NSButton) { if let url = URL(string: "https://gitee.com/vchewing/vChewing-macOS/wikis") { NSWorkspace.shared.open(url) }