!35 1.6.0 // Bug fixes. Merge Gitee PR!35 from upd/1.6.0

This commit is contained in:
ShikiSuen 2022-05-21 10:02:58 +00:00 committed by Gitee
commit 96453d0478
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
40 changed files with 842 additions and 654 deletions

View File

@ -2,12 +2,11 @@
威注音輸入法歡迎有熱心的志願者們參與。
威注音目前的 codebase 更能代表一個先進的 macOS 輸入法雛形專案的形態。目前的 dev 分支除了 Mandarin 模組(以及其與 KeyHandler 的對接的部分)以外被威注音使用的部分全都是清一色的 Swift codebase一目了然方便他人參與比某些其它開源品牌旗下的專案更具程式方面的生命力。為什麼這樣講呢那些傳統開源品牌的專案主要使用 C++ 這門不太友好的語言Mandarin 模組現在對我而言仍舊是天書,一大堆針對記憶體指針的操作完全看不懂。搞不清楚在這一層之上的功能邏輯的話,就無法制定 Swift 版的 coding 策略),這也是我這次用 Swift 重寫了語言模型引擎的原因(也是為後來者行方便)。
威注音目前的 codebase 更能代表一個先進的 macOS 輸入法雛形專案的形態。目前的 dev 分支除了第三方 OpenCC 模組以外被威注音使用的部分全都是清一色的 Swift codebase一目了然方便他人參與比某些其它開源品牌旗下的專案更具程式方面的生命力。為什麼這樣講呢那些傳統開源品牌的專案主要使用 C++ 這門不太友好的語言Mandarin 模組現在對我而言仍舊是天書,一大堆針對記憶體指針的操作完全看不懂。搞不清楚在這一層之上的功能邏輯的話,就無法制定 Swift 版的 coding 策略),這也是我這次用 Swift 重寫了語言模型引擎與注音拼音並擊處理引擎、來換掉 Gramambular 與 OVMandarin 的原因(也是為後來者行方便)。
為了不讓參與者們浪費各自的熱情,特設此文以說明該專案目前最需要協助的地方。
1. 讓 Alt+波浪鍵選單能夠在諸如 MS Word 以及終端機內正常工作(可以用方向鍵控制高亮候選內容,等)。
- 原理上而言恐怕得欺騙當前正在接受輸入的應用、使其誤以為當前有組字區。這只是推測。
1. 將選字窗換成 IMK 內建的矩陣選字窗。
除了上述各項以外的貢獻,除非特邀、或者有足夠的說服理由與吸引力(比如語法錯誤或更好的重構方法等),否則敝專案可能會無視或者拒絕。

View File

@ -7,6 +7,8 @@
威注音輸入法基於小麥注音二次開發,是**原生簡體中文、原生繁體中文注音輸入法**
- 威注音是業界現階段支援注音排列種類數量與輸入用拼音種類數量最多的注音輸入法。
- 受威注音自家的鐵恨注音並擊引擎加持。
- 威注音的原廠詞庫內不存在任何可以妨礙該輸入法在世界上任何地方傳播的內容。
- 相比中州韻(鼠須管)而言,威注音能夠做到真正的大千聲韻並擊。
@ -14,7 +16,7 @@
>- 支援 macOS 螢幕模擬鍵盤(僅傳統大千與傳統倚天佈局)。
>- 可以將自己打的繁體中文自動轉成日本 JIS 新字體來輸出(包括基礎的字詞轉換)、也可以轉成康熙繁體來輸出。
>- 簡繁體中文語料庫彼此分離,徹底杜絕任何繁簡轉換過程可能造成的失誤。
>- 支援最新的全字型檔漢字輸入。
>- 支援近年的全字庫漢字輸入。
>- 可以自動整理使用者語彙檔案格式、自訂聯想詞。
>- ……
@ -96,8 +98,14 @@
請洽該倉庫內的「[CONTRIBUTING.md](./CONTRIBUTING.md)」檔案。
## 特殊勸告
## 其他
為了您的精神衛生,任何使用威注音輸入法時遇到的產品問題、請勿提報至小麥注音,除非您確信小麥注音也有該問題。即便如此,也請在他們那邊不要提及威注音。
濫用沉默權來浪費對方的時間與熱情,也是一種暴力。
濫用沉默權來浪費對方的時間與熱情,也是一種暴力。**當對方最最最開始就把你當敵人的時候,你連呼吸都是錯的**。
其實我滿懷念上游專案還沒被 Lukhnos Liu 接管收入 OpenVanilla 的那個年代。MJHsieh 主導開發小麥注音的時候且不討論他立場怎樣但基礎的技術交流是完全沒問題的。LibChewing 那邊也是,正常交流完全沒問題。
有些事情,繼續爭論下去也沒用。本來我想著重寫 ctlInputMethod 撤掉 zonble 的狀態管理引擎的,畢竟有大陸同鄉寫的火山五筆輸入法的框架套上我的鐵恨注音並擊引擎可以直接用。但這樣賭氣對誰都沒好處。眼下,威注音 macOS 版還需要一些小維護。之後我就得開始考慮用 Rust 重寫鐵恨注音並擊引擎與天權星語彙引擎、方便接下來威注音的 Windows 版本的研發。能將 Lukhnos 的 C++ 內容全部換掉、徹底砸碎套在威注音身上的名為 C++ 的枷鎖、讓威注音有一個自由的未來,我已經知足了。讓更多的人用上好用的輸入法,才是最重要的。**這個重要性,不是 zonble 用「私人需求」這種帽子扣過來、就可以泯滅了的**。
$ EOF.

@ -1 +1 @@
Subproject commit 4e5f1dc11a9b477b7907f5e59594e636a8830ce8
Subproject commit 6c4d659d148ef5be3255427bfd4429fa8690631d

View File

@ -105,11 +105,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega
NSApp.setActivationPolicy(.accessory)
}
func checkForUpdate() {
checkForUpdate(forced: false)
}
func checkForUpdate(forced: Bool) {
func checkForUpdate(forced: Bool = false) {
if checkTask != nil {
// busy
return

View File

@ -117,7 +117,7 @@ enum CharCode: UInt /* 16 */ {
// ... but only focuses on which physical key is pressed.
}
class InputHandler: NSObject {
struct InputSignal: CustomStringConvertible {
private(set) var useVerticalMode: Bool
private(set) var inputText: String?
private(set) var inputTextIgnoringModifiers: String?
@ -125,15 +125,15 @@ class InputHandler: NSObject {
private(set) var keyCode: UInt16
private var isFlagChanged: Bool
private var flags: NSEvent.ModifierFlags
private var cursorForwardKey: KeyCode
private var cursorBackwardKey: KeyCode
private var extraChooseCandidateKey: KeyCode
private var extraChooseCandidateKeyReverse: KeyCode
private var absorbedArrowKey: KeyCode
private var verticalModeOnlyChooseCandidateKey: KeyCode
private var cursorForwardKey: KeyCode = .kNone
private var cursorBackwardKey: KeyCode = .kNone
private var extraChooseCandidateKey: KeyCode = .kNone
private var extraChooseCandidateKeyReverse: KeyCode = .kNone
private var absorbedArrowKey: KeyCode = .kNone
private var verticalModeOnlyChooseCandidateKey: KeyCode = .kNone
private(set) var emacsKey: vChewingEmacsKey
init(
public init(
inputText: String?, keyCode: UInt16, charCode: UInt16, flags: NSEvent.ModifierFlags,
isVerticalMode: Bool, inputTextIgnoringModifiers: String? = nil
) {
@ -150,17 +150,11 @@ class InputHandler: NSObject {
emacsKey = EmacsKeyHelper.detect(
charCode: AppleKeyboardConverter.cnvApple2ABC(charCode), flags: flags
)
// Define Arrow Keys
cursorForwardKey = useVerticalMode ? .kDownArrow : .kRightArrow
cursorBackwardKey = useVerticalMode ? .kUpArrow : .kLeftArrow
extraChooseCandidateKey = useVerticalMode ? .kLeftArrow : .kDownArrow
extraChooseCandidateKeyReverse = useVerticalMode ? .kRightArrow : .kUpArrow
absorbedArrowKey = useVerticalMode ? .kRightArrow : .kUpArrow
verticalModeOnlyChooseCandidateKey = useVerticalMode ? absorbedArrowKey : .kNone
super.init()
// Define Arrow Keys in the same way above.
defineArrowKeys()
}
init(event: NSEvent, isVerticalMode: Bool) {
public init(event: NSEvent, isVerticalMode: Bool) {
inputText = AppleKeyboardConverter.cnvStringApple2ABC(event.characters ?? "")
inputTextIgnoringModifiers = AppleKeyboardConverter.cnvStringApple2ABC(
event.charactersIgnoringModifiers ?? "")
@ -181,22 +175,20 @@ class InputHandler: NSObject {
charCode: AppleKeyboardConverter.cnvApple2ABC(charCode), flags: flags
)
// Define Arrow Keys in the same way above.
defineArrowKeys()
}
mutating func defineArrowKeys() {
cursorForwardKey = useVerticalMode ? .kDownArrow : .kRightArrow
cursorBackwardKey = useVerticalMode ? .kUpArrow : .kLeftArrow
extraChooseCandidateKey = useVerticalMode ? .kLeftArrow : .kDownArrow
extraChooseCandidateKeyReverse = useVerticalMode ? .kRightArrow : .kUpArrow
absorbedArrowKey = useVerticalMode ? .kRightArrow : .kUpArrow
verticalModeOnlyChooseCandidateKey = useVerticalMode ? absorbedArrowKey : .kNone
super.init()
}
override var description: String {
charCode = AppleKeyboardConverter.cnvApple2ABC(charCode)
inputText = AppleKeyboardConverter.cnvStringApple2ABC(inputText ?? "")
inputTextIgnoringModifiers = AppleKeyboardConverter.cnvStringApple2ABC(
inputTextIgnoringModifiers ?? "")
return
"<\(super.description) inputText:\(String(describing: inputText)), inputTextIgnoringModifiers:\(String(describing: inputTextIgnoringModifiers)) charCode:\(charCode), keyCode:\(keyCode), flags:\(flags), cursorForwardKey:\(cursorForwardKey), cursorBackwardKey:\(cursorBackwardKey), extraChooseCandidateKey:\(extraChooseCandidateKey), extraChooseCandidateKeyReverse:\(extraChooseCandidateKeyReverse), absorbedArrowKey:\(absorbedArrowKey), verticalModeOnlyChooseCandidateKey:\(verticalModeOnlyChooseCandidateKey), emacsKey:\(emacsKey), useVerticalMode:\(useVerticalMode)>"
var description: String {
"<inputText:\(String(describing: inputText)), inputTextIgnoringModifiers:\(String(describing: inputTextIgnoringModifiers)) charCode:\(charCode), keyCode:\(keyCode), flags:\(flags), cursorForwardKey:\(cursorForwardKey), cursorBackwardKey:\(cursorBackwardKey), extraChooseCandidateKey:\(extraChooseCandidateKey), extraChooseCandidateKeyReverse:\(extraChooseCandidateKeyReverse), absorbedArrowKey:\(absorbedArrowKey), verticalModeOnlyChooseCandidateKey:\(verticalModeOnlyChooseCandidateKey), emacsKey:\(emacsKey), useVerticalMode:\(useVerticalMode)>"
}
// ANSI charCode Swift KeyHandler
@ -365,7 +357,7 @@ enum vChewingEmacsKey: UInt16 {
case nextPage = 22 // V
}
class EmacsKeyHelper: NSObject {
enum EmacsKeyHelper {
static func detect(charCode: UniChar, flags: NSEvent.ModifierFlags) -> vChewingEmacsKey {
let charCode = AppleKeyboardConverter.cnvApple2ABC(charCode)
if flags.contains(.control) {

View File

@ -26,6 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import Cocoa
// InputState 使 Struct Struct
/// Represents the states for the input method controller.
///
/// An input method is actually a finite state machine. It receives the inputs
@ -44,10 +46,10 @@ import Cocoa
/// create a new state object to replace the current state instead of modifying
/// the existing one.
///
/// vChewing's input controller has following possible states:
/// The input controller has following possible states:
///
/// - Deactivated: The user is not using vChewing yet.
/// - Empty: The user has switched to vChewing but did not input anything yet,
/// - Deactivated: The user is not using the input method yet.
/// - Empty: The user has switched to this input method but inputted nothing yet,
/// or, he or she has committed text into the client apps and starts a new
/// input phase.
/// - Committing: The input controller is sending text to the client apps.
@ -136,14 +138,14 @@ class InputState {
}
var attributedString: NSAttributedString {
let attributedSting = NSAttributedString(
let attributedString = NSAttributedString(
string: composingBuffer,
attributes: [
.underlineStyle: NSUnderlineStyle.single.rawValue,
.markedClauseSegment: 0,
]
)
return attributedSting
return attributedString
}
override var description: String {
@ -257,22 +259,22 @@ class InputState {
}
var attributedString: NSAttributedString {
let attributedSting = NSMutableAttributedString(string: composingBuffer)
let attributedString = NSMutableAttributedString(string: composingBuffer)
let end = markedRange.location + markedRange.length
attributedSting.setAttributes(
attributedString.setAttributes(
[
.underlineStyle: NSUnderlineStyle.single.rawValue,
.markedClauseSegment: 0,
], range: NSRange(location: 0, length: markedRange.location)
)
attributedSting.setAttributes(
attributedString.setAttributes(
[
.underlineStyle: NSUnderlineStyle.thick.rawValue,
.markedClauseSegment: 1,
], range: markedRange
)
attributedSting.setAttributes(
attributedString.setAttributes(
[
.underlineStyle: NSUnderlineStyle.single.rawValue,
.markedClauseSegment: 2,
@ -282,21 +284,21 @@ class InputState {
length: (composingBuffer as NSString).length - end
)
)
return attributedSting
return attributedString
}
override var description: String {
"<InputState.Marking, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex), markedRange:\(markedRange)>"
}
func convertToInputting() -> Inputting {
var convertedToInputting: Inputting {
let state = Inputting(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
state.tooltip = tooltipForInputting
return state
}
var validToWrite: Bool {
/// vChewing allows users to input a string whose length differs
/// The input method allows users to input a string whose length differs
/// from the amount of Bopomofo readings. In this case, the range
/// in the composing buffer and the readings could not match, so
/// we disable the function to write user phrases in this case.
@ -370,14 +372,14 @@ class InputState {
}
var attributedString: NSAttributedString {
let attributedSting = NSAttributedString(
let attributedString = NSAttributedString(
string: composingBuffer,
attributes: [
.underlineStyle: NSUnderlineStyle.single.rawValue,
.markedClauseSegment: 0,
]
)
return attributedSting
return attributedString
}
override var description: String {
@ -415,6 +417,22 @@ class InputState {
)
}
// InputState.SymbolTable
// MS Word
//
//
// Crediting Qwertyyb: https://github.com/qwertyyb/Fire/issues/55#issuecomment-1133497700
override var attributedString: NSAttributedString {
let attributedString = NSAttributedString(
string: " ",
attributes: [
.underlineStyle: NSUnderlineStyle.single.rawValue,
.markedClauseSegment: 0,
]
)
return attributedString
}
override var description: String {
"<InputState.SymbolTable, candidates:\(candidates), useVerticalMode:\(useVerticalMode), composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
}

View File

@ -68,13 +68,35 @@ class KeyHandler {
return InputMode.imeModeNULL
}
}
set { setInputMode(newValue.rawValue) }
set {
let isCHS: Bool = (newValue == InputMode.imeModeCHS)
// ctlInputMethod:
ctlInputMethod.currentInputMode = isCHS ? InputMode.imeModeCHS.rawValue : InputMode.imeModeCHT.rawValue
mgrPrefs.mostRecentInputMode = ctlInputMethod.currentInputMode
// _inputMode ctlInputMethod
if _inputMode != ctlInputMethod.currentInputMode {
// Reinitiate language models if necessary
_languageModel = isCHS ? mgrLangModel.lmCHS : mgrLangModel.lmCHT
_userOverrideModel = isCHS ? mgrLangModel.uomCHS : mgrLangModel.uomCHT
// Synchronize the sub-languageModel state settings to the new LM.
syncBaseLMPrefs()
// Create new grid builder and clear the composer.
createNewBuilder()
_composer.clear()
}
//
_inputMode = ctlInputMethod.currentInputMode
}
}
public init() {
_builder = Megrez.BlockReadingBuilder(lm: _languageModel)
_builder = Megrez.BlockReadingBuilder(lm: _languageModel, separator: "-")
ensureParser()
setInputMode(ctlInputMethod.currentInputMode)
inputMode = InputMode(rawValue: ctlInputMethod.currentInputMode) ?? InputMode.imeModeNULL
}
func clear() {
@ -83,34 +105,6 @@ class KeyHandler {
_walkedNodes.removeAll()
}
func setInputMode(_ value: String) {
// isKindOfClass
// plist
let isCHS: Bool = (value == InputMode.imeModeCHS.rawValue)
// ctlInputMethod:
ctlInputMethod.currentInputMode = isCHS ? InputMode.imeModeCHS.rawValue : InputMode.imeModeCHT.rawValue
mgrPrefs.mostRecentInputMode = ctlInputMethod.currentInputMode
// _inputMode ctlInputMethod
if _inputMode != ctlInputMethod.currentInputMode {
// Reinitiate language models if necessary
setInputModesToLM(isCHS: isCHS)
// Synchronize the sub-languageModel state settings to the new LM.
syncBaseLMPrefs()
// Create new grid builder.
createNewBuilder()
if !_composer.isEmpty {
_composer.clear()
}
}
//
_inputMode = ctlInputMethod.currentInputMode
}
// MARK: - Functions dealing with Megrez.
func walk() {
@ -118,12 +112,10 @@ class KeyHandler {
// of the best possible Mandarin characters given the input syllables,
// using the Viterbi algorithm implemented in the Megrez library.
// The walk() traces the grid to the end, hence no need to use .reversed() here.
_walkedNodes = Megrez.Walker(
grid: _builder.grid()
).walk(at: _builder.grid().width(), nodesLimit: 3, balanced: true)
_walkedNodes = _builder.walk(at: _builder.grid.width, nodesLimit: 10, balanced: true)
}
func popOverflowComposingTextAndWalk() -> String {
var popOverflowComposingTextAndWalk: String {
// In ideal situations we can allow users to type infinitely in a buffer.
// However, Viberti algorithm has a complexity of O(N^2), the walk will
// become slower as the number of nodes increase. Therefore, we need to
@ -133,11 +125,11 @@ class KeyHandler {
// (i.e. popped out.)
var poppedText = ""
if _builder.grid().width() > mgrPrefs.composingBufferSize {
if _builder.grid.width > mgrPrefs.composingBufferSize {
if _walkedNodes.count > 0 {
let anchor: Megrez.NodeAnchor = _walkedNodes[0]
if let theNode = anchor.node {
poppedText = theNode.currentKeyValue().value
poppedText = theNode.currentKeyValue.value
}
_builder.removeHeadReadings(count: anchor.spanningLength)
}
@ -155,8 +147,8 @@ class KeyHandler {
}
func fixNode(value: String) {
let cursorIndex: Int = getActualCandidateCursorIndex()
let selectedNode: Megrez.NodeAnchor = _builder.grid().fixNodeSelectedCandidate(
let cursorIndex: Int = actualCandidateCursorIndex
let selectedNode: Megrez.NodeAnchor = _builder.grid.fixNodeSelectedCandidate(
location: cursorIndex, value: value
)
//
@ -194,16 +186,16 @@ class KeyHandler {
if nextPosition >= cursorIndex { break }
nextPosition += node.spanningLength
}
if nextPosition <= getBuilderLength() {
setBuilderCursorIndex(value: nextPosition)
if nextPosition <= builderLength {
builderCursorIndex = nextPosition
}
}
}
func getCandidatesArray() -> [String] {
var candidatesArray: [String] {
var arrCandidates: [String] = []
var arrNodes: [Megrez.NodeAnchor] = []
arrNodes.append(contentsOf: getRawNodes())
arrNodes.append(contentsOf: rawNodes)
/// nodes
///
@ -216,7 +208,7 @@ class KeyHandler {
// then use the Swift trick to retrieve the candidates for each node at/crossing the cursor
for currentNodeAnchor in arrNodes {
if let currentNode = currentNodeAnchor.node {
for currentCandidate in currentNode.candidates() {
for currentCandidate in currentNode.candidates {
arrCandidates.append(currentCandidate.value)
}
}
@ -230,17 +222,17 @@ class KeyHandler {
mgrPrefs.useSCPCTypingMode
? ""
: _userOverrideModel.suggest(
walkedNodes: _walkedNodes, cursorIndex: getBuilderCursorIndex(),
walkedNodes: _walkedNodes, cursorIndex: builderCursorIndex,
timestamp: NSDate().timeIntervalSince1970
)
if !overrideValue.isEmpty {
IME.prtDebugIntel(
"UOM: Suggestion retrieved, overriding the node score of the selected candidate.")
_builder.grid().overrideNodeScoreForSelectedCandidate(
location: getActualCandidateCursorIndex(),
_builder.grid.overrideNodeScoreForSelectedCandidate(
location: actualCandidateCursorIndex,
value: overrideValue,
overridingScore: findHighestScore(nodes: getRawNodes(), epsilon: kEpsilon)
overridingScore: findHighestScore(nodes: rawNodes, epsilon: kEpsilon)
)
} else {
IME.prtDebugIntel("UOM: Blank suggestion retrieved, dismissing.")
@ -251,7 +243,7 @@ class KeyHandler {
var highestScore: Double = 0
for currentAnchor in nodes {
if let theNode = currentAnchor.node {
let score = theNode.highestUnigramScore()
let score = theNode.highestUnigramScore
if score > highestScore {
highestScore = score
}
@ -260,70 +252,6 @@ class KeyHandler {
return highestScore + epsilon
}
// MARK: - Extracted methods and functions (Megrez).
func isBuilderEmpty() -> Bool { _builder.grid().width() == 0 }
func getRawNodes() -> [Megrez.NodeAnchor] {
/// 使 nodesCrossing macOS
/// nodeCrossing Megrez
/// Windows
mgrPrefs.setRearCursorMode
? _builder.grid().nodesCrossingOrEndingAt(location: getActualCandidateCursorIndex())
: _builder.grid().nodesEndingAt(location: getActualCandidateCursorIndex())
}
func setInputModesToLM(isCHS: Bool) {
_languageModel = isCHS ? mgrLangModel.lmCHS : mgrLangModel.lmCHT
_userOverrideModel = isCHS ? mgrLangModel.uomCHS : mgrLangModel.uomCHT
}
func syncBaseLMPrefs() {
_languageModel.isPhraseReplacementEnabled = mgrPrefs.phraseReplacementEnabled
_languageModel.isCNSEnabled = mgrPrefs.cns11643Enabled
_languageModel.isSymbolEnabled = mgrPrefs.symbolInputEnabled
}
func createNewBuilder() {
_builder = Megrez.BlockReadingBuilder(lm: _languageModel)
// Each Mandarin syllable is separated by a hyphen.
_builder.setJoinSeparator(separator: "-")
}
func currentReadings() -> [String] { _builder.readings() }
func ifLangModelHasUnigrams(forKey reading: String) -> Bool {
_languageModel.hasUnigramsFor(key: reading)
}
func insertReadingToBuilderAtCursor(reading: String) {
_builder.insertReadingAtCursor(reading: reading)
}
func setBuilderCursorIndex(value: Int) {
_builder.setCursorIndex(newIndex: value)
}
func getBuilderCursorIndex() -> Int {
_builder.cursorIndex()
}
func getBuilderLength() -> Int {
_builder.length()
}
func deleteBuilderReadingInFrontOfCursor() {
_builder.deleteReadingAtTheRearOfCursor()
}
func deleteBuilderReadingToTheFrontOfCursor() {
_builder.deleteReadingToTheFrontOfCursor()
}
func getKeyLengthAtIndexZero() -> Int {
_walkedNodes[0].node?.currentKeyValue().value.count ?? 0
}
// MARK: - Extracted methods and functions (Tekkon).
func ensureParser() {
@ -360,4 +288,59 @@ class KeyHandler {
}
_composer.clear()
}
// MARK: - Extracted methods and functions (Megrez).
var isBuilderEmpty: Bool { _builder.grid.width == 0 }
var rawNodes: [Megrez.NodeAnchor] {
/// 使 nodesCrossing macOS
/// nodeCrossing Megrez
/// Windows
mgrPrefs.setRearCursorMode
? _builder.grid.nodesCrossingOrEndingAt(location: actualCandidateCursorIndex)
: _builder.grid.nodesEndingAt(location: actualCandidateCursorIndex)
}
func syncBaseLMPrefs() {
_languageModel.isPhraseReplacementEnabled = mgrPrefs.phraseReplacementEnabled
_languageModel.isCNSEnabled = mgrPrefs.cns11643Enabled
_languageModel.isSymbolEnabled = mgrPrefs.symbolInputEnabled
}
func createNewBuilder() {
// Each Mandarin syllable is separated by a hyphen.
_builder = Megrez.BlockReadingBuilder(lm: _languageModel, separator: "-")
}
var currentReadings: [String] { _builder.readings }
func ifLangModelHasUnigrams(forKey reading: String) -> Bool {
_languageModel.hasUnigramsFor(key: reading)
}
func insertReadingToBuilderAtCursor(reading: String) {
_builder.insertReadingAtCursor(reading: reading)
}
var builderCursorIndex: Int {
get { _builder.cursorIndex }
set { _builder.cursorIndex = newValue }
}
var builderLength: Int {
_builder.length
}
func deleteBuilderReadingInFrontOfCursor() {
_builder.deleteReadingAtTheRearOfCursor()
}
func deleteBuilderReadingToTheFrontOfCursor() {
_builder.deleteReadingToTheFrontOfCursor()
}
var keyLengthAtIndexZero: Int {
_walkedNodes[0].node?.currentKeyValue.value.count ?? 0
}
}

View File

@ -31,7 +31,7 @@ import Cocoa
extension KeyHandler {
func handleCandidate(
state: InputState,
input: InputHandler,
input: InputSignal,
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
@ -47,16 +47,16 @@ extension KeyHandler {
if cancelCandidateKey {
if (state is InputState.AssociatedPhrases)
|| mgrPrefs.useSCPCTypingMode
|| isBuilderEmpty()
|| isBuilderEmpty
{
//
//
// 使 BackSpace
// isBuilderEmpty()
// isBuilderEmpty
clear()
stateCallback(InputState.EmptyIgnoringPreviousState())
} else {
stateCallback(buildInputtingState())
stateCallback(buildInputtingState)
}
return true
}
@ -320,7 +320,7 @@ extension KeyHandler {
punctuationNamePrefix = "_punctuation_"
}
let parser = getCurrentMandarinParser()
let parser = currentMandarinParser
let arrCustomPunctuations: [String] = [
punctuationNamePrefix, parser, String(format: "%c", CChar(charCode)),

View File

@ -30,7 +30,7 @@ import Cocoa
extension KeyHandler {
func handle(
input: InputHandler,
input: InputSignal,
state: InputState,
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
@ -135,7 +135,7 @@ extension KeyHandler {
) {
return true
}
state = marking.convertToInputting()
state = marking.convertedToInputting
stateCallback(state)
}
@ -154,7 +154,7 @@ extension KeyHandler {
// update the composing buffer.
let composeReading = _composer.hasToneMarker()
if !composeReading {
stateCallback(buildInputtingState())
stateCallback(buildInputtingState)
return true
}
}
@ -166,7 +166,7 @@ extension KeyHandler {
// However, Swift does not support "|=".
composeReading = composeReading || (!_composer.isEmpty && (input.isSpace || input.isEnter))
if composeReading {
if input.isSpace && !_composer.hasToneMarker() {
if input.isSpace, !_composer.hasToneMarker() {
_composer.receiveKey(fromString: " ") //
}
let reading = _composer.getComposition()
@ -176,7 +176,7 @@ extension KeyHandler {
IME.prtDebugIntel("B49C0979語彙庫內無「\(reading)」的匹配記錄。")
errorCallback()
_composer.clear()
stateCallback((getBuilderLength() == 0) ? InputState.EmptyIgnoringPreviousState() : buildInputtingState())
stateCallback((builderLength == 0) ? InputState.EmptyIgnoringPreviousState() : buildInputtingState)
return true
}
@ -184,7 +184,7 @@ extension KeyHandler {
insertReadingToBuilderAtCursor(reading: reading)
// ... then walk the grid...
let poppedText = popOverflowComposingTextAndWalk()
let poppedText = popOverflowComposingTextAndWalk
// ... get and tweak override model suggestion if possible...
dealWithOverrideModelSuggestions()
@ -192,7 +192,7 @@ extension KeyHandler {
// ... then update the text.
_composer.clear()
let inputting = buildInputtingState()
let inputting = buildInputtingState
inputting.poppedText = poppedText
stateCallback(inputting)
@ -233,7 +233,7 @@ extension KeyHandler {
// but does not compose. Only sequences such as "ˊ", "ˊˊ", "ˊˇ", or "ˊ "
// would compose.
if keyConsumedByReading {
stateCallback(buildInputtingState())
stateCallback(buildInputtingState)
return true
}
@ -247,7 +247,7 @@ extension KeyHandler {
if input.isSpace {
// If the Space key is NOT set to be a selection key
if input.isShiftHold || !mgrPrefs.chooseCandidateUsingSpace {
if getBuilderCursorIndex() >= getBuilderLength() {
if builderCursorIndex >= builderLength {
let composingBuffer = currentState.composingBuffer
if !composingBuffer.isEmpty {
stateCallback(InputState.Committing(poppedText: composingBuffer))
@ -257,8 +257,8 @@ extension KeyHandler {
stateCallback(InputState.Empty())
} else if ifLangModelHasUnigrams(forKey: " ") {
insertReadingToBuilderAtCursor(reading: " ")
let poppedText = popOverflowComposingTextAndWalk()
let inputting = buildInputtingState()
let poppedText = popOverflowComposingTextAndWalk
let inputting = buildInputtingState
inputting.poppedText = poppedText
stateCallback(inputting)
}
@ -351,12 +351,12 @@ extension KeyHandler {
// MARK: Punctuation list
if input.isSymbolMenuPhysicalKey && !input.isShiftHold {
if !input.isOptionHold {
if input.isOptionHold {
if ifLangModelHasUnigrams(forKey: "_punctuation_list") {
if _composer.isEmpty {
insertReadingToBuilderAtCursor(reading: "_punctuation_list")
let poppedText: String! = popOverflowComposingTextAndWalk()
let inputting = buildInputtingState()
let poppedText: String! = popOverflowComposingTextAndWalk
let inputting = buildInputtingState
inputting.poppedText = poppedText
stateCallback(inputting)
stateCallback(buildCandidate(state: inputting, useVerticalMode: input.useVerticalMode))
@ -392,7 +392,7 @@ extension KeyHandler {
punctuationNamePrefix = "_punctuation_"
}
let parser = getCurrentMandarinParser()
let parser = currentMandarinParser
let arrCustomPunctuations: [String] = [
punctuationNamePrefix, parser, String(format: "%c", CChar(charCode)),
]

View File

@ -29,22 +29,22 @@ import Cocoa
// MARK: - § Misc functions.
extension KeyHandler {
func getCurrentMandarinParser() -> String {
var currentMandarinParser: String {
mgrPrefs.mandarinParserName + "_"
}
func getActualCandidateCursorIndex() -> Int {
var cursorIndex = getBuilderCursorIndex()
var actualCandidateCursorIndex: Int {
var cursorIndex = builderCursorIndex
// Windows Yahoo Kimo IME style, phrase is *at the rear of* the cursor.
// (i.e. the cursor is always *before* the phrase.)
// This is different from MS Phonetics IME style ...
// ... since Windows Yahoo Kimo allows "node crossing".
if (mgrPrefs.setRearCursorMode
&& (cursorIndex < getBuilderLength()))
&& (cursorIndex < builderLength))
|| cursorIndex == 0
{
if cursorIndex == 0, !mgrPrefs.setRearCursorMode {
cursorIndex += getKeyLengthAtIndexZero()
cursorIndex += keyLengthAtIndexZero
} else {
cursorIndex += 1
}

View File

@ -31,42 +31,47 @@ import Cocoa
extension KeyHandler {
// MARK: - State Building
func buildInputtingState() -> InputState.Inputting {
var buildInputtingState: InputState.Inputting {
// "Updating the composing buffer" means to request the client
// to "refresh" the text input buffer with our "composing text"
var composingBuffer = ""
var composedStringCursorIndex = 0
var readingCursorIndex = 0
let builderCursorIndex = getBuilderCursorIndex()
for theAnchor in _walkedNodes {
guard let node = theAnchor.node else {
continue
}
let valueString = node.currentKeyValue().value
composingBuffer += valueString
let codepointCount = valueString.count
let spanningLength = theAnchor.spanningLength
if readingCursorIndex + spanningLength <= builderCursorIndex {
composedStringCursorIndex += valueString.count
readingCursorIndex += spanningLength
} else {
if codepointCount == spanningLength {
for _ in 0..<codepointCount {
if readingCursorIndex < builderCursorIndex {
composedStringCursorIndex += 1
readingCursorIndex += 1
}
}
// We must do some Unicode codepoint counting to find the actual cursor location for the client
// i.e. we need to take UTF-16 into consideration, for which a surrogate pair takes 2 UniChars
// locations. These processes are inherited from the ObjC++ version of this class and might be
// unnecessary in Swift, but this deduction requires further experiments.
for walkedNode in _walkedNodes {
if let theNode = walkedNode.node {
let strNodeValue = theNode.currentKeyValue.value
composingBuffer += strNodeValue
let arrSplit: [NSString] = (strNodeValue as NSString).split()
let codepointCount = arrSplit.count
// This re-aligns the cursor index in the composed string
// (the actual cursor on the screen) with the builder's logical
// cursor (reading) cursor; each built node has a "spanning length"
// (e.g. two reading blocks has a spanning length of 2), and we
// accumulate those lengths to calculate the displayed cursor
// index.
let spanningLength: Int = walkedNode.spanningLength
if readingCursorIndex + spanningLength <= builderCursorIndex {
composedStringCursorIndex += (strNodeValue as NSString).length
readingCursorIndex += spanningLength
} else {
if readingCursorIndex < builderCursorIndex {
composedStringCursorIndex += valueString.count
readingCursorIndex += spanningLength
if readingCursorIndex > builderCursorIndex {
readingCursorIndex = builderCursorIndex
if codepointCount == spanningLength {
var i = 0
while i < codepointCount, readingCursorIndex < builderCursorIndex {
composedStringCursorIndex += arrSplit[i].length
readingCursorIndex += 1
i += 1
}
} else {
if readingCursorIndex < builderCursorIndex {
composedStringCursorIndex += (strNodeValue as NSString).length
readingCursorIndex += spanningLength
if readingCursorIndex > builderCursorIndex {
readingCursorIndex = builderCursorIndex
}
}
}
}
@ -76,21 +81,9 @@ extension KeyHandler {
// Now, we gather all the intel, separate the composing buffer to two parts (head and tail),
// and insert the reading text (the Mandarin syllable) in between them.
// The reading text is what the user is typing.
var rawHead = ""
var rawEnd = ""
for (i, n) in composingBuffer.enumerated() {
if i < composedStringCursorIndex {
rawHead += String(n)
} else {
rawEnd += String(n)
}
}
let head = rawHead
let head = String((composingBuffer as NSString).substring(to: composedStringCursorIndex))
let reading = _composer.getInlineCompositionForIMK(isHanyuPinyin: mgrPrefs.showHanyuPinyinInCompositionBuffer)
let tail = rawEnd
let tail = String((composingBuffer as NSString).substring(from: composedStringCursorIndex))
let composedText = head + reading + tail
let cursorIndex = composedStringCursorIndex + reading.count
@ -106,7 +99,7 @@ extension KeyHandler {
InputState.ChoosingCandidate(
composingBuffer: currentState.composingBuffer,
cursorIndex: currentState.cursorIndex,
candidates: getCandidatesArray(),
candidates: candidatesArray,
useVerticalMode: useVerticalMode
)
}
@ -115,7 +108,7 @@ extension KeyHandler {
// buildAssociatePhraseStateWithKey
// 使
// ObjC buildAssociatePhraseArray
// Core buildAssociatePhraseArray
// String Swift
// nil
//
@ -134,12 +127,12 @@ extension KeyHandler {
func handleMarkingState(
_ state: InputState.Marking,
input: InputHandler,
input: InputSignal,
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
if input.isESC {
stateCallback(buildInputtingState())
stateCallback(buildInputtingState)
return true
}
@ -152,7 +145,7 @@ extension KeyHandler {
return true
}
}
stateCallback(buildInputtingState())
stateCallback(buildInputtingState)
return true
}
@ -168,7 +161,7 @@ extension KeyHandler {
readings: state.readings
)
marking.tooltipForInputting = state.tooltipForInputting
stateCallback(marking.markedRange.length == 0 ? marking.convertToInputting() : marking)
stateCallback(marking.markedRange.length == 0 ? marking.convertedToInputting : marking)
} else {
IME.prtDebugIntel("1149908D")
errorCallback()
@ -191,7 +184,7 @@ extension KeyHandler {
readings: state.readings
)
marking.tooltipForInputting = state.tooltipForInputting
stateCallback(marking.markedRange.length == 0 ? marking.convertToInputting() : marking)
stateCallback(marking.markedRange.length == 0 ? marking.convertedToInputting : marking)
} else {
IME.prtDebugIntel("9B51408D")
errorCallback()
@ -217,8 +210,8 @@ extension KeyHandler {
if _composer.isEmpty {
insertReadingToBuilderAtCursor(reading: customPunctuation)
let poppedText = popOverflowComposingTextAndWalk()
let inputting = buildInputtingState()
let poppedText = popOverflowComposingTextAndWalk
let inputting = buildInputtingState
inputting.poppedText = poppedText
stateCallback(inputting)
@ -273,7 +266,7 @@ extension KeyHandler {
) -> Bool {
guard state is InputState.Inputting else { return false }
var composingBuffer = currentReadings().joined(separator: "-")
var composingBuffer = currentReadings.joined(separator: "-")
if mgrPrefs.inlineDumpPinyinInLieuOfZhuyin {
composingBuffer = restoreToneOneInZhuyinKey(target: composingBuffer) //
composingBuffer = Tekkon.cnvPhonaToHanyuPinyin(target: composingBuffer) //
@ -303,7 +296,7 @@ extension KeyHandler {
for theAnchor in _walkedNodes {
if let node = theAnchor.node {
var key = node.currentKeyValue().key
var key = node.currentKeyValue.key
if mgrPrefs.inlineDumpPinyinInLieuOfZhuyin {
key = restoreToneOneInZhuyinKey(target: key) //
key = Tekkon.cnvPhonaToHanyuPinyin(target: key) //
@ -313,7 +306,7 @@ extension KeyHandler {
key = cnvZhuyinKeyToTextbookReading(target: key, newSeparator: " ")
}
let value = node.currentKeyValue().value
let value = node.currentKeyValue.value
if key.contains("_") { //
composed += value
} else {
@ -341,7 +334,7 @@ extension KeyHandler {
if _composer.hasToneMarker(withNothingElse: true) {
_composer.clear()
} else if _composer.isEmpty {
if getBuilderCursorIndex() >= 0 {
if builderCursorIndex >= 0 {
deleteBuilderReadingInFrontOfCursor()
walk()
} else {
@ -354,10 +347,10 @@ extension KeyHandler {
_composer.doBackSpace()
}
if _composer.isEmpty, getBuilderLength() == 0 {
if _composer.isEmpty, builderLength == 0 {
stateCallback(InputState.EmptyIgnoringPreviousState())
} else {
stateCallback(buildInputtingState())
stateCallback(buildInputtingState)
}
return true
}
@ -372,10 +365,10 @@ extension KeyHandler {
guard state is InputState.Inputting else { return false }
if _composer.isEmpty {
if getBuilderCursorIndex() != getBuilderLength() {
if builderCursorIndex != builderLength {
deleteBuilderReadingToTheFrontOfCursor()
walk()
let inputting = buildInputtingState()
let inputting = buildInputtingState
// count > 0!isEmpty滿
if inputting.composingBuffer.isEmpty {
stateCallback(InputState.EmptyIgnoringPreviousState())
@ -428,9 +421,9 @@ extension KeyHandler {
return true
}
if getBuilderCursorIndex() != 0 {
setBuilderCursorIndex(value: 0)
stateCallback(buildInputtingState())
if builderCursorIndex != 0 {
builderCursorIndex = 0
stateCallback(buildInputtingState)
} else {
IME.prtDebugIntel("66D97F90")
errorCallback()
@ -456,9 +449,9 @@ extension KeyHandler {
return true
}
if getBuilderCursorIndex() != getBuilderLength() {
setBuilderCursorIndex(value: getBuilderLength())
stateCallback(buildInputtingState())
if builderCursorIndex != builderLength {
builderCursorIndex = builderLength
stateCallback(buildInputtingState)
} else {
IME.prtDebugIntel("9B69908E")
errorCallback()
@ -490,10 +483,10 @@ extension KeyHandler {
// If reading is not empty, we cancel the reading.
if !_composer.isEmpty {
_composer.clear()
if getBuilderLength() == 0 {
if builderLength == 0 {
stateCallback(InputState.EmptyIgnoringPreviousState())
} else {
stateCallback(buildInputtingState())
stateCallback(buildInputtingState)
}
}
}
@ -504,7 +497,7 @@ extension KeyHandler {
func handleForward(
state: InputState,
input: InputHandler,
input: InputSignal,
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
@ -526,7 +519,7 @@ extension KeyHandler {
composingBuffer: currentState.composingBuffer,
cursorIndex: currentState.cursorIndex,
markerIndex: UInt(nextPosition),
readings: currentReadings()
readings: currentReadings
)
marking.tooltipForInputting = currentState.tooltip
stateCallback(marking)
@ -536,9 +529,9 @@ extension KeyHandler {
stateCallback(state)
}
} else {
if getBuilderCursorIndex() < getBuilderLength() {
setBuilderCursorIndex(value: getBuilderCursorIndex() + 1)
stateCallback(buildInputtingState())
if builderCursorIndex < builderLength {
builderCursorIndex += 1
stateCallback(buildInputtingState)
} else {
IME.prtDebugIntel("A96AAD58")
errorCallback()
@ -553,7 +546,7 @@ extension KeyHandler {
func handleBackward(
state: InputState,
input: InputHandler,
input: InputSignal,
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
@ -575,7 +568,7 @@ extension KeyHandler {
composingBuffer: currentState.composingBuffer,
cursorIndex: currentState.cursorIndex,
markerIndex: UInt(previousPosition),
readings: currentReadings()
readings: currentReadings
)
marking.tooltipForInputting = currentState.tooltip
stateCallback(marking)
@ -585,9 +578,9 @@ extension KeyHandler {
stateCallback(state)
}
} else {
if getBuilderCursorIndex() > 0 {
setBuilderCursorIndex(value: getBuilderCursorIndex() - 1)
stateCallback(buildInputtingState())
if builderCursorIndex > 0 {
builderCursorIndex -= 1
stateCallback(buildInputtingState)
} else {
IME.prtDebugIntel("7045E6F3")
errorCallback()

View File

@ -96,7 +96,7 @@ public struct Tekkon {
]
///
public static let allowedsemivowels = ["", "", ""]
public static let allowedSemivowels = ["", "", ""]
///
public static let allowedVowels = [
@ -109,7 +109,7 @@ public struct Tekkon {
/// 調
public static var allowedPhonabets: [String] {
allowedConsonants + allowedsemivowels + allowedVowels + allowedIntonations
allowedConsonants + allowedSemivowels + allowedVowels + allowedIntonations
}
// MARK: - Phonabet Structure
@ -132,18 +132,7 @@ public struct Tekkon {
if !input.isEmpty {
if allowedPhonabets.contains(String(input.reversed()[0])) {
valueStorage = String(input.reversed()[0])
if Tekkon.allowedConsonants.contains(value) {
type = .consonant
} else if Tekkon.allowedsemivowels.contains(value) {
type = .semivowel
} else if Tekkon.allowedVowels.contains(value) {
type = .vowel
} else if Tekkon.allowedIntonations.contains(value) {
type = .intonation
} else {
type = .null
valueStorage = ""
}
ensureType()
}
}
}
@ -159,6 +148,23 @@ public struct Tekkon {
/// - strWith:
mutating func selfReplace(_ strOf: String, _ strWith: String = "") {
valueStorage = valueStorage.replacingOccurrences(of: strOf, with: strWith)
ensureType()
}
///
mutating func ensureType() {
if Tekkon.allowedConsonants.contains(value) {
type = .consonant
} else if Tekkon.allowedSemivowels.contains(value) {
type = .semivowel
} else if Tekkon.allowedVowels.contains(value) {
type = .vowel
} else if Tekkon.allowedIntonations.contains(value) {
type = .intonation
} else {
type = .null
valueStorage = ""
}
}
// MARK: - Misc Definitions
@ -192,7 +198,7 @@ public struct Tekkon {
/// Syllable Composer
/// 使 Struct
/// 調
/// @--DISCUSSION--@
///
/// String Literal @input
/// @arrange .ofDachen
@frozen public struct Composer: Equatable, Hashable, ExpressibleByStringLiteral {
@ -303,7 +309,7 @@ public struct Tekkon {
// MARK: - Public Functions
///
/// @--DISCUSSION--@
///
/// parser
/// - Parameters:
/// - key: UniChar
@ -338,7 +344,7 @@ public struct Tekkon {
/// String
/// UniChar
/// @--DISCUSSION--@
///
/// 調
/// - Parameters:
/// - fromString: String
@ -364,7 +370,7 @@ public struct Tekkon {
/// UniChar
/// UniChar String
/// @--DISCUSSION--@
///
/// 調
/// - Parameters:
/// - fromCharCode: UniChar
@ -446,7 +452,7 @@ public struct Tekkon {
/// 使 BackSpace
/// 調
/// @--DISCUSSION--@
///
///
public mutating func doBackSpace() {
if [.ofHanyuPinyin, .ofSecondaryPinyin, .ofYalePinyin, .ofHualuoPinyin, .ofUniversalPinyin].contains(parser),
@ -490,7 +496,7 @@ public struct Tekkon {
//
/// String
/// @--DISCUSSION--@
///
///
/// - Parameters:
/// - key: String
@ -521,7 +527,7 @@ public struct Tekkon {
}
///
/// @--DISCUSSION--@
///
///
/// - Parameters:
/// - key: String
@ -605,7 +611,7 @@ public struct Tekkon {
}
///
/// @--DISCUSSION--@
///
///
/// - Parameters:
/// - key: String
@ -726,7 +732,7 @@ public struct Tekkon {
}
///
/// @--DISCUSSION--@
///
///
/// - Parameters:
/// - key: String
@ -1237,7 +1243,7 @@ public struct Tekkon {
// MARK: - Maps for Keyboard-to-Phonabet parsers
///
/// @--DISCUSSION--@
///
/// macOS 使 Ukelele
/// 使
static let mapQwertyDachen: [String: String] = [
@ -1248,7 +1254,7 @@ public struct Tekkon {
]
///
/// @--DISCUSSION--@
///
/// 便 validity check
///
static let mapDachenCP26StaticKeys: [String: String] = [
@ -1258,7 +1264,7 @@ public struct Tekkon {
]
///
/// @--DISCUSSION--@
///
/// 便 validity check
///
static let mapHsuStaticKeys: [String: String] = [
@ -1268,7 +1274,7 @@ public struct Tekkon {
]
///
/// @--DISCUSSION--@
///
/// 便 validity check
/// ////
static let mapEten26StaticKeys: [String: String] = [

View File

@ -51,7 +51,7 @@ class ctlInputMethod: IMKInputController {
// KeyHandler 調 KeyHandler
// InputState ctlInputMethod
// keyHandler InputHandler
// keyHandler InputSignal
// currentKeyHandler KeyHandler
// currentKeyHandler
static var currentKeyHandler: KeyHandler = .init()
@ -77,9 +77,11 @@ class ctlInputMethod: IMKInputController {
// MARK: - KeyHandler Reset Command
func resetKeyHandler() {
if let currentClient = currentClient {
keyHandler.clear()
func resetKeyHandler(client sender: Any? = nil) {
keyHandler.clear()
if let client = sender as? IMKTextInput {
handle(state: InputState.Empty(), client: client)
} else if let currentClient = currentClient {
handle(state: InputState.Empty(), client: currentClient)
}
}
@ -112,7 +114,8 @@ class ctlInputMethod: IMKInputController {
handle(state: .Deactivated(), client: client)
}
override func setValue(_ value: Any!, forTag _: Int, client: Any!) {
override func setValue(_ value: Any!, forTag tag: Int, client: Any!) {
_ = tag // Stop clang-format from ruining the parameters of this function.
var newInputMode = InputMode(rawValue: value as? String ?? "") ?? InputMode.imeModeNULL
switch newInputMode {
case InputMode.imeModeCHS:
@ -143,7 +146,8 @@ class ctlInputMethod: IMKInputController {
// MARK: - IMKServerInput protocol methods
override func recognizedEvents(_: Any!) -> Int {
override func recognizedEvents(_ sender: Any!) -> Int {
_ = sender // Stop clang-format from ruining the parameters of this function.
let events: NSEvent.EventTypeMask = [.keyDown, .flagsChanged]
return Int(events.rawValue)
}
@ -180,7 +184,7 @@ class ctlInputMethod: IMKInputController {
IME.areWeUsingOurOwnPhraseEditor = false
}
let input = InputHandler(event: event, isVerticalMode: useVerticalMode)
let input = InputSignal(event: event, isVerticalMode: useVerticalMode)
//
// KeyHandler
@ -195,6 +199,19 @@ class ctlInputMethod: IMKInputController {
}
return result
}
// App Ctrl+Enter / Shift+Enter
// handle(event:) Event
// commitComposition
override func commitComposition(_ sender: Any!) {
resetKeyHandler(client: sender)
}
//
override func composedString(_ sender: Any!) -> Any! {
_ = sender // Stop clang-format from ruining the parameters of this function.
return (state as? InputState.NotEmpty)?.composingBuffer ?? ""
}
}
// MARK: - State Handling
@ -220,6 +237,8 @@ extension ctlInputMethod {
handle(state: newState, previous: previous, client: client)
} else if let newState = newState as? InputState.AssociatedPhrases {
handle(state: newState, previous: previous, client: client)
} else if let newState = newState as? InputState.SymbolTable {
handle(state: newState, previous: previous, client: client)
}
}
@ -246,12 +265,25 @@ extension ctlInputMethod {
if buffer.isEmpty {
return
}
var bufferOutput = ""
//
for theChar in buffer {
if let charCode = theChar.utf16.first {
if !(theChar.isASCII && !(charCode.isPrintable())) {
bufferOutput += String(theChar)
}
}
}
(client as? IMKTextInput)?.insertText(
buffer, replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
bufferOutput, 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?) {
_ = state // Stop clang-format from ruining the parameters of this function.
currentClient = nil
ctlCandidateCurrent?.delegate = nil
@ -267,7 +299,8 @@ extension ctlInputMethod {
)
}
private func handle(state _: InputState.Empty, previous: InputState, client: Any?) {
private func handle(state: InputState.Empty, previous: InputState, client: Any?) {
_ = state // Stop clang-format from ruining the parameters of this function.
ctlCandidateCurrent?.visible = false
hideTooltip()
@ -285,8 +318,10 @@ extension ctlInputMethod {
}
private func handle(
state _: InputState.EmptyIgnoringPreviousState, previous _: InputState, client: Any!
state: InputState.EmptyIgnoringPreviousState, previous: InputState, client: Any!
) {
_ = state // Stop clang-format from ruining the parameters of this function.
_ = previous // Stop clang-format from ruining the parameters of this function.
ctlCandidateCurrent?.visible = false
hideTooltip()
@ -300,7 +335,8 @@ extension ctlInputMethod {
)
}
private func handle(state: InputState.Committing, previous _: InputState, client: Any?) {
private func handle(state: InputState.Committing, previous: InputState, client: Any?) {
_ = previous // Stop clang-format from ruining the parameters of this function.
ctlCandidateCurrent?.visible = false
hideTooltip()
@ -318,7 +354,8 @@ extension ctlInputMethod {
)
}
private func handle(state: InputState.Inputting, previous _: InputState, client: Any?) {
private func handle(state: InputState.Inputting, previous: InputState, client: Any?) {
_ = previous // Stop clang-format from ruining the parameters of this function.
ctlCandidateCurrent?.visible = false
hideTooltip()
@ -345,7 +382,8 @@ extension ctlInputMethod {
}
}
private func handle(state: InputState.Marking, previous _: InputState, client: Any?) {
private func handle(state: InputState.Marking, previous: InputState, client: Any?) {
_ = previous // Stop clang-format from ruining the parameters of this function.
ctlCandidateCurrent?.visible = false
guard let client = client as? IMKTextInput else {
hideTooltip()
@ -369,7 +407,8 @@ extension ctlInputMethod {
}
}
private func handle(state: InputState.ChoosingCandidate, previous _: InputState, client: Any?) {
private func handle(state: InputState.ChoosingCandidate, previous: InputState, client: Any?) {
_ = previous // Stop clang-format from ruining the parameters of this function.
hideTooltip()
guard let client = client as? IMKTextInput else {
ctlCandidateCurrent?.visible = false
@ -385,7 +424,25 @@ extension ctlInputMethod {
show(candidateWindowWith: state, client: client)
}
private func handle(state: InputState.AssociatedPhrases, previous _: InputState, client: Any?) {
private func handle(state: InputState.SymbolTable, previous: InputState, client: Any?) {
_ = previous // Stop clang-format from ruining the parameters of this function.
hideTooltip()
guard let client = client as? IMKTextInput else {
ctlCandidateCurrent?.visible = false
return
}
// the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound,
// 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)
)
show(candidateWindowWith: state, client: client)
}
private func handle(state: InputState.AssociatedPhrases, previous: InputState, client: Any?) {
_ = previous // Stop clang-format from ruining the parameters of this function.
hideTooltip()
guard let client = client as? IMKTextInput else {
ctlCandidateCurrent?.visible = false
@ -547,14 +604,16 @@ extension ctlInputMethod {
// MARK: -
extension ctlInputMethod: KeyHandlerDelegate {
func ctlCandidate(for _: KeyHandler) -> Any {
ctlCandidateCurrent ?? .vertical
func ctlCandidate(for keyHandler: KeyHandler) -> Any {
_ = keyHandler // Stop clang-format from ruining the parameters of this function.
return ctlCandidateCurrent ?? .vertical
}
func keyHandler(
_: KeyHandler, didSelectCandidateAt index: Int,
_ keyHandler: KeyHandler, didSelectCandidateAt index: Int,
ctlCandidate controller: Any
) {
_ = keyHandler // Stop clang-format from ruining the parameters of this function.
if let controller = controller as? ctlCandidate {
ctlCandidate(controller, didSelectCandidateAtIndex: UInt(index))
}
@ -592,7 +651,8 @@ extension ctlInputMethod: KeyHandlerDelegate {
// MARK: -
extension ctlInputMethod: ctlCandidateDelegate {
func candidateCountForController(_: ctlCandidate) -> UInt {
func candidateCountForController(_ controller: ctlCandidate) -> UInt {
_ = controller // Stop clang-format from ruining the parameters of this function.
if let state = state as? InputState.ChoosingCandidate {
return UInt(state.candidates.count)
} else if let state = state as? InputState.AssociatedPhrases {
@ -601,9 +661,10 @@ extension ctlInputMethod: ctlCandidateDelegate {
return 0
}
func ctlCandidate(_: ctlCandidate, candidateAtIndex index: UInt)
func ctlCandidate(_ controller: ctlCandidate, candidateAtIndex index: UInt)
-> String
{
_ = controller // Stop clang-format from ruining the parameters of this function.
if let state = state as? InputState.ChoosingCandidate {
return state.candidates[Int(index)]
} else if let state = state as? InputState.AssociatedPhrases {
@ -612,7 +673,8 @@ extension ctlInputMethod: ctlCandidateDelegate {
return ""
}
func ctlCandidate(_: ctlCandidate, didSelectCandidateAtIndex index: UInt) {
func ctlCandidate(_ controller: ctlCandidate, didSelectCandidateAtIndex index: UInt) {
_ = controller // Stop clang-format from ruining the parameters of this function.
let client = currentClient
if let state = state as? InputState.SymbolTable,
@ -634,7 +696,7 @@ extension ctlInputMethod: ctlCandidateDelegate {
let selectedValue = state.candidates[Int(index)]
keyHandler.fixNode(value: selectedValue)
let inputting = keyHandler.buildInputtingState()
let inputting = keyHandler.buildInputtingState
if mgrPrefs.useSCPCTypingMode {
keyHandler.clear()

View File

@ -302,7 +302,7 @@ extension ctlInputMethod {
}
@objc func openUserDataFolder(_: Any?) {
if !mgrLangModel.checkIfUserDataFolderExists() {
if !mgrLangModel.userDataFolderExists {
return
}
NSWorkspace.shared.openFile(

View File

@ -186,7 +186,7 @@ extension vChewing {
var strPrevious = "()"
var strAnterior = "()"
guard let kvCurrent = arrNodesReversed[0].node?.currentKeyValue(),
guard let kvCurrent = arrNodesReversed[0].node?.currentKeyValue,
!arrEndingPunctuation.contains(kvCurrent.value)
else {
return ""
@ -196,14 +196,14 @@ extension vChewing {
strCurrent = kvCurrent.key
if arrNodesReversed.count >= 2,
let kvPrevious = arrNodesReversed[1].node?.currentKeyValue(),
let kvPrevious = arrNodesReversed[1].node?.currentKeyValue,
!arrEndingPunctuation.contains(kvPrevious.value)
{
strPrevious = "(\(kvPrevious.key),\(kvPrevious.value))"
}
if arrNodesReversed.count >= 3,
let kvAnterior = arrNodesReversed[2].node?.currentKeyValue(),
let kvAnterior = arrNodesReversed[2].node?.currentKeyValue,
!arrEndingPunctuation.contains(kvAnterior.value)
{
strAnterior = "(\(kvAnterior.key),\(kvAnterior.value))"

View File

@ -271,7 +271,7 @@ enum mgrLangModel {
}
static func chkUserLMFilesExist(_ mode: InputMode) -> Bool {
if !checkIfUserDataFolderExists() {
if !userDataFolderExists {
return false
}
if !ensureFileExists(userPhrasesDataPath(mode))
@ -309,9 +309,8 @@ enum mgrLangModel {
return true
}
//
//
static func checkIfUserDataFolderExists() -> Bool {
//
static var userDataFolderExists: Bool {
let folderPath = mgrLangModel.dataFolderPath(isDefaultFolder: false)
var isFolder = ObjCBool(false)
var folderExist = FileManager.default.fileExists(atPath: folderPath, isDirectory: &isFolder)

View File

@ -24,33 +24,55 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
extension Megrez {
///
public class BlockReadingBuilder {
var mutMaximumBuildSpanLength = 10
var mutCursorIndex: Int = 0
var mutReadings: [String] = []
var mutGrid: Grid = .init()
var mutLM: LanguageModel
var mutJoinSeparator: String = ""
///
private var mutMaximumBuildSpanLength = 10
///
private var mutCursorIndex: Int = 0
///
private var mutReadings: [String] = []
///
private var mutGrid: Grid = .init()
/// 使
private var mutLM: LanguageModel
public init(lm: LanguageModel, length: Int = 10) {
mutLM = lm
mutMaximumBuildSpanLength = length
///
public var joinSeparator: String = ""
///
public var cursorIndex: Int {
get { mutCursorIndex }
set { mutCursorIndex = (newValue < 0) ? 0 : min(newValue, mutReadings.count) }
}
///
public var grid: Grid { mutGrid }
///
public var length: Int { mutReadings.count }
///
public var readings: [String] { mutReadings }
///
/// - Parameters:
/// - lm: Megrez.LanguageModel
/// - length: 10
/// - separator:
public init(lm: LanguageModel, length: Int = 10, separator: String = "") {
mutLM = lm
mutMaximumBuildSpanLength = length
joinSeparator = separator
}
///
public func clear() {
mutCursorIndex = 0
mutReadings.removeAll()
mutGrid.clear()
}
public func length() -> Int { mutReadings.count }
public func cursorIndex() -> Int { mutCursorIndex }
public func setCursorIndex(newIndex: Int) {
mutCursorIndex = min(newIndex, mutReadings.count)
}
///
/// - Parameters:
/// - reading:
public func insertReadingAtCursor(reading: String) {
mutReadings.insert(reading, at: mutCursorIndex)
mutGrid.expandGridByOneAt(location: mutCursorIndex)
@ -58,8 +80,8 @@ extension Megrez {
mutCursorIndex += 1
}
public func readings() -> [String] { mutReadings }
///
/// Rear
@discardableResult public func deleteReadingAtTheRearOfCursor() -> Bool {
if mutCursorIndex == 0 {
return false
@ -72,6 +94,8 @@ extension Megrez {
return true
}
///
/// Front
@discardableResult public func deleteReadingToTheFrontOfCursor() -> Bool {
if mutCursorIndex == mutReadings.count {
return false
@ -83,8 +107,12 @@ extension Megrez {
return true
}
///
///
///
///
@discardableResult public func removeHeadReadings(count: Int) -> Bool {
if count > length() {
if count > length {
return false
}
@ -100,17 +128,108 @@ extension Megrez {
return true
}
public func setJoinSeparator(separator: String) {
mutJoinSeparator = separator
// MARK: - Walker
///
///
/// 使
/// - Parameters:
/// - at:
/// - score: 0
/// - nodesLimit:
/// - balanced:
public func walk(
at location: Int,
score accumulatedScore: Double = 0.0,
nodesLimit: Int = 0,
balanced: Bool = false
) -> [NodeAnchor] {
Array(
reverseWalk(
at: location, score: accumulatedScore,
nodesLimit: nodesLimit, balanced: balanced
).reversed())
}
public func joinSeparator() -> String { mutJoinSeparator }
///
/// - Parameters:
/// - at:
/// - score: 0
/// - nodesLimit:
/// - balanced:
public func reverseWalk(
at location: Int,
score accumulatedScore: Double = 0.0,
nodesLimit: Int = 0,
balanced: Bool = false
) -> [NodeAnchor] {
if location == 0 || location > mutGrid.width {
return [] as [NodeAnchor]
}
public func grid() -> Grid { mutGrid }
var paths: [[NodeAnchor]] = []
var nodes: [NodeAnchor] = mutGrid.nodesEndingAt(location: location)
public func build() {
// if (mutLM == nil) { return } // nil
if balanced {
nodes.sort {
$0.balancedScore > $1.balancedScore
}
}
for (i, n) in nodes.enumerated() {
// X NodeAnchor node
// abs
if abs(nodesLimit) > 0, i == abs(nodesLimit) - 1 {
break
}
var n = n
guard let nNode = n.node else {
continue
}
n.accumulatedScore = accumulatedScore + nNode.score
//
//
if balanced {
let weightedScore: Double = (Double(n.spanningLength) - 1) * 2
n.accumulatedScore += weightedScore
}
var path: [NodeAnchor] = reverseWalk(
at: location - n.spanningLength,
score: n.accumulatedScore
)
path.insert(n, at: 0)
paths.append(path)
// 使
if balanced, nNode.score >= 0 {
break
}
}
if !paths.isEmpty {
if var result = paths.first {
for value in paths {
if let vLast = value.last, let rLast = result.last {
if vLast.accumulatedScore > rLast.accumulatedScore {
result = value
}
}
}
return result
}
}
return [] as [NodeAnchor]
}
// MARK: - Private functions
private func build() {
let itrBegin: Int =
(mutCursorIndex < mutMaximumBuildSpanLength) ? 0 : mutCursorIndex - mutMaximumBuildSpanLength
let itrEnd: Int = min(mutCursorIndex + mutMaximumBuildSpanLength, mutReadings.count)
@ -121,7 +240,7 @@ extension Megrez {
break
}
let strSlice = mutReadings[p..<(p + q)]
let combinedReading: String = join(slice: strSlice, separator: mutJoinSeparator)
let combinedReading: String = join(slice: strSlice, separator: joinSeparator)
if !mutGrid.hasMatchedNode(location: p, spanningLength: q, key: combinedReading) {
let unigrams: [Unigram] = mutLM.unigramsFor(key: combinedReading)
@ -134,7 +253,7 @@ extension Megrez {
}
}
public func join(slice strSlice: ArraySlice<String>, separator: String) -> String {
private func join(slice strSlice: ArraySlice<String>, separator: String) -> String {
var arrResult: [String] = []
for value in strSlice {
arrResult.append(value)

View File

@ -1,123 +0,0 @@
// Swiftified by (c) 2022 and onwards The vChewing Project (MIT-NTL License).
// Rebranded from (c) Lukhnos Liu's C++ library "Gramambular" (MIT License).
/*
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
1. The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
2. 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 above.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
extension Megrez {
public class Walker {
var mutGrid: Grid
public init(grid: Megrez.Grid = Megrez.Grid()) {
mutGrid = grid
}
public func walk(
at location: Int,
score accumulatedScore: Double = 0.0,
nodesLimit: Int = 0,
balanced: Bool = false
) -> [NodeAnchor] {
var arrReturn: [NodeAnchor] = []
let arrReversedSource = reverseWalk(
at: location, score: accumulatedScore,
nodesLimit: nodesLimit, balanced: balanced
).reversed()
for neta in arrReversedSource {
arrReturn.append(neta)
}
return arrReturn
}
public func reverseWalk(
at location: Int,
score accumulatedScore: Double = 0.0,
nodesLimit: Int = 0,
balanced: Bool = false
) -> [NodeAnchor] {
if location == 0 || location > mutGrid.width() {
return [] as [NodeAnchor]
}
var paths: [[NodeAnchor]] = []
var nodes: [NodeAnchor] = mutGrid.nodesEndingAt(location: location)
if balanced {
nodes.sort {
$0.balancedScore > $1.balancedScore
}
}
for (i, n) in nodes.enumerated() {
// X NodeAnchor node
// abs
if abs(nodesLimit) > 0, i == abs(nodesLimit) - 1 {
break
}
var n = n
guard let nNode = n.node else {
continue
}
n.accumulatedScore = accumulatedScore + nNode.score()
// Spanning Length
//
if balanced {
let weightedScore: Double = (Double(n.spanningLength) - 1) * 2
n.accumulatedScore += weightedScore
}
var path: [NodeAnchor] = reverseWalk(
at: location - n.spanningLength,
score: n.accumulatedScore
)
path.insert(n, at: 0)
paths.append(path)
// 使
if balanced, nNode.score() >= 0 {
break
}
}
if !paths.isEmpty {
if var result = paths.first {
for value in paths {
if let vLast = value.last, let rLast = result.last {
if vLast.accumulatedScore > rLast.accumulatedScore {
result = value
}
}
}
return result
}
}
return [] as [NodeAnchor]
}
}
}

View File

@ -24,17 +24,28 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
extension Megrez {
///
public class Grid {
var mutSpans: [Megrez.Span]
///
private var mutSpans: [Megrez.Span]
///
var width: Int { mutSpans.count }
public init() {
mutSpans = [Megrez.Span]()
}
///
public func clear() {
mutSpans = [Megrez.Span]()
}
///
/// - Parameters:
/// - node:
/// - location:
/// - spanningLength:
public func insertNode(node: Node, location: Int, spanningLength: Int) {
if location >= mutSpans.count {
let diff = location - mutSpans.count + 1
@ -45,15 +56,23 @@ extension Megrez {
mutSpans[location].insert(node: node, length: spanningLength)
}
///
/// - Parameters:
/// - location:
/// - spanningLength:
/// - key:
public func hasMatchedNode(location: Int, spanningLength: Int, key: String) -> Bool {
if location > mutSpans.count {
return false
}
let n = mutSpans[location].node(length: spanningLength)
return n == nil ? false : key == n?.key()
return n == nil ? false : key == n?.key
}
///
/// - Parameters:
/// - location:
public func expandGridByOneAt(location: Int) {
// abs
mutSpans.insert(Span(), at: abs(location))
@ -65,6 +84,9 @@ extension Megrez {
}
}
///
/// - Parameters:
/// - location:
public func shrinkGridByOneAt(location: Int) {
if location >= mutSpans.count {
return
@ -77,8 +99,9 @@ extension Megrez {
}
}
public func width() -> Int { mutSpans.count }
///
/// - Parameters:
/// - location:
public func nodesEndingAt(location: Int) -> [NodeAnchor] {
var results: [NodeAnchor] = []
if !mutSpans.isEmpty, location <= mutSpans.count {
@ -100,6 +123,9 @@ extension Megrez {
return results
}
///
/// - Parameters:
/// - location:
public func nodesCrossingOrEndingAt(location: Int) -> [NodeAnchor] {
var results: [NodeAnchor] = []
if !mutSpans.isEmpty, location <= mutSpans.count {
@ -126,14 +152,18 @@ extension Megrez {
return results
}
public func fixNodeSelectedCandidate(location: Int, value: String) -> NodeAnchor {
///
/// - Parameters:
/// - location:
/// - value:
@discardableResult public func fixNodeSelectedCandidate(location: Int, value: String) -> NodeAnchor {
var node = NodeAnchor()
for nodeAnchor in nodesCrossingOrEndingAt(location: location) {
guard let theNode = nodeAnchor.node else {
continue
}
let candidates = theNode.candidates()
// Reset the candidate-fixed state of every node at the location.
let candidates = theNode.candidates
//
theNode.resetCandidate()
for (i, candidate) in candidates.enumerated() {
if candidate.value == value {
@ -146,13 +176,18 @@ extension Megrez {
return node
}
///
/// - Parameters:
/// - location:
/// - value:
/// - overridingScore:
public func overrideNodeScoreForSelectedCandidate(location: Int, value: String, overridingScore: Double) {
for nodeAnchor in nodesCrossingOrEndingAt(location: location) {
guard let theNode = nodeAnchor.node else {
continue
}
let candidates = theNode.candidates()
// Reset the candidate-fixed state of every node at the location.
let candidates = theNode.candidates
//
theNode.resetCandidate()
for (i, candidate) in candidates.enumerated() {
if candidate.value == value {
@ -164,3 +199,38 @@ extension Megrez {
}
}
}
// MARK: - DumpDOT-related functions.
extension Megrez.Grid {
public var dumpDOT: String {
var sst = "digraph {\ngraph [ rankdir=LR ];\nBOS;\n"
for (p, span) in mutSpans.enumerated() {
for ni in 0...(span.maximumLength) {
guard let np: Megrez.Node = span.node(length: ni) else {
continue
}
if p == 0 {
sst += "BOS -> \(np.currentKeyValue.value);\n"
}
sst += "\(np.currentKeyValue.value);\n"
if (p + ni) < mutSpans.count {
let dstSpan = mutSpans[p + ni]
for q in 0...(dstSpan.maximumLength) {
if let dn = dstSpan.node(length: q) {
sst += np.currentKeyValue.value + " -> " + dn.currentKeyValue.value + ";\n"
}
}
}
if (p + ni) == mutSpans.count {
sst += np.currentKeyValue.value + " -> EOS;\n"
}
}
}
sst += "EOS;\n}\n"
return sst
}
}

View File

@ -24,19 +24,52 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
extension Megrez {
@frozen public struct NodeAnchor {
///
@frozen public struct NodeAnchor: CustomStringConvertible {
///
public var node: Node?
///
public var location: Int = 0
///
public var spanningLength: Int = 0
///
public var accumulatedScore: Double = 0.0
///
public var keyLength: Int {
node?.key().count ?? 0
node?.key.count ?? 0
}
///
public var description: String {
var stream = ""
stream += "{@(" + String(location) + "," + String(spanningLength) + "),"
if let node = node {
stream += node.description
} else {
stream += "null"
}
stream += "}"
return stream
}
///
public var balancedScore: Double {
let weightedScore: Double = (Double(spanningLength) - 1) * 2
let nodeScore: Double = node?.score() ?? 0
let nodeScore: Double = node?.score ?? 0
return weightedScore + nodeScore
}
}
}
// MARK: - DumpDOT-related functions.
extension Array where Element == Megrez.NodeAnchor {
///
public var description: String {
var arrOutputContent = [""]
for anchor in self {
arrOutputContent.append(anchor.description)
}
return arrOutputContent.joined(separator: "<-")
}
}

View File

@ -24,23 +24,28 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
extension Megrez {
///
@frozen public struct Span {
private var mutLengthNodeMap: [Int: Megrez.Node]
private var mutMaximumLength: Int
///
private var mutLengthNodeMap: [Int: Megrez.Node] = [:]
///
private var mutMaximumLength: Int = 0
///
var maximumLength: Int {
mutMaximumLength
}
public init() {
mutLengthNodeMap = [:]
mutMaximumLength = 0
}
///
mutating func clear() {
mutLengthNodeMap.removeAll()
mutMaximumLength = 0
}
///
/// - Parameters:
/// - node:
/// - length:
mutating func insert(node: Node, length: Int) {
mutLengthNodeMap[length] = node
if length > mutMaximumLength {
@ -48,6 +53,9 @@ extension Megrez {
}
}
///
/// - Parameters:
/// - length:
mutating func removeNodeOfLengthGreaterThan(_ length: Int) {
if length > mutMaximumLength { return }
var max = 0
@ -67,6 +75,9 @@ extension Megrez {
mutMaximumLength = max
}
///
/// - Parameters:
/// - length:
public func node(length: Int) -> Node? {
mutLengthNodeMap[length]
}

View File

@ -24,55 +24,69 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
extension Megrez {
public class Node {
let mutLM: LanguageModel
var mutKey: String
var mutScore: Double = 0
var mutUnigrams: [Unigram]
var mutCandidates: [KeyValuePair]
var mutValueUnigramIndexMap: [String: Int]
var mutPrecedingBigramMap: [KeyValuePair: [Megrez.Bigram]]
var mutCandidateFixed: Bool = false
var mutSelectedUnigramIndex: Int = 0
let kSelectedCandidateScore: Double = 99
public init(key: String, unigrams: [Megrez.Unigram], bigrams: [Megrez.Bigram] = []) {
mutLM = LanguageModel()
mutKey = key
mutScore = 0
mutUnigrams = unigrams
mutCandidates = []
mutValueUnigramIndexMap = [:]
mutPrecedingBigramMap = [:]
mutCandidateFixed = false
mutSelectedUnigramIndex = 0
if bigrams == [] {
node(key: key, unigrams: unigrams, bigrams: bigrams)
} else {
node(key: key, unigrams: unigrams)
}
///
public class Node: CustomStringConvertible {
///
private let mutLM: LanguageModel = .init()
///
private var mutKey: String = ""
///
private var mutScore: Double = 0
///
private var mutUnigrams: [Unigram]
///
private var mutBigrams: [Bigram]
///
private var mutCandidates: [KeyValuePair] = []
/// 調
private var mutValueUnigramIndexMap: [String: Int] = [:]
///
private var mutPrecedingBigramMap: [KeyValuePair: [Megrez.Bigram]] = [:]
///
private var mutCandidateFixed: Bool = false
///
private var mutSelectedUnigramIndex: Int = 0
///
private let kSelectedCandidateScore: Double = 99
///
public var description: String {
"(node,key:\(mutKey),fixed:\(mutCandidateFixed ? "true" : "false"),selected:\(mutSelectedUnigramIndex),\(mutUnigrams))"
}
public func node(key: String, unigrams: [Megrez.Unigram], bigrams: [Megrez.Bigram] = []) {
var unigrams = unigrams
///
var candidates: [KeyValuePair] { mutCandidates }
///
var isCandidateFixed: Bool { mutCandidateFixed }
///
var key: String { mutKey }
///
var score: Double { mutScore }
///
var currentKeyValue: KeyValuePair {
mutSelectedUnigramIndex >= mutUnigrams.count ? KeyValuePair() : mutCandidates[mutSelectedUnigramIndex]
}
///
var highestUnigramScore: Double { mutUnigrams.isEmpty ? 0.0 : mutUnigrams[0].score }
///
/// - Parameters:
/// - key:
/// - unigrams:
/// - bigrams:
public init(key: String, unigrams: [Megrez.Unigram], bigrams: [Megrez.Bigram] = []) {
mutKey = key
unigrams.sort {
mutUnigrams = unigrams
mutBigrams = bigrams
mutUnigrams.sort {
$0.score > $1.score
}
if !mutUnigrams.isEmpty {
mutScore = mutUnigrams[0].score
}
for (i, theGram) in unigrams.enumerated() {
mutValueUnigramIndexMap[theGram.keyValue.value] = i
mutCandidates.append(theGram.keyValue)
for (i, gram) in mutUnigrams.enumerated() {
mutValueUnigramIndexMap[gram.keyValue.value] = i
mutCandidates.append(gram.keyValue)
}
for gram in bigrams {
@ -80,11 +94,14 @@ extension Megrez {
}
}
///
/// - Parameters:
/// - precedingKeyValues:
public func primeNodeWith(precedingKeyValues: [KeyValuePair]) {
var newIndex = mutSelectedUnigramIndex
var max = mutScore
if !isCandidateFixed() {
if !isCandidateFixed {
for neta in precedingKeyValues {
let bigrams = mutPrecedingBigramMap[neta] ?? []
for bigram in bigrams {
@ -107,16 +124,17 @@ extension Megrez {
}
}
public func isCandidateFixed() -> Bool { mutCandidateFixed }
public func candidates() -> [KeyValuePair] { mutCandidates }
///
/// - Parameters:
/// - index:
/// - fix:
public func selectCandidateAt(index: Int = 0, fix: Bool = false) {
mutSelectedUnigramIndex = index >= mutUnigrams.count ? 0 : index
mutCandidateFixed = fix
mutScore = kSelectedCandidateScore
}
///
public func resetCandidate() {
mutSelectedUnigramIndex = 0
mutCandidateFixed = false
@ -125,16 +143,19 @@ extension Megrez {
}
}
///
/// - Parameters:
/// - index:
/// - score:
public func selectFloatingCandidateAt(index: Int, score: Double) {
mutSelectedUnigramIndex = index >= mutUnigrams.count ? 0 : index
mutCandidateFixed = false
mutScore = score
}
public func key() -> String { mutKey }
public func score() -> Double { mutScore }
///
/// - Parameters:
/// - candidate:
public func scoreFor(candidate: String) -> Double {
for unigram in mutUnigrams {
if unigram.keyValue.value == candidate {
@ -144,14 +165,6 @@ extension Megrez {
return 0.0
}
public func currentKeyValue() -> KeyValuePair {
mutSelectedUnigramIndex >= mutUnigrams.count ? KeyValuePair() : mutCandidates[mutSelectedUnigramIndex]
}
public func highestUnigramScore() -> Double {
mutUnigrams.isEmpty ? 0.0 : mutUnigrams[0].score
}
public static func == (lhs: Node, rhs: Node) -> Bool {
lhs.mutUnigrams == rhs.mutUnigrams && lhs.mutCandidates == rhs.mutCandidates
&& lhs.mutValueUnigramIndexMap == rhs.mutValueUnigramIndexMap

View File

@ -24,19 +24,23 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
extension Megrez {
// 使
// Swift
/// 使
open class LanguageModel {
public init() {}
// Swift
///
open func unigramsFor(key: String) -> [Megrez.Unigram] {
key.isEmpty ? [Megrez.Unigram]() : [Megrez.Unigram]()
}
///
open func bigramsForKeys(precedingKey: String, key: String) -> [Megrez.Bigram] {
precedingKey == key ? [Megrez.Bigram]() : [Megrez.Bigram]()
}
///
open func hasUnigramsFor(key: String) -> Bool {
key.count != 0
}

View File

@ -24,17 +24,28 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
extension Megrez {
@frozen public struct Bigram: Equatable {
///
@frozen public struct Bigram: Equatable, CustomStringConvertible {
///
public var keyValue: KeyValuePair
///
public var precedingKeyValue: KeyValuePair
///
public var score: Double
// var paired: String
///
public var description: String {
"(" + keyValue.description + "|" + precedingKeyValue.description + "," + String(score) + ")"
}
///
/// - Parameters:
/// - precedingKeyValue:
/// - keyValue:
/// - score:
public init(precedingKeyValue: KeyValuePair, keyValue: KeyValuePair, score: Double) {
self.keyValue = keyValue
self.precedingKeyValue = precedingKeyValue
self.score = score
// paired = "(" + keyValue.paired + "|" + precedingKeyValue.paired + "," + String(score) + ")"
}
public func hash(into hasher: inout Hasher) {
@ -44,16 +55,6 @@ extension Megrez {
// hasher.combine(paired)
}
// static func getPairedBigrams(grams: [Bigram]) -> String {
// var arrOutputContent = [""]
// var index = 0
// for gram in grams {
// arrOutputContent.append(contentsOf: [String(index) + "=>" + gram.paired])
// index += 1
// }
// return "[" + String(grams.count) + "]=>{" + arrOutputContent.joined(separator: ",") + "}"
// }
public static func == (lhs: Bigram, rhs: Bigram) -> Bool {
lhs.precedingKeyValue == rhs.precedingKeyValue && lhs.keyValue == rhs.keyValue && lhs.score == rhs.score
}
@ -62,13 +63,18 @@ extension Megrez {
lhs.precedingKeyValue < rhs.precedingKeyValue
|| (lhs.keyValue < rhs.keyValue || (lhs.keyValue == rhs.keyValue && lhs.keyValue < rhs.keyValue))
}
var description: String {
"\(keyValue):\(score)"
}
var debugDescription: String {
"Bigram(keyValue: \(keyValue), score: \(score))"
}
}
}
// MARK: - DumpDOT-related functions.
extension Array where Element == Megrez.Bigram {
///
public var description: String {
var arrOutputContent = [""]
for (index, gram) in enumerated() {
arrOutputContent.append(contentsOf: [String(index) + "=>" + gram.description])
}
return "[" + String(count) + "]=>{" + arrOutputContent.joined(separator: ",") + "}"
}
}

View File

@ -24,21 +24,29 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
extension Megrez {
@frozen public struct Unigram: Equatable {
///
@frozen public struct Unigram: Equatable, CustomStringConvertible {
///
public var keyValue: KeyValuePair
///
public var score: Double
// var paired: String
///
public var description: String {
"(" + keyValue.description + "," + String(score) + ")"
}
///
/// - Parameters:
/// - keyValue:
/// - score:
public init(keyValue: KeyValuePair, score: Double) {
self.keyValue = keyValue
self.score = score
// paired = "(" + keyValue.paired + "," + String(score) + ")"
}
public func hash(into hasher: inout Hasher) {
hasher.combine(keyValue)
hasher.combine(score)
// hasher.combine(paired)
}
//
@ -46,16 +54,6 @@ extension Megrez {
a.score > b.score
}
// static func getPairedUnigrams(grams: [Unigram]) -> String {
// var arrOutputContent = [""]
// var index = 0
// for gram in grams {
// arrOutputContent.append(contentsOf: [String(index) + "=>" + gram.paired])
// index += 1
// }
// return "[" + String(grams.count) + "]=>{" + arrOutputContent.joined(separator: ",") + "}"
// }
public static func == (lhs: Unigram, rhs: Unigram) -> Bool {
lhs.keyValue == rhs.keyValue && lhs.score == rhs.score
}
@ -63,13 +61,18 @@ extension Megrez {
public static func < (lhs: Unigram, rhs: Unigram) -> Bool {
lhs.keyValue < rhs.keyValue || (lhs.keyValue == rhs.keyValue && lhs.keyValue < rhs.keyValue)
}
var description: String {
"\(keyValue):\(score)"
}
var debugDescription: String {
"Unigram(keyValue: \(keyValue), score: \(score))"
}
}
}
// MARK: - DumpDOT-related functions.
extension Array where Element == Megrez.Unigram {
///
public var description: String {
var arrOutputContent = [""]
for (index, gram) in enumerated() {
arrOutputContent.append(contentsOf: [String(index) + "=>" + gram.description])
}
return "[" + String(count) + "]=>{" + arrOutputContent.joined(separator: ",") + "}"
}
}

View File

@ -24,21 +24,29 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
extension Megrez {
@frozen public struct KeyValuePair: Equatable, Hashable, Comparable {
///
@frozen public struct KeyValuePair: Equatable, Hashable, Comparable, CustomStringConvertible {
///
public var key: String
///
public var value: String
// public var paired: String
///
public var description: String {
"(" + key + "," + value + ")"
}
///
/// - Parameters:
/// - key:
/// - value:
public init(key: String = "", value: String = "") {
self.key = key
self.value = value
// paired = "(" + key + "," + value + ")"
}
public func hash(into hasher: inout Hasher) {
hasher.combine(key)
hasher.combine(value)
// hasher.combine(paired)
}
public static func == (lhs: KeyValuePair, rhs: KeyValuePair) -> Bool {
@ -60,13 +68,5 @@ extension Megrez {
public static func >= (lhs: KeyValuePair, rhs: KeyValuePair) -> Bool {
(lhs.key.count >= rhs.key.count) || (lhs.key.count == rhs.key.count && lhs.value >= rhs.value)
}
public var description: String {
"(\(key), \(value))"
}
public var debugDescription: String {
"KeyValuePair(key: \(key), value: \(value))"
}
}
}

View File

@ -109,7 +109,7 @@
"Debug Mode" = "Debug Mode";
"Dictionary" = "Dictionary";
"Emulating select-candidate-per-character mode" = "Emulating select-candidate-per-character mode";
"Enable CNS11643 Support (2022-01-27)" = "Enable CNS11643 Support (2022-01-27)";
"Enable CNS11643 Support (2022-04-27)" = "Enable CNS11643 Support (2022-04-27)";
"Enable Space key for calling candidate window" = "Enable Space key for calling candidate window";
"Enable symbol input support (incl. certain emoji symbols)" = "Enable symbol input support (incl. certain emoji symbols)";
"English" = "English";

View File

@ -109,7 +109,7 @@
"Debug Mode" = "Debug Mode";
"Dictionary" = "Dictionary";
"Emulating select-candidate-per-character mode" = "Emulating select-candidate-per-character mode";
"Enable CNS11643 Support (2022-01-27)" = "Enable CNS11643 Support (2022-01-27)";
"Enable CNS11643 Support (2022-04-27)" = "Enable CNS11643 Support (2022-04-27)";
"Enable Space key for calling candidate window" = "Enable Space key for calling candidate window";
"Enable symbol input support (incl. certain emoji symbols)" = "Enable symbol input support (incl. certain emoji symbols)";
"English" = "English";

View File

@ -109,7 +109,7 @@
"Debug Mode" = "欠陥辿着モード";
"Dictionary" = "辞書設定";
"Emulating select-candidate-per-character mode" = "漢字1つづつ全候補選択入力モード";
"Enable CNS11643 Support (2022-01-27)" = "全字庫モード // 入力可能な漢字数を倍増す (2022-01-07)";
"Enable CNS11643 Support (2022-04-27)" = "全字庫モード // 入力可能な漢字数を倍増す (2022-04-27)";
"Enable Space key for calling candidate window" = "Space キーで入力候補を呼び出す";
"Enable symbol input support (incl. certain emoji symbols)" = "僅かなる絵文字も含む符号入力サポートを起用";
"English" = "英語";

View File

@ -105,11 +105,11 @@
"Choose your preferred layout of the candidate window." = "选择您所偏好的候选字窗布局。";
"Cursor Selection:" = "选字游标:";
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千排列 (微软标准/王安/零壹/仲鼎/国乔)";
"Dachen 26 (libChewing)" = "酷音大千二十六键";
"Dachen 26 (libChewing)" = "酷音大千二十六键排列";
"Debug Mode" = "侦错模式";
"Dictionary" = "辞典";
"Emulating select-candidate-per-character mode" = "模拟 90 年代前期注音逐字选字输入风格";
"Enable CNS11643 Support (2022-01-27)" = "启用 CNS11643 全字库支援 (2022-01-07)";
"Enable CNS11643 Support (2022-04-27)" = "启用 CNS11643 全字库支援 (2022-04-27)";
"Enable Space key for calling candidate window" = "敲空格键以呼出候选字窗";
"Enable symbol input support (incl. certain emoji symbols)" = "启用包括少许绘文字在内的符号输入支援";
"English" = "英语";

View File

@ -105,11 +105,11 @@
"Choose your preferred layout of the candidate window." = "選擇您所偏好的候選字窗佈局。";
"Cursor Selection:" = "選字游標:";
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千排列 (微軟標準/王安/零壹/仲鼎/國喬)";
"Dachen 26 (libChewing)" = "酷音大千二十六鍵";
"Dachen 26 (libChewing)" = "酷音大千二十六鍵排列";
"Debug Mode" = "偵錯模式";
"Dictionary" = "辭典";
"Emulating select-candidate-per-character mode" = "模擬 90 年代前期注音逐字選字輸入風格";
"Enable CNS11643 Support (2022-01-27)" = "啟用 CNS11643 全字庫支援 (2022-01-07)";
"Enable CNS11643 Support (2022-04-27)" = "啟用 CNS11643 全字庫支援 (2022-04-27)";
"Enable Space key for calling candidate window" = "敲空格鍵以呼出候選字窗";
"Enable symbol input support (incl. certain emoji symbols)" = "啟用包括少許繪文字在內的符號輸入支援";
"English" = "英語";

View File

@ -113,7 +113,7 @@ struct suiPrefPaneDictionary: View {
mgrPrefs.shouldAutoReloadUserDataFiles = value
}
Divider()
Toggle(LocalizedStringKey("Enable CNS11643 Support (2022-01-27)"), isOn: $selEnableCNS11643)
Toggle(LocalizedStringKey("Enable CNS11643 Support (2022-04-27)"), isOn: $selEnableCNS11643)
.onChange(of: selEnableCNS11643) { value in
mgrPrefs.cns11643Enabled = value
mgrLangModel.setCNSEnabled(value)

View File

@ -682,7 +682,7 @@
<constraints>
<constraint firstAttribute="height" constant="16" id="KdE-Vd-Y50"/>
</constraints>
<buttonCell key="cell" type="check" title="Enable CNS11643 Support (2022-01-07)" bezelStyle="regularSquare" imagePosition="left" controlSize="small" inset="2" id="W24-T4-cg0">
<buttonCell key="cell" type="check" title="Enable CNS11643 Support (2022-04-27)" bezelStyle="regularSquare" imagePosition="left" controlSize="small" inset="2" id="W24-T4-cg0">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>

View File

@ -152,8 +152,8 @@
/* Class = "NSBox"; title = "Output Settings"; ObjectID = "Uyz-xL-TVN"; */
"Uyz-xL-TVN.title" = "Output Settings";
/* Class = "NSButtonCell"; title = "Enable CNS11643 Support (2022-01-07)"; ObjectID = "W24-T4-cg0"; */
"W24-T4-cg0.title" = "Enable CNS11643 Support (2022-01-07)";
/* Class = "NSButtonCell"; title = "Enable CNS11643 Support (2022-04-27)"; ObjectID = "W24-T4-cg0"; */
"W24-T4-cg0.title" = "Enable CNS11643 Support (2022-04-27)";
/* Class = "NSBox"; title = "Keyboard Layout"; ObjectID = "Wvt-HE-LOv"; */
"Wvt-HE-LOv.title" = "Keyboard Layout";

View File

@ -152,8 +152,8 @@
/* Class = "NSBox"; title = "Output Settings"; ObjectID = "Uyz-xL-TVN"; */
"Uyz-xL-TVN.title" = "出力設定";
/* Class = "NSButtonCell"; title = "Enable CNS11643 Support (2022-01-07)"; ObjectID = "W24-T4-cg0"; */
"W24-T4-cg0.title" = "全字庫モード // 入力可能の漢字数倍増 (2022-01-07)";
/* Class = "NSButtonCell"; title = "Enable CNS11643 Support (2022-04-27)"; ObjectID = "W24-T4-cg0"; */
"W24-T4-cg0.title" = "全字庫モード // 入力可能の漢字数倍増 (2022-04-27)";
/* Class = "NSBox"; title = "Keyboard Layout"; ObjectID = "Wvt-HE-LOv"; */
"Wvt-HE-LOv.title" = "キーボード";

View File

@ -152,8 +152,8 @@
/* Class = "NSBox"; title = "Output Settings"; ObjectID = "Uyz-xL-TVN"; */
"Uyz-xL-TVN.title" = "输出设定";
/* Class = "NSButtonCell"; title = "Enable CNS11643 Support (2022-01-07)"; ObjectID = "W24-T4-cg0"; */
"W24-T4-cg0.title" = "启用 CNS11643 全字库支援 (2022-01-07)";
/* Class = "NSButtonCell"; title = "Enable CNS11643 Support (2022-04-27)"; ObjectID = "W24-T4-cg0"; */
"W24-T4-cg0.title" = "启用 CNS11643 全字库支援 (2022-04-27)";
/* Class = "NSBox"; title = "Keyboard Layout"; ObjectID = "Wvt-HE-LOv"; */
"Wvt-HE-LOv.title" = "键盘布局";

View File

@ -152,8 +152,8 @@
/* Class = "NSBox"; title = "Output Settings"; ObjectID = "Uyz-xL-TVN"; */
"Uyz-xL-TVN.title" = "輸出設定";
/* Class = "NSButtonCell"; title = "Enable CNS11643 Support (2022-01-07)"; ObjectID = "W24-T4-cg0"; */
"W24-T4-cg0.title" = "啟用 CNS11643 全字庫支援 (2022-01-07)";
/* Class = "NSButtonCell"; title = "Enable CNS11643 Support (2022-04-27)"; ObjectID = "W24-T4-cg0"; */
"W24-T4-cg0.title" = "啟用 CNS11643 全字庫支援 (2022-04-27)";
/* Class = "NSBox"; title = "Keyboard Layout"; ObjectID = "Wvt-HE-LOv"; */
"Wvt-HE-LOv.title" = "鍵盤佈局";

View File

@ -3,9 +3,9 @@
<plist version="1.0">
<dict>
<key>CFBundleShortVersionString</key>
<string>1.5.9</string>
<string>1.6.0</string>
<key>CFBundleVersion</key>
<string>1959</string>
<string>1960</string>
<key>UpdateInfoEndpoint</key>
<string>https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist</string>
<key>UpdateInfoSite</key>

View File

@ -726,7 +726,7 @@
<key>USE_HFS+_COMPRESSION</key>
<false/>
<key>VERSION</key>
<string>1.5.9</string>
<string>1.6.0</string>
</dict>
<key>TYPE</key>
<integer>0</integer>

View File

@ -20,7 +20,6 @@
5B38F59D281E2E49007D5F5D /* 4_Node.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1A15FC0EB100ABF4B3 /* 4_Node.swift */; };
5B38F59E281E2E49007D5F5D /* 6_Bigram.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1415FC0EB100ABF4B3 /* 6_Bigram.swift */; };
5B38F59F281E2E49007D5F5D /* 3_NodeAnchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1B15FC0EB100ABF4B3 /* 3_NodeAnchor.swift */; };
5B38F5A0281E2E49007D5F5D /* 1_Walker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1E15FC0EB100ABF4B3 /* 1_Walker.swift */; };
5B38F5A1281E2E49007D5F5D /* 1_BlockReadingBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1515FC0EB100ABF4B3 /* 1_BlockReadingBuilder.swift */; };
5B38F5A2281E2E49007D5F5D /* 0_Megrez.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1615FC0EB100ABF4B3 /* 0_Megrez.swift */; };
5B38F5A3281E2E49007D5F5D /* 3_Span.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1C15FC0EB100ABF4B3 /* 3_Span.swift */; };
@ -107,7 +106,7 @@
6ACA41FD15FC1D9000935EF6 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6ACA41F015FC1D9000935EF6 /* MainMenu.xib */; };
6ACA420215FC1E5200935EF6 /* vChewing.app in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */; };
D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427F76B278CA1BA004A2160 /* AppDelegate.swift */; };
D456576E279E4F7B00DF6BC9 /* InputHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D456576D279E4F7B00DF6BC9 /* InputHandler.swift */; };
D456576E279E4F7B00DF6BC9 /* InputSignal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D456576D279E4F7B00DF6BC9 /* InputSignal.swift */; };
D461B792279DAC010070E734 /* InputState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D461B791279DAC010070E734 /* InputState.swift */; };
D47B92C027972AD100458394 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47B92BF27972AC800458394 /* main.swift */; };
D47F7DCE278BFB57002F9DD7 /* ctlPrefWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCD278BFB57002F9DD7 /* ctlPrefWindow.swift */; };
@ -300,7 +299,6 @@
6A0D4F1B15FC0EB100ABF4B3 /* 3_NodeAnchor.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = 3_NodeAnchor.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
6A0D4F1C15FC0EB100ABF4B3 /* 3_Span.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = 3_Span.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
6A0D4F1D15FC0EB100ABF4B3 /* 6_Unigram.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = 6_Unigram.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
6A0D4F1E15FC0EB100ABF4B3 /* 1_Walker.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = 1_Walker.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
6A15B32421A51F2300B92CD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
6A15B32521A51F2300B92CD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
6A225A1E23679F2600F685C6 /* NotarizedArchives */ = {isa = PBXFileReference; lastKnownFileType = folder; path = NotarizedArchives; sourceTree = "<group>"; };
@ -313,7 +311,7 @@
6ACA41F315FC1D9000935EF6 /* Installer-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Installer-Prefix.pch"; path = "Installer/Installer-Prefix.pch"; sourceTree = SOURCE_ROOT; };
D427A9BF25ED28CC005D43E0 /* vChewing-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "vChewing-Bridging-Header.h"; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
D427F76B278CA1BA004A2160 /* AppDelegate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = AppDelegate.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
D456576D279E4F7B00DF6BC9 /* InputHandler.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputHandler.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
D456576D279E4F7B00DF6BC9 /* InputSignal.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputSignal.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
D461B791279DAC010070E734 /* InputState.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputState.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
D47B92BF27972AC800458394 /* main.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = main.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
D47F7DCD278BFB57002F9DD7 /* ctlPrefWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlPrefWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
@ -413,7 +411,7 @@
5B11328827B94CFB00E58451 /* AppleKeyboardConverter.swift */,
D4E569DA27A34CC100AC2CEF /* CTools.h */,
D4E569DB27A34CC100AC2CEF /* CTools.m */,
D456576D279E4F7B00DF6BC9 /* InputHandler.swift */,
D456576D279E4F7B00DF6BC9 /* InputSignal.swift */,
D461B791279DAC010070E734 /* InputState.swift */,
5BD0113C2818543900609769 /* KeyHandler_Core.swift */,
5B782EC3280C243C007276DE /* KeyHandler_HandleCandidate.swift */,
@ -769,7 +767,6 @@
children = (
6A0D4F1615FC0EB100ABF4B3 /* 0_Megrez.swift */,
6A0D4F1515FC0EB100ABF4B3 /* 1_BlockReadingBuilder.swift */,
6A0D4F1E15FC0EB100ABF4B3 /* 1_Walker.swift */,
6A0D4F1715FC0EB100ABF4B3 /* 2_Grid.swift */,
6A0D4F1B15FC0EB100ABF4B3 /* 3_NodeAnchor.swift */,
6A0D4F1C15FC0EB100ABF4B3 /* 3_Span.swift */,
@ -1054,7 +1051,7 @@
D47F7DD0278C0897002F9DD7 /* ctlNonModalAlertWindow.swift in Sources */,
5B38F5A2281E2E49007D5F5D /* 0_Megrez.swift in Sources */,
5B949BD92816DC5400D87B5D /* LineReader.swift in Sources */,
D456576E279E4F7B00DF6BC9 /* InputHandler.swift in Sources */,
D456576E279E4F7B00DF6BC9 /* InputSignal.swift in Sources */,
5BA9FD1027FEDB6B002DE248 /* suiPrefPaneKeyboard.swift in Sources */,
5B3133BF280B229700A4A505 /* KeyHandler_States.swift in Sources */,
5BA9FD4327FEF3C8002DE248 /* Preferences.swift in Sources */,
@ -1086,7 +1083,6 @@
5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */,
5B61B0CA280BEFD4002E3CFA /* KeyHandler_Misc.swift in Sources */,
5B38F59A281E2E49007D5F5D /* 6_Unigram.swift in Sources */,
5B38F5A0281E2E49007D5F5D /* 1_Walker.swift in Sources */,
5B62A34827AE7CD900A19448 /* ctlCandidateVertical.swift in Sources */,
5BA9FD4027FEF3C8002DE248 /* Localization.swift in Sources */,
5BAA8FBE282CAF380066C406 /* SyllableComposer.swift in Sources */,
@ -1296,7 +1292,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1959;
CURRENT_PROJECT_VERSION = 1960;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
@ -1319,7 +1315,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.9;
MARKETING_VERSION = 1.6.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
@ -1352,7 +1348,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1959;
CURRENT_PROJECT_VERSION = 1960;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
@ -1371,7 +1367,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.9;
MARKETING_VERSION = 1.6.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
@ -1486,7 +1482,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1959;
CURRENT_PROJECT_VERSION = 1960;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
@ -1521,7 +1517,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.9;
MARKETING_VERSION = 1.6.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1553,7 +1549,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1959;
CURRENT_PROJECT_VERSION = 1960;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
@ -1583,7 +1579,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.9;
MARKETING_VERSION = 1.6.0;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -1666,7 +1662,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1959;
CURRENT_PROJECT_VERSION = 1960;
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
@ -1691,7 +1687,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.9;
MARKETING_VERSION = 1.6.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1718,7 +1714,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1959;
CURRENT_PROJECT_VERSION = 1960;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
@ -1738,7 +1734,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.5.9;
MARKETING_VERSION = 1.6.0;
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";