Repo // Move IMEState-related protocols to Shared package.
This commit is contained in:
parent
cab7eb28f7
commit
1648152b24
|
@ -0,0 +1,64 @@
|
||||||
|
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||||
|
// ====================
|
||||||
|
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||||
|
// ... with NTL restriction stating that:
|
||||||
|
// No trademark license is granted to use the trade names, trademarks, service
|
||||||
|
// marks, or product names of Contributor, except as required to fulfill notice
|
||||||
|
// requirements defined in MIT License.
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
// 所有 IMEState 均遵守該協定:
|
||||||
|
public protocol IMEStateProtocol {
|
||||||
|
var type: StateType { get }
|
||||||
|
var data: StateDataProtocol { get }
|
||||||
|
var isASCIIMode: Bool { get set }
|
||||||
|
var isVerticalTyping: Bool { get set }
|
||||||
|
var isVerticalCandidateWindow: Bool { get set }
|
||||||
|
var candidates: [(String, String)] { get set }
|
||||||
|
var hasComposition: Bool { get }
|
||||||
|
var isCandidateContainer: Bool { get }
|
||||||
|
var displayedText: String { get }
|
||||||
|
var displayedTextConverted: String { get }
|
||||||
|
var textToCommit: String { get set }
|
||||||
|
var tooltip: String { get set }
|
||||||
|
var attributedString: NSAttributedString { get }
|
||||||
|
var convertedToInputting: IMEStateProtocol { get }
|
||||||
|
var isFilterable: Bool { get }
|
||||||
|
var isMarkedLengthValid: Bool { get }
|
||||||
|
var node: CandidateNode { get set }
|
||||||
|
var displayTextSegments: [String] { get }
|
||||||
|
var tooltipBackupForInputting: String { get set }
|
||||||
|
var markedRange: Range<Int> { get }
|
||||||
|
var u16MarkedRange: Range<Int> { get }
|
||||||
|
var u16Cursor: Int { get }
|
||||||
|
var cursor: Int { get set }
|
||||||
|
var marker: Int { get set }
|
||||||
|
}
|
||||||
|
|
||||||
|
public protocol StateDataProtocol {
|
||||||
|
var cursor: Int { get set }
|
||||||
|
var marker: Int { get set }
|
||||||
|
var markedRange: Range<Int> { get }
|
||||||
|
var u16MarkedRange: Range<Int> { get }
|
||||||
|
var u16Cursor: Int { get }
|
||||||
|
var textToCommit: String { get set }
|
||||||
|
var markedReadings: [String] { get set }
|
||||||
|
var displayTextSegments: [String] { get set }
|
||||||
|
var isFilterable: Bool { get }
|
||||||
|
var isVerticalTyping: Bool { get set }
|
||||||
|
var isMarkedLengthValid: Bool { get }
|
||||||
|
var candidates: [(String, String)] { get set }
|
||||||
|
var displayedText: String { get set }
|
||||||
|
var displayedTextConverted: String { get }
|
||||||
|
var tooltipBackupForInputting: String { get set }
|
||||||
|
var tooltip: String { get set }
|
||||||
|
var attributedStringNormal: NSAttributedString { get }
|
||||||
|
var attributedStringMarking: NSAttributedString { get }
|
||||||
|
var attributedStringPlaceholder: NSAttributedString { get }
|
||||||
|
var userPhraseDumped: String { get }
|
||||||
|
var userPhraseDumpedConverted: String { get }
|
||||||
|
var doesUserPhraseExist: Bool { get }
|
||||||
|
var tooltipColorState: TooltipColorState { get set }
|
||||||
|
mutating func updateTooltipForMarking()
|
||||||
|
}
|
|
@ -103,6 +103,33 @@ public enum UserDef: String, CaseIterable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Tooltip Color States
|
||||||
|
|
||||||
|
public enum TooltipColorState {
|
||||||
|
case normal
|
||||||
|
case redAlert
|
||||||
|
case warning
|
||||||
|
case denialOverflow
|
||||||
|
case denialInsufficiency
|
||||||
|
case prompt
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - IMEState types.
|
||||||
|
|
||||||
|
// 用以讓每個狀態自描述的 enum。
|
||||||
|
public enum StateType: String {
|
||||||
|
case ofDeactivated = "Deactivated"
|
||||||
|
case ofEmpty = "Empty"
|
||||||
|
case ofAbortion = "Abortion" // 該狀態會自動轉為 Empty
|
||||||
|
case ofCommitting = "Committing"
|
||||||
|
case ofAssociates = "Associates"
|
||||||
|
case ofNotEmpty = "NotEmpty"
|
||||||
|
case ofInputting = "Inputting"
|
||||||
|
case ofMarking = "Marking"
|
||||||
|
case ofCandidates = "Candidates"
|
||||||
|
case ofSymbolTable = "SymbolTable"
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Parser for Syllable composer
|
// MARK: - Parser for Syllable composer
|
||||||
|
|
||||||
public enum KeyboardParser: Int, CaseIterable {
|
public enum KeyboardParser: Int, CaseIterable {
|
||||||
|
|
|
@ -15,6 +15,7 @@ let package = Package(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(path: "../Fuziki_NSAttributedTextView"),
|
.package(path: "../Fuziki_NSAttributedTextView"),
|
||||||
.package(path: "../vChewing_CocoaExtension"),
|
.package(path: "../vChewing_CocoaExtension"),
|
||||||
|
.package(path: "../vChewing_Shared"),
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
|
@ -22,6 +23,7 @@ let package = Package(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "NSAttributedTextView", package: "Fuziki_NSAttributedTextView"),
|
.product(name: "NSAttributedTextView", package: "Fuziki_NSAttributedTextView"),
|
||||||
.product(name: "CocoaExtension", package: "vChewing_CocoaExtension"),
|
.product(name: "CocoaExtension", package: "vChewing_CocoaExtension"),
|
||||||
|
.product(name: "Shared", package: "vChewing_Shared"),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
|
@ -9,17 +9,9 @@
|
||||||
import Cocoa
|
import Cocoa
|
||||||
import CocoaExtension
|
import CocoaExtension
|
||||||
import NSAttributedTextView
|
import NSAttributedTextView
|
||||||
|
import Shared
|
||||||
|
|
||||||
public class TooltipUI: NSWindowController {
|
public class TooltipUI: NSWindowController {
|
||||||
public enum ColorStates {
|
|
||||||
case normal
|
|
||||||
case redAlert
|
|
||||||
case warning
|
|
||||||
case denialOverflow
|
|
||||||
case denialInsufficiency
|
|
||||||
case prompt
|
|
||||||
}
|
|
||||||
|
|
||||||
private var messageText: NSAttributedTooltipTextView
|
private var messageText: NSAttributedTooltipTextView
|
||||||
private var tooltip: String = "" {
|
private var tooltip: String = "" {
|
||||||
didSet {
|
didSet {
|
||||||
|
@ -68,7 +60,7 @@ public class TooltipUI: NSWindowController {
|
||||||
set(windowTopLeftPoint: point, bottomOutOfScreenAdjustmentHeight: heightDelta)
|
set(windowTopLeftPoint: point, bottomOutOfScreenAdjustmentHeight: heightDelta)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setColor(state: ColorStates) {
|
public func setColor(state: TooltipColorState) {
|
||||||
var backgroundColor = NSColor.controlBackgroundColor
|
var backgroundColor = NSColor.controlBackgroundColor
|
||||||
var textColor = NSColor.textColor
|
var textColor = NSColor.textColor
|
||||||
switch state {
|
switch state {
|
||||||
|
|
|
@ -7,47 +7,7 @@
|
||||||
// requirements defined in MIT License.
|
// requirements defined in MIT License.
|
||||||
|
|
||||||
import LangModelAssembly
|
import LangModelAssembly
|
||||||
|
import Shared
|
||||||
// 用以讓每個狀態自描述的 enum。
|
|
||||||
public enum StateType: String {
|
|
||||||
case ofDeactivated = "Deactivated"
|
|
||||||
case ofEmpty = "Empty"
|
|
||||||
case ofAbortion = "Abortion" // 該狀態會自動轉為 Empty
|
|
||||||
case ofCommitting = "Committing"
|
|
||||||
case ofAssociates = "Associates"
|
|
||||||
case ofNotEmpty = "NotEmpty"
|
|
||||||
case ofInputting = "Inputting"
|
|
||||||
case ofMarking = "Marking"
|
|
||||||
case ofCandidates = "Candidates"
|
|
||||||
case ofSymbolTable = "SymbolTable"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 所有 IMEState 均遵守該協定:
|
|
||||||
public protocol IMEStateProtocol {
|
|
||||||
var type: StateType { get }
|
|
||||||
var data: StateData { get }
|
|
||||||
var isASCIIMode: Bool { get set }
|
|
||||||
var isVerticalTyping: Bool { get set }
|
|
||||||
var isVerticalCandidateWindow: Bool { get set }
|
|
||||||
var candidates: [(String, String)] { get }
|
|
||||||
var hasComposition: Bool { get }
|
|
||||||
var isCandidateContainer: Bool { get }
|
|
||||||
var displayedText: String { get }
|
|
||||||
var displayedTextConverted: String { get }
|
|
||||||
var textToCommit: String { get set }
|
|
||||||
var tooltip: String { get set }
|
|
||||||
var attributedString: NSAttributedString { get }
|
|
||||||
var convertedToInputting: IMEState { get }
|
|
||||||
var isFilterable: Bool { get }
|
|
||||||
var isMarkedLengthValid: Bool { get }
|
|
||||||
var node: CandidateNode { get set }
|
|
||||||
var displayTextSegments: [String] { get }
|
|
||||||
var tooltipBackupForInputting: String { get set }
|
|
||||||
var markedRange: Range<Int> { get }
|
|
||||||
var cursor: Int { get }
|
|
||||||
var u16MarkedRange: Range<Int> { get }
|
|
||||||
var u16Cursor: Int { get }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 用以呈現輸入法控制器(ctlInputMethod)的各種狀態。
|
/// 用以呈現輸入法控制器(ctlInputMethod)的各種狀態。
|
||||||
///
|
///
|
||||||
|
@ -82,17 +42,17 @@ public protocol IMEStateProtocol {
|
||||||
/// - .SymbolTable: 波浪鍵符號選單專用的狀態,有自身的特殊處理。
|
/// - .SymbolTable: 波浪鍵符號選單專用的狀態,有自身的特殊處理。
|
||||||
public struct IMEState: IMEStateProtocol {
|
public struct IMEState: IMEStateProtocol {
|
||||||
public var type: StateType = .ofEmpty
|
public var type: StateType = .ofEmpty
|
||||||
public var data: StateData = .init()
|
public var data: StateDataProtocol = StateData() as StateDataProtocol
|
||||||
public var node: CandidateNode = .init(name: "")
|
public var node: CandidateNode = .init(name: "")
|
||||||
public var isASCIIMode = false
|
public var isASCIIMode = false
|
||||||
public var isVerticalCandidateWindow = false
|
public var isVerticalCandidateWindow = false
|
||||||
init(_ data: StateData = .init(), type: StateType = .ofEmpty) {
|
init(_ data: StateDataProtocol = StateData() as StateDataProtocol, type: StateType = .ofEmpty) {
|
||||||
self.data = data
|
self.data = data
|
||||||
self.type = type
|
self.type = type
|
||||||
isVerticalTyping = ctlInputMethod.isVerticalTyping
|
isVerticalTyping = ctlInputMethod.isVerticalTyping
|
||||||
}
|
}
|
||||||
|
|
||||||
init(_ data: StateData = .init(), type: StateType = .ofEmpty, node: CandidateNode) {
|
init(_ data: StateDataProtocol = StateData() as StateDataProtocol, type: StateType = .ofEmpty, node: CandidateNode) {
|
||||||
self.data = data
|
self.data = data
|
||||||
self.type = type
|
self.type = type
|
||||||
self.node = node
|
self.node = node
|
||||||
|
@ -108,14 +68,14 @@ extension IMEState {
|
||||||
public static func ofAbortion() -> IMEState { .init(type: .ofAbortion) }
|
public static func ofAbortion() -> IMEState { .init(type: .ofAbortion) }
|
||||||
public static func ofCommitting(textToCommit: String) -> IMEState {
|
public static func ofCommitting(textToCommit: String) -> IMEState {
|
||||||
var result = IMEState(type: .ofCommitting)
|
var result = IMEState(type: .ofCommitting)
|
||||||
result.data.textToCommit = textToCommit
|
result.textToCommit = textToCommit
|
||||||
ChineseConverter.ensureCurrencyNumerals(target: &result.data.textToCommit)
|
ChineseConverter.ensureCurrencyNumerals(target: &result.data.textToCommit)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ofAssociates(candidates: [(String, String)]) -> IMEState {
|
public static func ofAssociates(candidates: [(String, String)]) -> IMEState {
|
||||||
var result = IMEState(type: .ofAssociates)
|
var result = IMEState(type: .ofAssociates)
|
||||||
result.data.candidates = candidates
|
result.candidates = candidates
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,15 +135,24 @@ extension IMEState {
|
||||||
extension IMEState {
|
extension IMEState {
|
||||||
public var isFilterable: Bool { data.isFilterable }
|
public var isFilterable: Bool { data.isFilterable }
|
||||||
public var isMarkedLengthValid: Bool { data.isMarkedLengthValid }
|
public var isMarkedLengthValid: Bool { data.isMarkedLengthValid }
|
||||||
public var candidates: [(String, String)] { data.candidates }
|
|
||||||
public var displayedText: String { data.displayedText }
|
public var displayedText: String { data.displayedText }
|
||||||
public var displayedTextConverted: String { data.displayedTextConverted }
|
public var displayedTextConverted: String { data.displayedTextConverted }
|
||||||
public var cursor: Int { data.cursor }
|
|
||||||
public var displayTextSegments: [String] { data.displayTextSegments }
|
public var displayTextSegments: [String] { data.displayTextSegments }
|
||||||
public var markedRange: Range<Int> { data.markedRange }
|
public var markedRange: Range<Int> { data.markedRange }
|
||||||
public var u16MarkedRange: Range<Int> { data.u16MarkedRange }
|
public var u16MarkedRange: Range<Int> { data.u16MarkedRange }
|
||||||
public var u16Cursor: Int { data.u16Cursor }
|
public var u16Cursor: Int { data.u16Cursor }
|
||||||
public var convertedToInputting: IMEState {
|
|
||||||
|
public var cursor: Int {
|
||||||
|
get { data.cursor }
|
||||||
|
set { data.cursor = newValue }
|
||||||
|
}
|
||||||
|
|
||||||
|
public var marker: Int {
|
||||||
|
get { data.marker }
|
||||||
|
set { data.marker = newValue }
|
||||||
|
}
|
||||||
|
|
||||||
|
public var convertedToInputting: IMEStateProtocol {
|
||||||
if type == .ofInputting { return self }
|
if type == .ofInputting { return self }
|
||||||
var result = IMEState.ofInputting(displayTextSegments: data.displayTextSegments, cursor: data.cursor)
|
var result = IMEState.ofInputting(displayTextSegments: data.displayTextSegments, cursor: data.cursor)
|
||||||
result.tooltip = data.tooltipBackupForInputting
|
result.tooltip = data.tooltipBackupForInputting
|
||||||
|
@ -191,22 +160,19 @@ extension IMEState {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var candidates: [(String, String)] {
|
||||||
|
get { data.candidates }
|
||||||
|
set { data.candidates = newValue }
|
||||||
|
}
|
||||||
|
|
||||||
public var textToCommit: String {
|
public var textToCommit: String {
|
||||||
get {
|
get { data.textToCommit }
|
||||||
data.textToCommit
|
set { data.textToCommit = newValue }
|
||||||
}
|
|
||||||
set {
|
|
||||||
data.textToCommit = newValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var tooltip: String {
|
public var tooltip: String {
|
||||||
get {
|
get { data.tooltip }
|
||||||
data.tooltip
|
set { data.tooltip = newValue }
|
||||||
}
|
|
||||||
set {
|
|
||||||
data.tooltip = newValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var attributedString: NSAttributedString {
|
public var attributedString: NSAttributedString {
|
||||||
|
@ -237,11 +203,7 @@ extension IMEState {
|
||||||
}
|
}
|
||||||
|
|
||||||
public var tooltipBackupForInputting: String {
|
public var tooltipBackupForInputting: String {
|
||||||
get {
|
get { data.tooltipBackupForInputting }
|
||||||
data.tooltipBackupForInputting
|
set { data.tooltipBackupForInputting = newValue }
|
||||||
}
|
|
||||||
set {
|
|
||||||
data.tooltipBackupForInputting = newValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,11 @@
|
||||||
// marks, or product names of Contributor, except as required to fulfill notice
|
// marks, or product names of Contributor, except as required to fulfill notice
|
||||||
// requirements defined in MIT License.
|
// requirements defined in MIT License.
|
||||||
|
|
||||||
|
import Shared
|
||||||
import Tekkon
|
import Tekkon
|
||||||
import TooltipUI
|
import TooltipUI
|
||||||
|
|
||||||
public struct StateData {
|
public struct StateData: StateDataProtocol {
|
||||||
private static var minCandidateLength: Int {
|
private static var minCandidateLength: Int {
|
||||||
PrefMgr.shared.allowBoostingSingleKanjiAsUserPhrase ? 1 : 2
|
PrefMgr.shared.allowBoostingSingleKanjiAsUserPhrase ? 1 : 2
|
||||||
}
|
}
|
||||||
|
@ -18,8 +19,8 @@ public struct StateData {
|
||||||
Self.minCandidateLength...PrefMgr.shared.maxCandidateLength
|
Self.minCandidateLength...PrefMgr.shared.maxCandidateLength
|
||||||
}
|
}
|
||||||
|
|
||||||
var displayedText: String = ""
|
public var displayedText: String = ""
|
||||||
var displayedTextConverted: String {
|
public var displayedTextConverted: String {
|
||||||
/// 先做繁簡轉換
|
/// 先做繁簡轉換
|
||||||
var result = ChineseConverter.kanjiConversionIfRequired(displayedText)
|
var result = ChineseConverter.kanjiConversionIfRequired(displayedText)
|
||||||
if result.utf16.count != displayedText.utf16.count
|
if result.utf16.count != displayedText.utf16.count
|
||||||
|
@ -32,19 +33,19 @@ public struct StateData {
|
||||||
|
|
||||||
// MARK: Cursor & Marker & Range for UTF8
|
// MARK: Cursor & Marker & Range for UTF8
|
||||||
|
|
||||||
var cursor: Int = 0 {
|
public var cursor: Int = 0 {
|
||||||
didSet {
|
didSet {
|
||||||
cursor = min(max(cursor, 0), displayedText.count)
|
cursor = min(max(cursor, 0), displayedText.count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var marker: Int = 0 {
|
public var marker: Int = 0 {
|
||||||
didSet {
|
didSet {
|
||||||
marker = min(max(marker, 0), displayedText.count)
|
marker = min(max(marker, 0), displayedText.count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var markedRange: Range<Int> {
|
public var markedRange: Range<Int> {
|
||||||
min(cursor, marker)..<max(cursor, marker)
|
min(cursor, marker)..<max(cursor, marker)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,58 +54,58 @@ public struct StateData {
|
||||||
/// IMK 協定的內文組字區的游標長度與游標位置無法正確統計 UTF8 高萬字(比如 emoji)的長度,
|
/// IMK 協定的內文組字區的游標長度與游標位置無法正確統計 UTF8 高萬字(比如 emoji)的長度,
|
||||||
/// 所以在這裡必須做糾偏處理。因為在用 Swift,所以可以用「.utf16」取代「NSString.length()」。
|
/// 所以在這裡必須做糾偏處理。因為在用 Swift,所以可以用「.utf16」取代「NSString.length()」。
|
||||||
/// 這樣就可以免除不必要的類型轉換。
|
/// 這樣就可以免除不必要的類型轉換。
|
||||||
var u16Cursor: Int {
|
public var u16Cursor: Int {
|
||||||
displayedText.charComponents[0..<cursor].joined().utf16.count
|
displayedText.charComponents[0..<cursor].joined().utf16.count
|
||||||
}
|
}
|
||||||
|
|
||||||
var u16Marker: Int {
|
public var u16Marker: Int {
|
||||||
displayedText.charComponents[0..<marker].joined().utf16.count
|
displayedText.charComponents[0..<marker].joined().utf16.count
|
||||||
}
|
}
|
||||||
|
|
||||||
var u16MarkedRange: Range<Int> {
|
public var u16MarkedRange: Range<Int> {
|
||||||
min(u16Cursor, u16Marker)..<max(u16Cursor, u16Marker)
|
min(u16Cursor, u16Marker)..<max(u16Cursor, u16Marker)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Other data for non-empty states.
|
// MARK: Other data for non-empty states.
|
||||||
|
|
||||||
var isVerticalTyping = false
|
public var isVerticalTyping = false
|
||||||
var markedTargetExists: Bool {
|
public var markedTargetExists: Bool {
|
||||||
let pair = userPhraseKVPair
|
let pair = userPhraseKVPair
|
||||||
return LMMgr.checkIfUserPhraseExist(
|
return LMMgr.checkIfUserPhraseExist(
|
||||||
userPhrase: pair.1, mode: IMEApp.currentInputMode, key: pair.0
|
userPhrase: pair.1, mode: IMEApp.currentInputMode, key: pair.0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var displayTextSegments = [String]() {
|
public var displayTextSegments = [String]() {
|
||||||
didSet {
|
didSet {
|
||||||
displayedText = displayTextSegments.joined()
|
displayedText = displayTextSegments.joined()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var reading: String = ""
|
public var reading: String = ""
|
||||||
var markedReadings = [String]()
|
public var markedReadings = [String]()
|
||||||
var candidates = [(String, String)]()
|
public var candidates = [(String, String)]()
|
||||||
var textToCommit: String = ""
|
public var textToCommit: String = ""
|
||||||
var tooltip: String = ""
|
public var tooltip: String = ""
|
||||||
var tooltipBackupForInputting: String = ""
|
public var tooltipBackupForInputting: String = ""
|
||||||
var attributedStringPlaceholder: NSAttributedString = .init(
|
public var attributedStringPlaceholder: NSAttributedString = .init(
|
||||||
string: " ",
|
string: " ",
|
||||||
attributes: [
|
attributes: [
|
||||||
.underlineStyle: NSUnderlineStyle.single.rawValue,
|
.underlineStyle: NSUnderlineStyle.single.rawValue,
|
||||||
.markedClauseSegment: 0,
|
.markedClauseSegment: 0,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
var isFilterable: Bool {
|
public var isFilterable: Bool {
|
||||||
markedTargetExists ? isMarkedLengthValid : false
|
markedTargetExists ? isMarkedLengthValid : false
|
||||||
}
|
}
|
||||||
|
|
||||||
var isMarkedLengthValid: Bool {
|
public var isMarkedLengthValid: Bool {
|
||||||
Self.allowedMarkLengthRange.contains(markedRange.count)
|
Self.allowedMarkLengthRange.contains(markedRange.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tooltipColorState: TooltipUI.ColorStates = .normal
|
public var tooltipColorState: TooltipColorState = .normal
|
||||||
|
|
||||||
var attributedStringNormal: NSAttributedString {
|
public var attributedStringNormal: NSAttributedString {
|
||||||
/// 考慮到因為滑鼠點擊等其它行為導致的組字區內容遞交情況,
|
/// 考慮到因為滑鼠點擊等其它行為導致的組字區內容遞交情況,
|
||||||
/// 這裡對組字區內容也加上康熙字轉換或者 JIS 漢字轉換處理。
|
/// 這裡對組字區內容也加上康熙字轉換或者 JIS 漢字轉換處理。
|
||||||
let attributedString = NSMutableAttributedString(string: displayedTextConverted)
|
let attributedString = NSMutableAttributedString(string: displayedTextConverted)
|
||||||
|
@ -122,7 +123,7 @@ public struct StateData {
|
||||||
return attributedString
|
return attributedString
|
||||||
}
|
}
|
||||||
|
|
||||||
var attributedStringMarking: NSAttributedString {
|
public var attributedStringMarking: NSAttributedString {
|
||||||
/// 考慮到因為滑鼠點擊等其它行為導致的組字區內容遞交情況,
|
/// 考慮到因為滑鼠點擊等其它行為導致的組字區內容遞交情況,
|
||||||
/// 這裡對組字區內容也加上康熙字轉換或者 JIS 漢字轉換處理。
|
/// 這裡對組字區內容也加上康熙字轉換或者 JIS 漢字轉換處理。
|
||||||
let attributedString = NSMutableAttributedString(string: displayedTextConverted)
|
let attributedString = NSMutableAttributedString(string: displayedTextConverted)
|
||||||
|
@ -161,7 +162,7 @@ public struct StateData {
|
||||||
// MARK: - IMEState 工具函式
|
// MARK: - IMEState 工具函式
|
||||||
|
|
||||||
extension StateData {
|
extension StateData {
|
||||||
var chkIfUserPhraseExists: Bool {
|
public var doesUserPhraseExist: Bool {
|
||||||
let text = displayedText.charComponents[markedRange].joined()
|
let text = displayedText.charComponents[markedRange].joined()
|
||||||
let joined = markedReadings.joined(separator: "-")
|
let joined = markedReadings.joined(separator: "-")
|
||||||
return LMMgr.checkIfUserPhraseExist(
|
return LMMgr.checkIfUserPhraseExist(
|
||||||
|
@ -169,7 +170,7 @@ extension StateData {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var readingThreadForDisplay: String {
|
public var readingThreadForDisplay: String {
|
||||||
var arrOutput = [String]()
|
var arrOutput = [String]()
|
||||||
for neta in markedReadings {
|
for neta in markedReadings {
|
||||||
var neta = neta
|
var neta = neta
|
||||||
|
@ -193,19 +194,19 @@ extension StateData {
|
||||||
return arrOutput.joined(separator: "\u{A0}")
|
return arrOutput.joined(separator: "\u{A0}")
|
||||||
}
|
}
|
||||||
|
|
||||||
var userPhraseKVPair: (String, String) {
|
public var userPhraseKVPair: (String, String) {
|
||||||
let key = markedReadings.joined(separator: "-")
|
let key = markedReadings.joined(separator: "-")
|
||||||
let value = displayedText.charComponents[markedRange].joined()
|
let value = displayedText.charComponents[markedRange].joined()
|
||||||
return (key, value)
|
return (key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
var userPhraseDumped: String {
|
public var userPhraseDumped: String {
|
||||||
let pair = userPhraseKVPair
|
let pair = userPhraseKVPair
|
||||||
let nerfedScore = ctlInputMethod.areWeNerfing && markedTargetExists ? " -114.514" : ""
|
let nerfedScore = ctlInputMethod.areWeNerfing && markedTargetExists ? " -114.514" : ""
|
||||||
return "\(pair.1) \(pair.0)\(nerfedScore)"
|
return "\(pair.1) \(pair.0)\(nerfedScore)"
|
||||||
}
|
}
|
||||||
|
|
||||||
var userPhraseDumpedConverted: String {
|
public var userPhraseDumpedConverted: String {
|
||||||
let pair = userPhraseKVPair
|
let pair = userPhraseKVPair
|
||||||
let text = ChineseConverter.crossConvert(pair.1) ?? ""
|
let text = ChineseConverter.crossConvert(pair.1) ?? ""
|
||||||
let nerfedScore = ctlInputMethod.areWeNerfing && markedTargetExists ? " -114.514" : ""
|
let nerfedScore = ctlInputMethod.areWeNerfing && markedTargetExists ? " -114.514" : ""
|
||||||
|
@ -213,7 +214,7 @@ extension StateData {
|
||||||
return "\(text) \(pair.0)\(nerfedScore)\t\(convertedMark)"
|
return "\(text) \(pair.0)\(nerfedScore)\t\(convertedMark)"
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func updateTooltipForMarking() {
|
public mutating func updateTooltipForMarking() {
|
||||||
var tooltipForMarking: String {
|
var tooltipForMarking: String {
|
||||||
let pair = userPhraseKVPair
|
let pair = userPhraseKVPair
|
||||||
if PrefMgr.shared.phraseReplacementEnabled {
|
if PrefMgr.shared.phraseReplacementEnabled {
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
// marks, or product names of Contributor, except as required to fulfill notice
|
// marks, or product names of Contributor, except as required to fulfill notice
|
||||||
// requirements defined in MIT License.
|
// requirements defined in MIT License.
|
||||||
|
|
||||||
|
import Shared
|
||||||
|
|
||||||
public class ctlPopupCompositionBuffer: NSWindowController {
|
public class ctlPopupCompositionBuffer: NSWindowController {
|
||||||
public var isTypingDirectionVertical = false {
|
public var isTypingDirectionVertical = false {
|
||||||
didSet {
|
didSet {
|
||||||
|
|
|
@ -32,7 +32,7 @@ extension ctlInputMethod: KeyHandlerDelegate {
|
||||||
(inputMode == .imeModeCHT) ? .imeModeCHS : .imeModeCHT
|
(inputMode == .imeModeCHT) ? .imeModeCHS : .imeModeCHT
|
||||||
if !LMMgr.writeUserPhrase(
|
if !LMMgr.writeUserPhrase(
|
||||||
state.data.userPhraseDumped, inputMode: inputMode,
|
state.data.userPhraseDumped, inputMode: inputMode,
|
||||||
areWeDuplicating: state.data.chkIfUserPhraseExists,
|
areWeDuplicating: state.data.doesUserPhraseExist,
|
||||||
areWeDeleting: addToFilter
|
areWeDeleting: addToFilter
|
||||||
)
|
)
|
||||||
|| !LMMgr.writeUserPhrase(
|
|| !LMMgr.writeUserPhrase(
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
// marks, or product names of Contributor, except as required to fulfill notice
|
// marks, or product names of Contributor, except as required to fulfill notice
|
||||||
// requirements defined in MIT License.
|
// requirements defined in MIT License.
|
||||||
|
|
||||||
|
import Shared
|
||||||
|
|
||||||
// MARK: - 狀態調度 (State Handling)
|
// MARK: - 狀態調度 (State Handling)
|
||||||
|
|
||||||
extension ctlInputMethod {
|
extension ctlInputMethod {
|
||||||
|
|
Loading…
Reference in New Issue