Zonble: UserPhrases // UTF8 Surrogate Pair Fix - phase 2
- Add a feature to block users from adding user phrases when an unhandlable char appeared in the selection.
This commit is contained in:
parent
3e561d215c
commit
2d444d174c
|
@ -91,16 +91,14 @@ class InputState: NSObject {
|
||||||
class NotEmpty: InputState {
|
class NotEmpty: InputState {
|
||||||
@objc private(set) var composingBuffer: String
|
@objc private(set) var composingBuffer: String
|
||||||
@objc private(set) var cursorIndex: UInt
|
@objc private(set) var cursorIndex: UInt
|
||||||
@objc private(set) var phrases: [InputPhrase]
|
|
||||||
|
|
||||||
@objc init(composingBuffer: String, cursorIndex: UInt, phrases: [InputPhrase]) {
|
@objc init(composingBuffer: String, cursorIndex: UInt) {
|
||||||
self.composingBuffer = composingBuffer
|
self.composingBuffer = composingBuffer
|
||||||
self.cursorIndex = cursorIndex
|
self.cursorIndex = cursorIndex
|
||||||
self.phrases = phrases
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override var description: String {
|
override var description: String {
|
||||||
"<InputState.NotEmpty, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex), phrases:\(phrases)>"
|
"<InputState.NotEmpty, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,8 +107,8 @@ class InputState: NSObject {
|
||||||
class Inputting: NotEmpty {
|
class Inputting: NotEmpty {
|
||||||
@objc var poppedText: String = ""
|
@objc var poppedText: String = ""
|
||||||
|
|
||||||
@objc override init(composingBuffer: String, cursorIndex: UInt, phrases: [InputPhrase]) {
|
@objc override init(composingBuffer: String, cursorIndex: UInt) {
|
||||||
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex, phrases: phrases)
|
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc var attributedString: NSAttributedString {
|
@objc var attributedString: NSAttributedString {
|
||||||
|
@ -122,7 +120,7 @@ class InputState: NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
override var description: String {
|
override var description: String {
|
||||||
"<InputState.Inputting, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex), phrases:\(phrases)>, poppedText:\(poppedText)>"
|
"<InputState.Inputting, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>, poppedText:\(poppedText)>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +134,11 @@ class InputState: NSObject {
|
||||||
@objc private(set) var markerIndex: UInt
|
@objc private(set) var markerIndex: UInt
|
||||||
@objc private(set) var markedRange: NSRange
|
@objc private(set) var markedRange: NSRange
|
||||||
@objc var tooltip: String {
|
@objc var tooltip: String {
|
||||||
|
|
||||||
|
if composingBuffer.count != readings.count {
|
||||||
|
return NSLocalizedString("⚠︎ Unhandlable char selected for user phrases.", comment: "")
|
||||||
|
}
|
||||||
|
|
||||||
if Preferences.phraseReplacementEnabled {
|
if Preferences.phraseReplacementEnabled {
|
||||||
return NSLocalizedString("⚠︎ Phrase replacement mode enabled, interfering user phrase entry.", comment: "")
|
return NSLocalizedString("⚠︎ Phrase replacement mode enabled, interfering user phrase entry.", comment: "")
|
||||||
}
|
}
|
||||||
|
@ -144,7 +146,7 @@ class InputState: NSObject {
|
||||||
if markedRange.length == 0 {
|
if markedRange.length == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = (composingBuffer as NSString).substring(with: markedRange)
|
let text = (composingBuffer as NSString).substring(with: markedRange)
|
||||||
if markedRange.length < kMinMarkRangeLength {
|
if markedRange.length < kMinMarkRangeLength {
|
||||||
return String(format: NSLocalizedString("\"%@\" length must ≥ 2 for a user phrase.", comment: ""), text)
|
return String(format: NSLocalizedString("\"%@\" length must ≥ 2 for a user phrase.", comment: ""), text)
|
||||||
|
@ -154,12 +156,15 @@ class InputState: NSObject {
|
||||||
return String(format: NSLocalizedString("\"%@\" selected. ENTER to add user phrase.", comment: ""), text)
|
return String(format: NSLocalizedString("\"%@\" selected. ENTER to add user phrase.", comment: ""), text)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc init(composingBuffer: String, cursorIndex: UInt, markerIndex: UInt, phrases: [InputPhrase]) {
|
@objc private(set) var readings: [String]
|
||||||
|
|
||||||
|
@objc init(composingBuffer: String, cursorIndex: UInt, markerIndex: UInt, readings: [String]) {
|
||||||
self.markerIndex = markerIndex
|
self.markerIndex = markerIndex
|
||||||
let begin = min(cursorIndex, markerIndex)
|
let begin = min(cursorIndex, markerIndex)
|
||||||
let end = max(cursorIndex, markerIndex)
|
let end = max(cursorIndex, markerIndex)
|
||||||
markedRange = NSMakeRange(Int(begin), Int(end - begin))
|
markedRange = NSMakeRange(Int(begin), Int(end - begin))
|
||||||
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex, phrases: phrases)
|
self.readings = readings
|
||||||
|
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc var attributedString: NSAttributedString {
|
@objc var attributedString: NSAttributedString {
|
||||||
|
@ -183,34 +188,26 @@ class InputState: NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
override var description: String {
|
override var description: String {
|
||||||
"<InputState.Marking, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex), markedRange:\(markedRange), phrases:\(phrases)>"
|
"<InputState.Marking, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex), markedRange:\(markedRange)>"
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func convertToInputting() -> Inputting {
|
@objc func convertToInputting() -> Inputting {
|
||||||
let state = Inputting(composingBuffer: composingBuffer, cursorIndex: cursorIndex, phrases: phrases)
|
let state = Inputting(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc var validToWrite: Bool {
|
@objc var validToWrite: Bool {
|
||||||
markedRange.length >= kMinMarkRangeLength && markedRange.length <= kMaxMarkRangeLength
|
if composingBuffer.count != readings.count {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return markedRange.length >= kMinMarkRangeLength && markedRange.length <= kMaxMarkRangeLength
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc var userPhrase: String {
|
@objc var userPhrase: String {
|
||||||
let text = (composingBuffer as NSString).substring(with: markedRange)
|
let text = (composingBuffer as NSString).substring(with: markedRange)
|
||||||
let end = markedRange.location + markedRange.length
|
let exactBegin = StringUtils.convertToCharIndex(from: markedRange.location, in: composingBuffer)
|
||||||
var selectedPhrases = [InputPhrase]()
|
let exactEnd = StringUtils.convertToCharIndex(from: markedRange.location + markedRange.length, in: composingBuffer)
|
||||||
var length = 0
|
let readings = readings[exactBegin..<exactEnd]
|
||||||
for component in self.phrases {
|
|
||||||
if length >= end {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if length >= markedRange.location {
|
|
||||||
selectedPhrases.append(component)
|
|
||||||
}
|
|
||||||
length += (component.text as NSString).length
|
|
||||||
}
|
|
||||||
|
|
||||||
let readings = selectedPhrases.map { $0.reading }
|
|
||||||
let joined = readings.joined(separator: "-")
|
let joined = readings.joined(separator: "-")
|
||||||
return "\(text) \(joined)"
|
return "\(text) \(joined)"
|
||||||
}
|
}
|
||||||
|
@ -222,10 +219,10 @@ class InputState: NSObject {
|
||||||
@objc private(set) var candidates: [String]
|
@objc private(set) var candidates: [String]
|
||||||
@objc private(set) var useVerticalMode: Bool
|
@objc private(set) var useVerticalMode: Bool
|
||||||
|
|
||||||
@objc init(composingBuffer: String, cursorIndex: UInt, candidates: [String], phrases: [InputPhrase], useVerticalMode: Bool) {
|
@objc init(composingBuffer: String, cursorIndex: UInt, candidates: [String], useVerticalMode: Bool) {
|
||||||
self.candidates = candidates
|
self.candidates = candidates
|
||||||
self.useVerticalMode = useVerticalMode
|
self.useVerticalMode = useVerticalMode
|
||||||
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex, phrases: phrases)
|
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc var attributedString: NSAttributedString {
|
@objc var attributedString: NSAttributedString {
|
||||||
|
@ -237,7 +234,7 @@ class InputState: NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
override var description: String {
|
override var description: String {
|
||||||
"<InputState.ChoosingCandidate, candidates:\(candidates), useVerticalMode:\(useVerticalMode), phrases:\(phrases), composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
|
"<InputState.ChoosingCandidate, candidates:\(candidates), useVerticalMode:\(useVerticalMode), composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -545,7 +545,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
||||||
// Shift + left
|
// Shift + left
|
||||||
if (currentState.cursorIndex > 0) {
|
if (currentState.cursorIndex > 0) {
|
||||||
NSInteger previousPosition = [StringUtils previousUtf16PositionForIndex:currentState.cursorIndex in:currentState.composingBuffer];
|
NSInteger previousPosition = [StringUtils previousUtf16PositionForIndex:currentState.cursorIndex in:currentState.composingBuffer];
|
||||||
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:previousPosition phrases:currentState.phrases];
|
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:previousPosition readings:[self _currentReadings]];
|
||||||
stateCallback(marking);
|
stateCallback(marking);
|
||||||
} else {
|
} else {
|
||||||
errorCallback();
|
errorCallback();
|
||||||
|
@ -582,7 +582,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
||||||
// Shift + Right
|
// Shift + Right
|
||||||
if (currentState.cursorIndex < currentState.composingBuffer.length) {
|
if (currentState.cursorIndex < currentState.composingBuffer.length) {
|
||||||
NSInteger nextPosition = [StringUtils nextUtf16PositionForIndex:currentState.cursorIndex in:currentState.composingBuffer];
|
NSInteger nextPosition = [StringUtils nextUtf16PositionForIndex:currentState.cursorIndex in:currentState.composingBuffer];
|
||||||
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:nextPosition phrases:currentState.phrases];
|
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:nextPosition readings:[self _currentReadings]];
|
||||||
stateCallback(marking);
|
stateCallback(marking);
|
||||||
} else {
|
} else {
|
||||||
errorCallback();
|
errorCallback();
|
||||||
|
@ -809,7 +809,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
||||||
NSUInteger index = state.markerIndex;
|
NSUInteger index = state.markerIndex;
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
index = [StringUtils previousUtf16PositionForIndex:index in:state.composingBuffer];
|
index = [StringUtils previousUtf16PositionForIndex:index in:state.composingBuffer];
|
||||||
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index phrases:state.phrases];
|
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index readings:state.readings];
|
||||||
stateCallback(marking);
|
stateCallback(marking);
|
||||||
} else {
|
} else {
|
||||||
errorCallback();
|
errorCallback();
|
||||||
|
@ -824,7 +824,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
||||||
NSUInteger index = state.markerIndex;
|
NSUInteger index = state.markerIndex;
|
||||||
if (index < state.composingBuffer.length) {
|
if (index < state.composingBuffer.length) {
|
||||||
index = [StringUtils nextUtf16PositionForIndex:index in:state.composingBuffer];
|
index = [StringUtils nextUtf16PositionForIndex:index in:state.composingBuffer];
|
||||||
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index phrases:state.phrases];
|
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index readings:state.readings];
|
||||||
stateCallback(marking);
|
stateCallback(marking);
|
||||||
} else {
|
} else {
|
||||||
errorCallback();
|
errorCallback();
|
||||||
|
@ -1104,7 +1104,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
||||||
NSString *composedText = [head stringByAppendingString:[reading stringByAppendingString:tail]];
|
NSString *composedText = [head stringByAppendingString:[reading stringByAppendingString:tail]];
|
||||||
NSInteger cursorIndex = composedStringCursorIndex + [reading length];
|
NSInteger cursorIndex = composedStringCursorIndex + [reading length];
|
||||||
|
|
||||||
InputStateInputting *newState = [[InputStateInputting alloc] initWithComposingBuffer:composedText cursorIndex:cursorIndex phrases:phrases];
|
InputStateInputting *newState = [[InputStateInputting alloc] initWithComposingBuffer:composedText cursorIndex:cursorIndex];
|
||||||
return newState;
|
return newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1174,7 +1174,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStateChoosingCandidate *state = [[InputStateChoosingCandidate alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex candidates:candidatesArray phrases:currentState.phrases useVerticalMode:useVerticalMode];
|
InputStateChoosingCandidate *state = [[InputStateChoosingCandidate alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex candidates:candidatesArray useVerticalMode:useVerticalMode];
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
"Please specify at least 4 candidate keys." = "Please specify at least 4 candidate keys.";
|
"Please specify at least 4 candidate keys." = "Please specify at least 4 candidate keys.";
|
||||||
"Maximum 15 candidate keys allowed." = "Maximum 15 candidate keys allowed.";
|
"Maximum 15 candidate keys allowed." = "Maximum 15 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 char selected for user phrases." = "⚠︎ Unhandlable char selected for user phrases.";
|
||||||
"NT351 BPMF EMU" = "NT351 Per-Char Select Mode";
|
"NT351 BPMF EMU" = "NT351 Per-Char Select Mode";
|
||||||
"CNS11643 Mode" = "CNS11643 Mode";
|
"CNS11643 Mode" = "CNS11643 Mode";
|
||||||
"Reboot vChewing…" = "Reboot vChewing…";
|
"Reboot vChewing…" = "Reboot vChewing…";
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
"Please specify at least 4 candidate keys." = "言選り用キー陣列に少なくとも4つのキーをご登録ください。";
|
"Please specify at least 4 candidate keys." = "言選り用キー陣列に少なくとも4つのキーをご登録ください。";
|
||||||
"Maximum 15 candidate keys allowed." = "言選り用キー陣列には最多15つキー登録できます。";
|
"Maximum 15 candidate keys allowed." = "言選り用キー陣列には最多15つキー登録できます。";
|
||||||
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 言葉置換機能稼働中、新添付言葉にも影響。";
|
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 言葉置換機能稼働中、新添付言葉にも影響。";
|
||||||
|
"⚠︎ Unhandlable char selected for user phrases." = "⚠︎ ユーザー辞書の対処できない文字は選択されています。";
|
||||||
"NT351 BPMF EMU" = "全候補入力モード";
|
"NT351 BPMF EMU" = "全候補入力モード";
|
||||||
"CNS11643 Mode" = "全字庫モード";
|
"CNS11643 Mode" = "全字庫モード";
|
||||||
"Reboot vChewing…" = "入力アプリ再起動…";
|
"Reboot vChewing…" = "入力アプリ再起動…";
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
"Please specify at least 4 candidate keys." = "请至少指定四个选字键。";
|
"Please specify at least 4 candidate keys." = "请至少指定四个选字键。";
|
||||||
"Maximum 15 candidate keys allowed." = "选字键最多只能指定十五个。";
|
"Maximum 15 candidate keys allowed." = "选字键最多只能指定十五个。";
|
||||||
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 语汇置换功能已启用,会波及语汇自订。";
|
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 语汇置换功能已启用,会波及语汇自订。";
|
||||||
|
"⚠︎ Unhandlable char selected for user phrases." = "⚠︎ 已选中无法处理的字元,无法加入自订语汇。";
|
||||||
"NT351 BPMF EMU" = "模拟逐字选字输入";
|
"NT351 BPMF EMU" = "模拟逐字选字输入";
|
||||||
"CNS11643 Mode" = "全字库模式";
|
"CNS11643 Mode" = "全字库模式";
|
||||||
"Reboot vChewing…" = "重新启动输入法…";
|
"Reboot vChewing…" = "重新启动输入法…";
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
"Please specify at least 4 candidate keys." = "請至少指定四個選字鍵。";
|
"Please specify at least 4 candidate keys." = "請至少指定四個選字鍵。";
|
||||||
"Maximum 15 candidate keys allowed." = "選字鍵最多只能指定十五個。";
|
"Maximum 15 candidate keys allowed." = "選字鍵最多只能指定十五個。";
|
||||||
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 語彙置換功能已啟用,會波及語彙自訂。";
|
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry." = "⚠︎ 語彙置換功能已啟用,會波及語彙自訂。";
|
||||||
|
"⚠︎ Unhandlable char selected for user phrases." = "⚠︎ 已選中無法處理的字元,無法加入自訂語彙。";
|
||||||
"NT351 BPMF EMU" = "模擬逐字選字輸入";
|
"NT351 BPMF EMU" = "模擬逐字選字輸入";
|
||||||
"CNS11643 Mode" = "全字庫模式";
|
"CNS11643 Mode" = "全字庫模式";
|
||||||
"Reboot vChewing…" = "重新啟動輸入法…";
|
"Reboot vChewing…" = "重新啟動輸入法…";
|
||||||
|
|
Loading…
Reference in New Issue