Proj // Swift-format tweaks.

This commit is contained in:
ShikiSuen 2022-04-18 09:50:42 +08:00
parent 6d7f260991
commit c8f83a28aa
59 changed files with 837 additions and 593 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,7 +9,6 @@ import Foundation
import copencc
public enum ConversionError: Error {
case fileNotFound
case invalidFormat

View File

@ -9,9 +9,7 @@ import Foundation
import copencc
extension ChineseConverter {
struct DictionaryLoader {
private static let subdirectory = "Dictionary"
private static let dictCache = WeakValueCache<String, ConversionDictionary>()
@ -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)

View File

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

View File

@ -8,7 +8,6 @@
import Foundation
class WeakBox<Value: AnyObject> {
private(set) weak var value: Value?
init(_ value: Value) {
@ -17,7 +16,6 @@ class WeakBox<Value: AnyObject> {
}
class WeakValueCache<Key: Hashable, Value: AnyObject> {
private var storage: [Key: WeakBox<Value>] = [:]
private var lock = NSLock()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,6 +6,7 @@
import SwiftUI
// MARK: - NSComboBox
// Ref: https://stackoverflow.com/a/71058587/4162914
@available(macOS 11.0, *)
struct ComboBox: NSViewRepresentable {

View File

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

View File

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

View File

@ -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 {
"<InputState.EmptyIgnoringPreviousState>"
}
@ -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..<exactEnd]
let joined = selectedReadings.joined(separator: "-")
let exist = mgrLangModel.checkIfUserPhraseExist(
userPhrase: text, mode: ctlInputMethod.currentKeyHandler.inputMode, key: joined)
userPhrase: text, mode: ctlInputMethod.currentKeyHandler.inputMode, key: joined
)
if exist {
deleteTargetExists = exist
TooltipController.backgroundColor = NSColor(
red: 0.00, green: 0.18, blue: 0.13, alpha: 1.00)
red: 0.00, green: 0.18, blue: 0.13, alpha: 1.00
)
TooltipController.textColor = NSColor(
red: 0.00, green: 1.00, blue: 0.74, alpha: 1.00)
red: 0.00, green: 1.00, blue: 0.74, alpha: 1.00
)
return String(
format: NSLocalizedString(
"\"%@\" already exists: ↩ to boost, ⇧⌘↩ to exclude.", comment: ""), text
"\"%@\" already exists: ↩ to boost, ⇧⌘↩ to exclude.", comment: ""
), text
)
}
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.white
return String(
format: NSLocalizedString("\"%@\" selected. ↩ to add user phrase.", comment: ""),
text)
text
)
}
@objc var tooltipForInputting: String = ""
@ -256,12 +271,14 @@ class InputState: NSObject {
[
.underlineStyle: NSUnderlineStyle.single.rawValue,
.markedClauseSegment: 0,
], range: NSRange(location: 0, length: markedRange.location))
], range: NSRange(location: 0, length: markedRange.location)
)
attributedSting.setAttributes(
[
.underlineStyle: NSUnderlineStyle.thick.rawValue,
.markedClauseSegment: 1,
], range: markedRange)
], range: markedRange
)
attributedSting.setAttributes(
[
.underlineStyle: NSUnderlineStyle.single.rawValue,
@ -269,7 +286,9 @@ class InputState: NSObject {
],
range: NSRange(
location: end,
length: (composingBuffer as NSString).length - end))
length: (composingBuffer as NSString).length - end
)
)
return attributedSting
}
@ -297,7 +316,7 @@ class InputState: NSObject {
if markedRange.length > 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..<exactEnd]
let joined = selectedReadings.joined(separator: "-")
return mgrLangModel.checkIfUserPhraseExist(
userPhrase: text, mode: ctlInputMethod.currentKeyHandler.inputMode, key: joined)
userPhrase: text, mode: ctlInputMethod.currentKeyHandler.inputMode, key: joined
)
== true
}
@ -363,7 +383,8 @@ class InputState: NSObject {
attributes: [
.underlineStyle: NSUnderlineStyle.single.rawValue,
.markedClauseSegment: 0,
])
]
)
return attributedSting
}
@ -397,17 +418,17 @@ class InputState: NSObject {
@objc init(node: SymbolNode, useVerticalMode: Bool) {
self.node = node
let candidates = node.children?.map { $0.title } ?? [String]()
let candidates = node.children?.map(\.title) ?? [String]()
super.init(
composingBuffer: "", cursorIndex: 0, candidates: candidates,
useVerticalMode: useVerticalMode)
useVerticalMode: useVerticalMode
)
}
override var description: String {
"<InputState.SymbolTable, candidates:\(candidates), useVerticalMode:\(useVerticalMode), composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
}
}
}
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: "﹣﹦≡|∣∥–︱—︳╴¯ ̄﹉﹊﹍﹎﹋﹌﹏︴∕﹨╱╲/\"),
])
]
)
}

View File

@ -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,18 +234,19 @@ import Cocoa
candidates = (state as! InputState.AssociatedPhrases).candidates
}
if candidates.isEmpty { return false }
if (input.isEnd || input.emacsKey == vChewingEmacsKey.end) && candidates.count > 0 {
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
}
}
if state is InputState.AssociatedPhrases {
if !input.isShiftHold { return false }
@ -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
}

View File

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

View File

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

View File

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

View File

@ -84,7 +84,7 @@ 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
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 {

View File

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

View File

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

View File

@ -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<FSEventStreamHelper>.fromOpaque(clientCallBackInfo!)
.takeUnretainedValue()
let pathsBase = eventPaths.assumingMemoryBound(to: UnsafePointer<CChar>.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)
},

View File

@ -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<CFBoolean>.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("/") {

View File

@ -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<CFString>.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<CFString>.fromOpaque(bundleIDPtr)
.takeUnretainedValue()
let inputsSourceModeID = Unmanaged<CFString>.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
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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..<count {
let rctCandidate = (dispCandidatesWithLabels[index] as NSString).boundingRect(
with: baseSize, options: .usesLineFragmentOrigin,
attributes: candidateWithLabelAttrDict)
attributes: candidateWithLabelAttrDict
)
var cellWidth = rctCandidate.size.width + cellPadding
let cellHeight = rctCandidate.size.height + cellPadding
if cellWidth < cellHeight * 1.35 {
@ -115,7 +116,7 @@ private class HorizontalCandidateView: NSView {
cellPadding = ceil(biggestSize / 2.0)
}
override func draw(_ dirtyRect: NSRect) {
override func draw(_: NSRect) {
let bounds = bounds
NSColor.controlBackgroundColor.setFill() // Candidate list panel base background
NSBezierPath.fill(bounds)
@ -124,21 +125,25 @@ private class HorizontalCandidateView: NSView {
NSBezierPath.strokeLine(
from: NSPoint(x: bounds.size.width, y: 0.0),
to: NSPoint(x: bounds.size.width, y: bounds.size.height))
to: NSPoint(x: bounds.size.width, y: bounds.size.height)
)
var accuWidth: CGFloat = 0
for index in 0..<elementWidths.count {
let currentWidth = elementWidths[index]
let rctCandidateArea = NSRect(
x: accuWidth, y: 0.0, width: currentWidth + 1.0,
height: candidateTextHeight + cellPadding)
height: candidateTextHeight + cellPadding
)
let rctLabel = NSRect(
x: accuWidth + cellPadding / 2 - 1, y: cellPadding / 2, width: keyLabelWidth,
height: keyLabelHeight * 2.0)
height: keyLabelHeight * 2.0
)
let rctCandidatePhrase = NSRect(
x: accuWidth + keyLabelWidth - 1, y: cellPadding / 2,
width: currentWidth - keyLabelWidth,
height: candidateTextHeight)
height: candidateTextHeight
)
var activeCandidateIndexAttr = keyLabelAttrDict
var activeCandidateAttr = candidateAttrDict
@ -149,12 +154,14 @@ private class HorizontalCandidateView: NSView {
case InputMode.imeModeCHS:
NSColor.systemRed.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor)!
of: NSColor.controlBackgroundColor
)!
.setFill()
case InputMode.imeModeCHT:
NSColor.systemBlue.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor)!
of: NSColor.controlBackgroundColor
)!
.setFill()
default:
NSColor.alternateSelectedControlColor.setFill()
@ -181,9 +188,11 @@ private class HorizontalCandidateView: NSView {
}
NSBezierPath.fill(rctCandidateArea)
(keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr)
in: rctLabel, withAttributes: activeCandidateIndexAttr
)
(displayedCandidates[index] as NSString).draw(
in: rctCandidatePhrase, withAttributes: activeCandidateAttr)
in: rctCandidatePhrase, withAttributes: activeCandidateAttr
)
accuWidth += currentWidth + 1.0
}
}
@ -197,13 +206,12 @@ private class HorizontalCandidateView: NSView {
for index in 0..<elementWidths.count {
let currentWidth = elementWidths[index]
if location.x >= 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)
}
}

View File

@ -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..<count {
let rctCandidate = (dispCandidatesWithLabels[index] as NSString).boundingRect(
with: baseSize, options: .usesLineFragmentOrigin,
attributes: candidateWithLabelAttrDict)
attributes: candidateWithLabelAttrDict
)
let cellWidth = rctCandidate.size.width + cellPadding
let cellHeight = rctCandidate.size.height + cellPadding
if calculatedWindowWidth < rctCandidate.size.width {
@ -121,7 +122,7 @@ private class VerticalCandidateView: NSView {
cellPadding = ceil(biggestSize / 2.0)
}
override func draw(_ dirtyRect: NSRect) {
override func draw(_: NSRect) {
let bounds = bounds
NSColor.controlBackgroundColor.setFill() // Candidate list panel base background
NSBezierPath.fill(bounds)
@ -130,7 +131,8 @@ private class VerticalCandidateView: NSView {
NSBezierPath.strokeLine(
from: NSPoint(x: bounds.size.width, y: 0.0),
to: NSPoint(x: bounds.size.width, y: bounds.size.height))
to: NSPoint(x: bounds.size.width, y: bounds.size.height)
)
var accuHeight: CGFloat = 0
for index in 0..<elementHeights.count {
@ -140,10 +142,12 @@ private class VerticalCandidateView: NSView {
)
let rctLabel = NSRect(
x: cellPadding / 2 - 1, y: accuHeight + cellPadding / 2, width: keyLabelWidth,
height: keyLabelHeight * 2.0)
height: keyLabelHeight * 2.0
)
let rctCandidatePhrase = NSRect(
x: cellPadding / 2 - 1 + keyLabelWidth, y: accuHeight + cellPadding / 2 - 1,
width: windowWidth - keyLabelWidth, height: candidateTextHeight)
width: windowWidth - keyLabelWidth, height: candidateTextHeight
)
var activeCandidateIndexAttr = keyLabelAttrDict
var activeCandidateAttr = candidateAttrDict
@ -154,12 +158,14 @@ private class VerticalCandidateView: NSView {
case InputMode.imeModeCHS:
NSColor.systemRed.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor)!
of: NSColor.controlBackgroundColor
)!
.setFill()
case InputMode.imeModeCHT:
NSColor.systemBlue.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor)!
of: NSColor.controlBackgroundColor
)!
.setFill()
default:
NSColor.alternateSelectedControlColor.setFill()
@ -186,9 +192,11 @@ private class VerticalCandidateView: NSView {
}
NSBezierPath.fill(rctCandidateArea)
(keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr)
in: rctLabel, withAttributes: activeCandidateIndexAttr
)
(displayedCandidates[index] as NSString).draw(
in: rctCandidatePhrase, withAttributes: activeCandidateAttr)
in: rctCandidatePhrase, withAttributes: activeCandidateAttr
)
accuHeight += currentHeight
}
}
@ -202,13 +210,12 @@ private class VerticalCandidateView: NSView {
for index in 0..<elementHeights.count {
let currentHeight = elementHeights[index]
if location.y >= 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)
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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