Repo // Deprecating Zonble's method of handling selection key errors.

- Also adding the ability of detecting non-printable chars.
This commit is contained in:
ShikiSuen 2022-10-08 21:56:29 +08:00
parent 1176f53bce
commit 0abc362576
9 changed files with 83 additions and 76 deletions

View File

@ -192,58 +192,56 @@ public enum CandidateKey {
"123456789", "234567890", "QWERTYUIO", "QWERTASDF", "ASDFGHJKL", "ASDFZXCVB", "123456789", "234567890", "QWERTYUIO", "QWERTASDF", "ASDFGHJKL", "ASDFZXCVB",
] ]
public enum ErrorType: Error, LocalizedError { ///
case empty public enum ValidationError {
case noError
case invalidCharacters case invalidCharacters
case containSpace case countMismatch
case duplicatedCharacters
case tooShort
case tooLong
public var errorDescription: String { public var description: String {
switch self { switch self {
case .empty:
return NSLocalizedString("Candidates keys cannot be empty.", comment: "")
case .invalidCharacters: case .invalidCharacters:
return NSLocalizedString( return "- "
"Candidate keys can only contain ASCII characters like alphanumericals.", + NSLocalizedString(
comment: "" "Candidate keys can only contain printable ASCII characters like alphanumericals.",
) comment: ""
case .containSpace: ) + "\n" + "- " + NSLocalizedString("Candidate keys cannot contain space.", comment: "")
return NSLocalizedString("Candidate keys cannot contain space.", comment: "") case .countMismatch:
case .duplicatedCharacters: return "- "
return NSLocalizedString("There should not be duplicated keys.", comment: "") + NSLocalizedString(
case .tooShort: "Minimum 6 candidate keys allowed.", comment: ""
return NSLocalizedString( ) + "\n" + "- " + NSLocalizedString("Maximum 9 candidate keys allowed.", comment: "")
"Please specify at least 6 candidate keys.", comment: "" case .noError:
) return ""
case .tooLong:
return NSLocalizedString("Maximum 9 candidate keys allowed.", comment: "")
} }
} }
} }
public static func validate(keys candidateKeys: String) throws { ///
let trimmed = candidateKeys.trimmingCharacters(in: .whitespacesAndNewlines) /// - Remark:
if trimmed.isEmpty { /// ```
throw CandidateKey.ErrorType.empty /// .trimmingCharacters(in: .whitespacesAndNewlines).deduplicated
/// ```
/// - Parameter candidateKeys:
/// - Returns: nil
public static func validate(keys candidateKeys: String) -> String? {
var result = ValidationError.noError
charValidityCheck: for neta in candidateKeys {
if String(neta) == " " {
result = CandidateKey.ValidationError.invalidCharacters
break charValidityCheck
}
for subNeta in neta.unicodeScalars {
if !subNeta.isPrintableASCII {
result = CandidateKey.ValidationError.invalidCharacters
break charValidityCheck
}
}
} }
if !trimmed.canBeConverted(to: .ascii) { if !(6...9).contains(candidateKeys.count) {
throw CandidateKey.ErrorType.invalidCharacters result = CandidateKey.ValidationError.countMismatch
}
if trimmed.contains(" ") {
throw CandidateKey.ErrorType.containSpace
}
if trimmed.count < 6 {
throw CandidateKey.ErrorType.tooShort
}
if trimmed.count > 9 {
throw CandidateKey.ErrorType.tooLong
}
let set = Set(Array(trimmed))
if set.count != trimmed.count {
throw CandidateKey.ErrorType.duplicatedCharacters
} }
return result == ValidationError.noError ? nil : result.description
} }
} }

View File

@ -72,6 +72,12 @@ extension UniChar {
} }
} }
extension Unicode.Scalar {
public var isPrintableASCII: Bool {
(32...126).contains(value)
}
}
// MARK: - Stable Sort Extension // MARK: - Stable Sort Extension
// Ref: https://stackoverflow.com/a/50545761/4162914 // Ref: https://stackoverflow.com/a/50545761/4162914

View File

@ -57,20 +57,24 @@ struct suiPrefPaneKeyboard: View {
text: $selSelectionKeys.onChange { text: $selSelectionKeys.onChange {
let value = selSelectionKeys let value = selSelectionKeys
let keys: String = value.trimmingCharacters(in: .whitespacesAndNewlines).deduplicated let keys: String = value.trimmingCharacters(in: .whitespacesAndNewlines).deduplicated
do { if keys.isEmpty {
try CandidateKey.validate(keys: keys)
PrefMgr.shared.candidateKeys = keys
selSelectionKeys = PrefMgr.shared.candidateKeys selSelectionKeys = PrefMgr.shared.candidateKeys
} catch CandidateKey.ErrorType.empty { return
selSelectionKeys = PrefMgr.shared.candidateKeys }
} catch { // Start Error Handling.
if let window = ctlPrefUI.shared.controller.window, let error = error as? CandidateKey.ErrorType { if let errorResult = CandidateKey.validate(keys: keys) {
let alert = NSAlert(error: error.errorDescription) if let window = ctlPrefUI.shared.controller.window {
let alert = NSAlert(error: NSLocalizedString("Invalid Selection Keys.", comment: ""))
alert.informativeText = errorResult
alert.beginSheetModal(for: window) { _ in alert.beginSheetModal(for: window) { _ in
selSelectionKeys = PrefMgr.shared.candidateKeys selSelectionKeys = PrefMgr.shared.candidateKeys
} }
IMEApp.buzz() IMEApp.buzz()
} }
} else {
PrefMgr.shared.candidateKeys = keys
selSelectionKeys = PrefMgr.shared.candidateKeys
return
} }
} }
).frame(width: 180).disabled(PrefMgr.shared.useIMKCandidateWindow) ).frame(width: 180).disabled(PrefMgr.shared.useIMKCandidateWindow)

View File

@ -202,22 +202,21 @@ class ctlPrefWindow: NSWindowController {
) )
.deduplicated .deduplicated
else { else {
selectionKeyComboBox.stringValue = PrefMgr.shared.candidateKeys
return return
} }
do { guard let errorResult = CandidateKey.validate(keys: keys) else {
try CandidateKey.validate(keys: keys)
PrefMgr.shared.candidateKeys = keys PrefMgr.shared.candidateKeys = keys
selectionKeyComboBox.stringValue = PrefMgr.shared.candidateKeys selectionKeyComboBox.stringValue = PrefMgr.shared.candidateKeys
} catch CandidateKey.ErrorType.empty { return
selectionKeyComboBox.stringValue = PrefMgr.shared.candidateKeys }
} catch { if let window = window {
if let window = window, let error = error as? CandidateKey.ErrorType { let alert = NSAlert(error: NSLocalizedString("Invalid Selection Keys.", comment: ""))
let alert = NSAlert(error: error.errorDescription) alert.informativeText = errorResult
alert.beginSheetModal(for: window) { _ in alert.beginSheetModal(for: window) { _ in
self.selectionKeyComboBox.stringValue = PrefMgr.shared.candidateKeys self.selectionKeyComboBox.stringValue = PrefMgr.shared.candidateKeys
}
IMEApp.buzz()
} }
IMEApp.buzz()
} }
} }

View File

@ -1,4 +1,5 @@
"vChewing" = "vChewing"; "vChewing" = "vChewing";
"Invalid Selection Keys." = "Invalid Selection Keys.";
"Alphanumerical Input Mode" = "Alphanumerical Input Mode"; "Alphanumerical Input Mode" = "Alphanumerical Input Mode";
"Chinese Input Mode" = "Chinese Input Mode"; "Chinese Input Mode" = "Chinese Input Mode";
"Please enter the client app bundle identifier(s) you want to register." = "Please enter the client app bundle identifier(s) you want to register."; "Please enter the client app bundle identifier(s) you want to register." = "Please enter the client app bundle identifier(s) you want to register.";
@ -51,10 +52,9 @@
"\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude." = "\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude."; "\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude." = "\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude.";
"Edit Phrase Replacement Table…" = "Edit Phrase Replacement Table…"; "Edit Phrase Replacement Table…" = "Edit Phrase Replacement Table…";
"Use Phrase Replacement" = "Use Phrase Replacement"; "Use Phrase Replacement" = "Use Phrase Replacement";
"Candidate keys can only contain ASCII characters like alphanumericals." = "Candidate keys can only contain ASCII characters like alphanumericals."; "Candidate keys can only contain printable ASCII characters like alphanumericals." = "Candidate keys can only contain printable ASCII characters like alphanumericals.";
"Candidate keys cannot contain space." = "Candidate keys cannot contain space."; "Candidate keys cannot contain space." = "Candidate keys cannot contain space.";
"There should not be duplicated keys." = "There should not be duplicated keys."; "Minimum 6 candidate keys allowed." = "Minimum 6 candidate keys allowed.";
"Please specify at least 6 candidate keys." = "Please specify at least 6 candidate keys.";
"Maximum 9 candidate keys allowed." = "Maximum 9 candidate keys allowed."; "Maximum 9 candidate keys allowed." = "Maximum 9 candidate keys allowed.";
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ Phrase replacement mode enabled, interfering user phrase entry."; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ Phrase replacement mode enabled, interfering user phrase entry.";
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match."; "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match.";

View File

@ -1,4 +1,5 @@
"vChewing" = "vChewing"; "vChewing" = "vChewing";
"Invalid Selection Keys." = "Invalid Selection Keys.";
"Alphanumerical Input Mode" = "Alphanumerical Input Mode"; "Alphanumerical Input Mode" = "Alphanumerical Input Mode";
"Chinese Input Mode" = "Chinese Input Mode"; "Chinese Input Mode" = "Chinese Input Mode";
"Please enter the client app bundle identifier(s) you want to register." = "Please enter the client app bundle identifier(s) you want to register."; "Please enter the client app bundle identifier(s) you want to register." = "Please enter the client app bundle identifier(s) you want to register.";
@ -51,10 +52,9 @@
"\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude." = "\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude."; "\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude." = "\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude.";
"Edit Phrase Replacement Table…" = "Edit Phrase Replacement Table…"; "Edit Phrase Replacement Table…" = "Edit Phrase Replacement Table…";
"Use Phrase Replacement" = "Use Phrase Replacement"; "Use Phrase Replacement" = "Use Phrase Replacement";
"Candidate keys can only contain ASCII characters like alphanumericals." = "Candidate keys can only contain ASCII characters like alphanumericals."; "Candidate keys can only contain printable ASCII characters like alphanumericals." = "Candidate keys can only contain printable ASCII characters like alphanumericals.";
"Candidate keys cannot contain space." = "Candidate keys cannot contain space."; "Candidate keys cannot contain space." = "Candidate keys cannot contain space.";
"There should not be duplicated keys." = "There should not be duplicated keys."; "Minimum 6 candidate keys allowed." = "Minimum 6 candidate keys allowed.";
"Please specify at least 6 candidate keys." = "Please specify at least 6 candidate keys.";
"Maximum 9 candidate keys allowed." = "Maximum 9 candidate keys allowed."; "Maximum 9 candidate keys allowed." = "Maximum 9 candidate keys allowed.";
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ Phrase replacement mode enabled, interfering user phrase entry."; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ Phrase replacement mode enabled, interfering user phrase entry.";
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match."; "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match.";

View File

@ -1,4 +1,5 @@
"vChewing" = "威注音入力アプリ"; "vChewing" = "威注音入力アプリ";
"Invalid Selection Keys." = "候補用キーによる不具合。";
"Alphanumerical Input Mode" = "英數入力モード"; "Alphanumerical Input Mode" = "英數入力モード";
"Chinese Input Mode" = "漢語入力モード"; "Chinese Input Mode" = "漢語入力モード";
"Please enter the client app bundle identifier(s) you want to register." = "登録したい客体アプリの唯一識別子Bundle Identifierをご入力ください。"; "Please enter the client app bundle identifier(s) you want to register." = "登録したい客体アプリの唯一識別子Bundle Identifierをご入力ください。";
@ -51,10 +52,9 @@
"\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude." = "「%@」は既存語彙:\n ENTER で最優先にし、SHIFT+COMMAND+ENTER で優先順位を下げる;\n BackSpace 或いは Delete で排除。"; "\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude." = "「%@」は既存語彙:\n ENTER で最優先にし、SHIFT+COMMAND+ENTER で優先順位を下げる;\n BackSpace 或いは Delete で排除。";
"Edit Phrase Replacement Table…" = "言葉置換表を編集…"; "Edit Phrase Replacement Table…" = "言葉置換表を編集…";
"Use Phrase Replacement" = "言葉置換機能"; "Use Phrase Replacement" = "言葉置換機能";
"Candidate keys can only contain ASCII characters like alphanumericals." = "言選り用キー陣列にはASCII文字だけをご登録ください英数など。"; "Candidate keys can only contain printable ASCII characters like alphanumericals." = "言選り用キー陣列にはプリントできるASCII文字だけをご登録ください英数など。";
"Candidate keys cannot contain space." = "言選り用キー陣列にスペースキーは登録できません。"; "Candidate keys cannot contain space." = "言選り用キー陣列にスペースキーは登録できません。";
"There should not be duplicated keys." = "言選り用キー陣列に同じキーの重複登録はできません。"; "Minimum 6 candidate keys allowed." = "言選り用キー陣列に少なくとも6つのキーをご登録ください。";
"Please specify at least 6 candidate keys." = "言選り用キー陣列に少なくとも6つのキーをご登録ください。";
"Maximum 9 candidate keys allowed." = "言選り用キー陣列には最多9つキー登録できます。"; "Maximum 9 candidate keys allowed." = "言選り用キー陣列には最多9つキー登録できます。";
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 言葉置換機能稼働中、新添付言葉にも影響。"; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 言葉置換機能稼働中、新添付言葉にも影響。";
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ 対処不可:緩衝列の字数は読みの数と不同等。"; "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ 対処不可:緩衝列の字数は読みの数と不同等。";

View File

@ -1,4 +1,5 @@
"vChewing" = "威注音输入法"; "vChewing" = "威注音输入法";
"Invalid Selection Keys." = "选字键参数资料值不规范。";
"Alphanumerical Input Mode" = "英数输入模式"; "Alphanumerical Input Mode" = "英数输入模式";
"Chinese Input Mode" = "中文输入模式"; "Chinese Input Mode" = "中文输入模式";
"Please enter the client app bundle identifier(s) you want to register." = "请键入您要登记的客体应用的唯一标帜Bundle Identifier。"; "Please enter the client app bundle identifier(s) you want to register." = "请键入您要登记的客体应用的唯一标帜Bundle Identifier。";
@ -51,10 +52,9 @@
"\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude." = "「%@」已存在:\n 敲 Enter 以升权、敲 Shift+Command+Enter 以降权;\n 敲 BackSpace 或 Delete 以排除。"; "\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude." = "「%@」已存在:\n 敲 Enter 以升权、敲 Shift+Command+Enter 以降权;\n 敲 BackSpace 或 Delete 以排除。";
"Edit Phrase Replacement Table…" = "编辑语汇置换表…"; "Edit Phrase Replacement Table…" = "编辑语汇置换表…";
"Use Phrase Replacement" = "使用语汇置换"; "Use Phrase Replacement" = "使用语汇置换";
"Candidate keys can only contain ASCII characters like alphanumericals." = "选字键只能是英数等 ASCII 字符。"; "Candidate keys can only contain printable ASCII characters like alphanumericals." = "选字键只能是英数等 ASCII 可列印字符。";
"Candidate keys cannot contain space." = "选字键不得包含空格。"; "Candidate keys cannot contain space." = "选字键不得包含空格。";
"There should not be duplicated keys." = "选字键不得重复。"; "Minimum 6 candidate keys allowed." = "请至少指定 6 个选字键。";
"Please specify at least 6 candidate keys." = "请至少指定 6 个选字键。";
"Maximum 9 candidate keys allowed." = "选字键最多只能指定 9 个。"; "Maximum 9 candidate keys allowed." = "选字键最多只能指定 9 个。";
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 语汇置换功能已启用,会波及语汇自订。"; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 语汇置换功能已启用,会波及语汇自订。";
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ 无法处理:组字区字数与读音数不对应。"; "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ 无法处理:组字区字数与读音数不对应。";

View File

@ -1,4 +1,5 @@
"vChewing" = "威注音輸入法"; "vChewing" = "威注音輸入法";
"Invalid Selection Keys." = "選字鍵參數資料值不規範。";
"Alphanumerical Input Mode" = "英數輸入模式"; "Alphanumerical Input Mode" = "英數輸入模式";
"Chinese Input Mode" = "中文輸入模式"; "Chinese Input Mode" = "中文輸入模式";
"Please enter the client app bundle identifier(s) you want to register." = "請鍵入您要登記的客體應用的唯一標幟Bundle Identifier。"; "Please enter the client app bundle identifier(s) you want to register." = "請鍵入您要登記的客體應用的唯一標幟Bundle Identifier。";
@ -51,10 +52,9 @@
"\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude." = "「%@」已存在:\n 敲 Enter 以升權、敲 Shift+Command+Enter 以降權;\n 敲 BackSpace 或 Delete 以排除。"; "\"%@\" already exists:\n ENTER to boost, SHIFT+COMMAND+ENTER to nerf, \n BackSpace or Delete key to exclude." = "「%@」已存在:\n 敲 Enter 以升權、敲 Shift+Command+Enter 以降權;\n 敲 BackSpace 或 Delete 以排除。";
"Edit Phrase Replacement Table…" = "編輯語彙置換表…"; "Edit Phrase Replacement Table…" = "編輯語彙置換表…";
"Use Phrase Replacement" = "使用語彙置換"; "Use Phrase Replacement" = "使用語彙置換";
"Candidate keys can only contain ASCII characters like alphanumericals." = "選字鍵只能是英數等 ASCII 字符。"; "Candidate keys can only contain printable ASCII characters like alphanumericals." = "選字鍵只能是英數等 ASCII 可列印字符。";
"Candidate keys cannot contain space." = "選字鍵不得包含空格。"; "Candidate keys cannot contain space." = "選字鍵不得包含空格。";
"There should not be duplicated keys." = "選字鍵不得重複。"; "Minimum 6 candidate keys allowed." = "請至少指定 6 個選字鍵。";
"Please specify at least 6 candidate keys." = "請至少指定 6 個選字鍵。";
"Maximum 9 candidate keys allowed." = "選字鍵最多只能指定 9 個。"; "Maximum 9 candidate keys allowed." = "選字鍵最多只能指定 9 個。";
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 語彙置換功能已啟用,會波及語彙自訂。"; "⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 語彙置換功能已啟用,會波及語彙自訂。";
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ 無法處理:組字區字數與讀音數不對應。"; "⚠︎ Unhandlable: Chars and Readings in buffer doesn't match." = "⚠︎ 無法處理:組字區字數與讀音數不對應。";