diff --git a/Installer/Resources/Base.lproj/MainMenu.xib b/Installer/Resources/Base.lproj/MainMenu.xib index d2962136..18ad828f 100644 --- a/Installer/Resources/Base.lproj/MainMenu.xib +++ b/Installer/Resources/Base.lproj/MainMenu.xib @@ -67,7 +67,7 @@ - + @@ -271,7 +271,6 @@ Gw - @@ -283,7 +282,7 @@ Gw - + diff --git a/KeyboardExtension/Base.lproj/ShareViewController.xib b/KeyboardExtension/Base.lproj/ShareViewController.xib new file mode 100644 index 00000000..bc80e0d6 --- /dev/null +++ b/KeyboardExtension/Base.lproj/ShareViewController.xib @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/KeyboardExtension/Info.plist b/KeyboardExtension/Info.plist new file mode 100644 index 00000000..f275862c --- /dev/null +++ b/KeyboardExtension/Info.plist @@ -0,0 +1,23 @@ + + + + + CFBundleIconFile + icon + NSExtension + + NSExtensionAttributes + + NSExtensionActivationRule + + NSExtensionActivationSupportsText + + + + NSExtensionPointIdentifier + com.apple.share-services + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).ShareViewController + + + diff --git a/KeyboardExtension/KeyboardExtension.entitlements b/KeyboardExtension/KeyboardExtension.entitlements new file mode 100644 index 00000000..33ede3bb --- /dev/null +++ b/KeyboardExtension/KeyboardExtension.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.temporary-exception.mach-register.global-name + org_atelierInmu_inputmethod_vChewing + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + + diff --git a/KeyboardExtension/ShareViewController.swift b/KeyboardExtension/ShareViewController.swift new file mode 100644 index 00000000..75910d4c --- /dev/null +++ b/KeyboardExtension/ShareViewController.swift @@ -0,0 +1,41 @@ +// +// ShareViewController.swift +// KeyboardExtension +// +// Created by ShikiSuen on 2022/2/20. +// + +import Cocoa + +class ShareViewController: NSViewController { + + override var nibName: NSNib.Name? { + return NSNib.Name("ShareViewController") + } + + override func loadView() { + super.loadView() + + // Insert code here to customize the view + let item = self.extensionContext!.inputItems[0] as! NSExtensionItem + if let attachments = item.attachments { + NSLog("Attachments = %@", attachments as NSArray) + } else { + NSLog("No Attachments") + } + } + + @IBAction func send(_ sender: AnyObject?) { + let outputItem = NSExtensionItem() + // Complete implementation by setting the appropriate value on the output item + + let outputItems = [outputItem] + self.extensionContext!.completeRequest(returningItems: outputItems, completionHandler: nil) +} + + @IBAction func cancel(_ sender: AnyObject?) { + let cancelError = NSError(domain: NSCocoaErrorDomain, code: NSUserCancelledError, userInfo: nil) + self.extensionContext!.cancelRequest(withError: cancelError) + } + +} diff --git a/KeyboardExtension/icon.icns b/KeyboardExtension/icon.icns new file mode 100644 index 00000000..84ae85cd Binary files /dev/null and b/KeyboardExtension/icon.icns differ diff --git a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Info.plist b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Info.plist similarity index 67% rename from Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Info.plist rename to KeyboardExtension/vChewingKeyLayout.bundle/Contents/Info.plist index 52159851..594e7ab6 100644 --- a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Info.plist +++ b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Info.plist @@ -8,48 +8,48 @@ vChewingKeyLayout CFBundleVersion 1.0 - KLInfo_Zhuyin Dachen + KLInfo_vChewingDachen TICapsLockLanguageSwitchCapable TISInputSourceID - org.atelierInmu.keyboardlayout.vChewingKeyLayout.zhuyindachen + org.atelierInmu.keyboardlayout.vChewingKeyLayout.vChewingDachen TISIntendedLanguage zh-Hanb - KLInfo_Zhuyin ETen + KLInfo_vChewingETen TICapsLockLanguageSwitchCapable TISInputSourceID - org.atelierInmu.keyboardlayout.vChewingKeyLayout.zhuyineten + org.atelierInmu.keyboardlayout.vChewingKeyLayout.vChewingETen TISIntendedLanguage zh-Hanb - KLInfo_Zhuyin IBM + KLInfo_vChewingIBM TICapsLockLanguageSwitchCapable TISInputSourceID - org.atelierInmu.keyboardlayout.vChewingKeyLayout.zhuyinibm + org.atelierInmu.keyboardlayout.vChewingKeyLayout.vChewingIBM TISIntendedLanguage zh-Hanb - KLInfo_Zhuyin MiTAC + KLInfo_vChewingMiTAC TICapsLockLanguageSwitchCapable TISInputSourceID - org.atelierInmu.keyboardlayout.vChewingKeyLayout.zhuyinmitac + org.atelierInmu.keyboardlayout.vChewingKeyLayout.vChewingMiTAC TISIntendedLanguage zh-Hanb - KLInfo_Zhuyin Seigyou + KLInfo_vChewingSeigyou TICapsLockLanguageSwitchCapable TISInputSourceID - org.atelierInmu.keyboardlayout.vChewingKeyLayout.zhuyinseigyou + org.atelierInmu.keyboardlayout.vChewingKeyLayout.vChewingSeigyou TISIntendedLanguage zh-Hanb diff --git a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin Dachen.keylayout b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingDachen.keylayout similarity index 99% rename from Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin Dachen.keylayout rename to KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingDachen.keylayout index bf901502..19c784b8 100644 --- a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin Dachen.keylayout +++ b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingDachen.keylayout @@ -1,7 +1,7 @@ - + diff --git a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin ETen.keylayout b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingETen.keylayout similarity index 99% rename from Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin ETen.keylayout rename to KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingETen.keylayout index 98ba181c..918c7780 100644 --- a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin ETen.keylayout +++ b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingETen.keylayout @@ -1,7 +1,7 @@ - + diff --git a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin IBM.keylayout b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingIBM.keylayout similarity index 99% rename from Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin IBM.keylayout rename to KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingIBM.keylayout index e0b3d15c..66ea8e1b 100644 --- a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin IBM.keylayout +++ b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingIBM.keylayout @@ -1,7 +1,7 @@ - + diff --git a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin MiTAC.keylayout b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingMiTAC.keylayout similarity index 99% rename from Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin MiTAC.keylayout rename to KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingMiTAC.keylayout index 2a670716..c459b76a 100644 --- a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin MiTAC.keylayout +++ b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingMiTAC.keylayout @@ -1,7 +1,7 @@ - + diff --git a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin Seigyou.keylayout b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingSeigyou.keylayout similarity index 99% rename from Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin Seigyou.keylayout rename to KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingSeigyou.keylayout index bc6032ad..d153ef26 100644 --- a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/Zhuyin Seigyou.keylayout +++ b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/vChewingSeigyou.keylayout @@ -1,7 +1,7 @@ - + diff --git a/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/zh.lproj/InfoPlist.strings b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/zh.lproj/InfoPlist.strings new file mode 100644 index 00000000..128b7a66 Binary files /dev/null and b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/Resources/zh.lproj/InfoPlist.strings differ diff --git a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/version.plist b/KeyboardExtension/vChewingKeyLayout.bundle/Contents/version.plist similarity index 100% rename from Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/version.plist rename to KeyboardExtension/vChewingKeyLayout.bundle/Contents/version.plist diff --git a/Source/Data b/Source/Data index 36a71ee9..6dc73cd3 160000 --- a/Source/Data +++ b/Source/Data @@ -1 +1 @@ -Subproject commit 36a71ee9d2e58611cd8466a1908f0a30274e261e +Subproject commit 6dc73cd3edd47c85089db8f58e92f0c821e67ed6 diff --git a/Source/Modules/AppDelegate.swift b/Source/Modules/AppDelegate.swift index 3d09736e..461b836b 100644 --- a/Source/Modules/AppDelegate.swift +++ b/Source/Modules/AppDelegate.swift @@ -142,8 +142,8 @@ struct VersionUpdateApi { @objc(AppDelegate) class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelegate, FSEventStreamHelperDelegate { func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event]) { - // 拖一秒鐘再重載,畢竟有些有特殊需求的使用者可能會想使用巨型自訂語彙檔案。 - DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { + // 拖 100ms 再重載,畢竟有些有特殊需求的使用者可能會想使用巨型自訂語彙檔案。 + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { if Preferences.shouldAutoReloadUserDataFiles { mgrLangModel.loadUserPhrases() mgrLangModel.loadUserPhraseReplacement() @@ -159,7 +159,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega private var ctlAboutWindowInstance: ctlAboutWindow? // New About Window private var checkTask: URLSessionTask? private var updateNextStepURL: URL? - private var fsStreamHelper = FSEventStreamHelper(path: mgrLangModel.dataFolderPath, queue: DispatchQueue(label: "User Phrases")) + private var fsStreamHelper = FSEventStreamHelper(path: mgrLangModel.dataFolderPath, queue: DispatchQueue(label: "vChewing User Phrases")) // 補上 dealloc deinit { diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index 94f37529..e488c15e 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -182,9 +182,9 @@ class InputState: NSObject { let (exactEnd, _) = (composingBuffer as NSString).characterIndex(from: markedRange.location + markedRange.length) let selectedReadings = readings[exactBegin.. kMaxMarkRangeLength { return false } + return markedRange.length >= kMinMarkRangeLength && markedRange.length <= kMaxMarkRangeLength + } + + @objc var chkIfUserPhraseExists: Bool { let text = (composingBuffer as NSString).substring(with: markedRange) let (exactBegin, _) = (composingBuffer as NSString).characterIndex(from: markedRange.location) let (exactEnd, _) = (composingBuffer as NSString).characterIndex(from: markedRange.location + markedRange.length) let selectedReadings = readings[exactBegin.. -// C++ namespace usages -using namespace std; -using namespace Taiyan::Mandarin; -using namespace Taiyan::Gramambular; -using namespace vChewing; - InputMode imeModeCHT = @"org.atelierInmu.inputmethod.vChewing.IMECHT"; InputMode imeModeCHS = @"org.atelierInmu.inputmethod.vChewing.IMECHS"; InputMode imeModeNULL = @"org.atelierInmu.inputmethod.vChewing.IMENULL"; static const double kEpsilon = 0.000001; -static double FindHighestScore(const vector &nodes, double epsilon) { +static double FindHighestScore(const std::vector &nodes, double epsilon) { double highestScore = 0.0; for (auto ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) { double score = ni->node->highestUnigramScore(); @@ -49,16 +44,15 @@ static double FindHighestScore(const vector &nodes, double epsilon) return highestScore + epsilon; } -// sort helper -class NodeAnchorDescendingSorter -{ +class NodeAnchorDescendingSorter { public: - bool operator()(const NodeAnchor &a, const NodeAnchor &b) const { + bool operator()(const Taiyan::Gramambular::NodeAnchor &a, const Taiyan::Gramambular::NodeAnchor &b) const + { return a.node->key().length() > b.node->key().length(); } }; -// if DEBUG is defined, a DOT file (GraphViz format) will be written to the +;// if DEBUG is defined, a DOT file (GraphViz format) will be written to the // specified path every time the grid is walked #if DEBUG static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; @@ -71,7 +65,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; Taiyan::Mandarin::BopomofoReadingBuffer *_bpmfReadingBuffer; // language model - vChewing::vChewingLM *_languageModel; + vChewing::LMInstantiator *_languageModel; // user override model vChewing::UserOverrideModel *_userOverrideModel; @@ -96,8 +90,8 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; - (void)setInputMode:(NSString *)value { NSString *newInputMode; - vChewingLM *newLanguageModel; - UserOverrideModel *newUserOverrideModel; + vChewing::LMInstantiator *newLanguageModel; + vChewing::UserOverrideModel *newUserOverrideModel; if ([value isKindOfClass:[NSString class]] && [value isEqual:imeModeCHS]) { newInputMode = imeModeCHS; @@ -120,7 +114,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; if (_builder) { delete _builder; - _builder = new BlockReadingBuilder(_languageModel); + _builder = new Taiyan::Gramambular::BlockReadingBuilder(_languageModel); _builder->setJoinSeparator("-"); } @@ -146,7 +140,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; { self = [super init]; if (self) { - _bpmfReadingBuffer = new BopomofoReadingBuffer(BopomofoKeyboardLayout::StandardLayout()); + _bpmfReadingBuffer = new Taiyan::Mandarin::BopomofoReadingBuffer(Taiyan::Mandarin::BopomofoKeyboardLayout::StandardLayout()); // create the lattice builder _languageModel = [mgrLangModel lmCHT]; @@ -154,8 +148,8 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; _languageModel->setCNSEnabled(Preferences.cns11643Enabled); _userOverrideModel = [mgrLangModel userOverrideModelCHT]; - _builder = new BlockReadingBuilder(_languageModel); - + _builder = new Taiyan::Gramambular::BlockReadingBuilder(_languageModel); + // each Mandarin syllable is separated by a hyphen _builder->setJoinSeparator("-"); _inputMode = imeModeCHT; @@ -168,31 +162,31 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; NSInteger layout = Preferences.keyboardLayout; switch (layout) { case KeyboardLayoutStandard: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::StandardLayout()); + _bpmfReadingBuffer->setKeyboardLayout(Taiyan::Mandarin::BopomofoKeyboardLayout::StandardLayout()); break; case KeyboardLayoutEten: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::ETenLayout()); + _bpmfReadingBuffer->setKeyboardLayout(Taiyan::Mandarin::BopomofoKeyboardLayout::ETenLayout()); break; case KeyboardLayoutHsu: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::HsuLayout()); + _bpmfReadingBuffer->setKeyboardLayout(Taiyan::Mandarin::BopomofoKeyboardLayout::HsuLayout()); break; case KeyboardLayoutEten26: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::ETen26Layout()); + _bpmfReadingBuffer->setKeyboardLayout(Taiyan::Mandarin::BopomofoKeyboardLayout::ETen26Layout()); break; case KeyboardLayoutIBM: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::IBMLayout()); + _bpmfReadingBuffer->setKeyboardLayout(Taiyan::Mandarin::BopomofoKeyboardLayout::IBMLayout()); break; case KeyboardLayoutMiTAC: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::MiTACLayout()); + _bpmfReadingBuffer->setKeyboardLayout(Taiyan::Mandarin::BopomofoKeyboardLayout::MiTACLayout()); break; case KeyboardLayoutFakeSeigyou: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::FakeSeigyouLayout()); + _bpmfReadingBuffer->setKeyboardLayout(Taiyan::Mandarin::BopomofoKeyboardLayout::FakeSeigyouLayout()); break; case KeyboardLayoutHanyuPinyin: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::HanyuPinyinLayout()); + _bpmfReadingBuffer->setKeyboardLayout(Taiyan::Mandarin::BopomofoKeyboardLayout::HanyuPinyinLayout()); break; default: - _bpmfReadingBuffer->setKeyboardLayout(BopomofoKeyboardLayout::StandardLayout()); + _bpmfReadingBuffer->setKeyboardLayout(Taiyan::Mandarin::BopomofoKeyboardLayout::StandardLayout()); Preferences.keyboardLayout = KeyboardLayoutStandard; } } @@ -200,8 +194,8 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; - (void)fixNodeWithValue:(NSString *)value { size_t cursorIndex = [self _actualCandidateCursorIndex]; - string stringValue = [value UTF8String]; - NodeAnchor selectedNode = _builder->grid().fixNodeSelectedCandidate(cursorIndex, stringValue); + std::string stringValue(value.UTF8String); + Taiyan::Gramambular::NodeAnchor selectedNode = _builder->grid().fixNodeSelectedCandidate(cursorIndex, stringValue); if (!Preferences.useSCPCTypingMode) { // 不要針對逐字選字模式啟用臨時半衰記憶模型。 // If the length of the readings and the characters do not match, // it often means it is a special symbol and it should not be stored @@ -234,10 +228,10 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; _walkedNodes.clear(); } -- (string)_currentLayout +- (std::string)_currentLayout { NSString *keyboardLayoutName = Preferences.keyboardLayoutName; - string layout = string(keyboardLayoutName.UTF8String) + string("_"); + std::string layout = std::string(keyboardLayoutName.UTF8String) + std::string("_"); return layout; } @@ -348,7 +342,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; composeReading |= (!_bpmfReadingBuffer->isEmpty() && ([input isSpace] || [input isEnterCharCode] || [input isEnter])); if (composeReading) { // combine the reading - string reading = _bpmfReadingBuffer->syllable().composedString(); + std::string reading = _bpmfReadingBuffer->syllable().composedString(); // see if we have a unigram for this if (!_languageModel->hasUnigramsForKey(reading)) { @@ -365,12 +359,12 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; NSString *poppedText = [self _popOverflowComposingTextAndWalk]; // get user override model suggestion - string overrideValue = (Preferences.useSCPCTypingMode) ? "" : + std::string overrideValue = (Preferences.useSCPCTypingMode) ? "" : _userOverrideModel->suggest(_walkedNodes, _builder->cursorIndex(), [[NSDate date] timeIntervalSince1970]); if (!overrideValue.empty()) { size_t cursorIndex = [self _actualCandidateCursorIndex]; - vector nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); + std::vector nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); double highestScore = FindHighestScore(nodes, kEpsilon); _builder->grid().overrideNodeScoreForSelectedCandidate(cursorIndex, overrideValue, static_cast(highestScore)); } @@ -411,13 +405,13 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; return YES; } - // MARK: Space and Down, plus PageUp / PageDn / PageLeft / PageRight. - // keyCode 125 = Down, charCode 32 = Space - if (_bpmfReadingBuffer->isEmpty() && - [state isKindOfClass:[InputStateNotEmpty class]] && - ([input isExtraChooseCandidateKey] || [input isExtraChooseCandidateKeyReverse] + // MARK: Space and Down, plus PageUp / PageDn / PageLeft / PageRight. + // keyCode 125 = Down, charCode 32 = Space + if (_bpmfReadingBuffer->isEmpty() && + [state isKindOfClass:[InputStateNotEmpty class]] && + ([input isExtraChooseCandidateKey] || [input isExtraChooseCandidateKeyReverse] || [input isSpace] || [input isPageDown] || [input isPageUp] - || (input.useVerticalMode && ([input isVerticalModeOnlyChooseCandidateKey])))) { + || (input.useVerticalMode && ([input isVerticalModeOnlyChooseCandidateKey])))) { if ([input isSpace]) { // if the spacebar is NOT set to be a selection key if ([input isShiftHold] || !Preferences.chooseCandidateUsingSpace) { @@ -521,7 +515,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; InputStateSymbolTable *symbolState = [[InputStateSymbolTable alloc] initWithNode:root useVerticalMode:input.useVerticalMode]; stateCallback(symbolState); return YES; -// if (_languageModel->hasUnigramsForKey(string("_punctuation_list"))) { +// if (_languageModel->hasUnigramsForKey("_punctuation_list"))) { // if (_bpmfReadingBuffer->isEmpty()) { // _builder->insertReadingAtCursor(string("_punctuation_list")); // NSString *poppedText = [self _popOverflowComposingTextAndWalk]; @@ -540,28 +534,30 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; // MARK: Punctuation // if nothing is matched, see if it's a punctuation key for current layout. - string punctuationNamePrefix; + std::string punctuationNamePrefix; if ([input isControlHold]) { - punctuationNamePrefix = string("_ctrl_punctuation_"); + punctuationNamePrefix = std::string("_ctrl_punctuation_"); } else if (Preferences.halfWidthPunctuationEnabled) { - punctuationNamePrefix = string("_half_punctuation_"); + punctuationNamePrefix = std::string("_half_punctuation_"); } else { - punctuationNamePrefix = string("_punctuation_"); + punctuationNamePrefix = std::string("_punctuation_"); } - string layout = [self _currentLayout]; - string customPunctuation = punctuationNamePrefix + layout + string(1, (char) charCode); + std::string layout = [self _currentLayout]; + std::string customPunctuation = punctuationNamePrefix + layout + std::string(1, (char) charCode); if ([self _handlePunctuation:customPunctuation state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) { return YES; } // if nothing is matched, see if it's a punctuation key. - string punctuation = punctuationNamePrefix + string(1, (char) charCode); + std::string punctuation = punctuationNamePrefix + std::string(1, (char) charCode); if ([self _handlePunctuation:punctuation state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) { return YES; } - if ((char) charCode >= 'A' && (char) charCode <= 'Z') { - string letter = string("_letter_") + string(1, (char) charCode); + // Lukhnos 這裡的處理反而會使得 Apple 倚天注音動態鍵盤佈局「敲不了半形大寫英文」的缺點曝露無疑,所以注釋掉。 + // 至於他試圖用這種處理來解決的上游 UPR293 的問題,其實針對詞庫檔案的排序做點手腳就可以解決。威注音本來也就是這麼做的。 + if (/*[state isKindOfClass:[InputStateNotEmpty class]] && */(char) charCode >= 'A' && (char) charCode <= 'Z') { + std::string letter = std::string("_letter_") + std::string(1, (char) charCode); if ([self _handlePunctuation:letter state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) { return YES; } @@ -845,7 +841,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; return YES; } -- (BOOL)_handlePunctuation:(string)customPunctuation state:(InputState *)state usingVerticalMode:(BOOL)useVerticalMode stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback +- (BOOL)_handlePunctuation:(std::string)customPunctuation state:(InputState *)state usingVerticalMode:(BOOL)useVerticalMode stateCallback:(void (^)(InputState *))stateCallback errorCallback:(void (^)(void))errorCallback { if (!_languageModel->hasUnigramsForKey(customPunctuation)) { return NO; @@ -1150,23 +1146,23 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; } if (Preferences.useSCPCTypingMode) { - string layout = [self _currentLayout]; - string punctuationNamePrefix; + std::string layout = [self _currentLayout]; + std::string punctuationNamePrefix; if ([input isControlHold]) { - punctuationNamePrefix = string("_ctrl_punctuation_"); + punctuationNamePrefix = std::string("_ctrl_punctuation_"); } else if (Preferences.halfWidthPunctuationEnabled) { - punctuationNamePrefix = string("_half_punctuation_"); + punctuationNamePrefix = std::string("_half_punctuation_"); } else { - punctuationNamePrefix = string("_punctuation_"); + punctuationNamePrefix = std::string("_punctuation_"); } - string customPunctuation = punctuationNamePrefix + layout + string(1, (char) charCode); - string punctuation = punctuationNamePrefix + string(1, (char) charCode); + std::string customPunctuation = punctuationNamePrefix + layout + std::string(1, (char) charCode); + std::string punctuation = punctuationNamePrefix + std::string(1, (char) charCode); BOOL shouldAutoSelectCandidate = _bpmfReadingBuffer->isValidKey((char) charCode) || _languageModel->hasUnigramsForKey(customPunctuation) || _languageModel->hasUnigramsForKey(punctuation); if (!shouldAutoSelectCandidate && (char) charCode >= 'A' && (char) charCode <= 'Z') { - string letter = string("_letter_") + string(1, (char) charCode); + std::string letter = std::string("_letter_") + std::string(1, (char) charCode); if (_languageModel->hasUnigramsForKey(letter)) { shouldAutoSelectCandidate = YES; } @@ -1206,9 +1202,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; // 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 - for (vector::iterator wi = _walkedNodes.begin(), we = _walkedNodes.end(); wi != we; ++wi) { + for (std::vector::iterator wi = _walkedNodes.begin(), we = _walkedNodes.end(); wi != we; ++wi) { if ((*wi).node) { - string nodeStr = (*wi).node->currentKeyValue().value; + std::string nodeStr = (*wi).node->currentKeyValue().value; NSString *valueString = [NSString stringWithUTF8String:nodeStr.c_str()]; [composingBuffer appendString:valueString]; @@ -1274,7 +1270,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; // retrieve the most likely trellis, i.e. a Maximum Likelihood Estimation // of the best possible Mandarain characters given the input syllables, // using the Viterbi algorithm implemented in the Gramambular library - Walker walker(&_builder->grid()); + Taiyan::Gramambular::Walker walker(&_builder->grid()); // the reverse walk traces the trellis from the end _walkedNodes = walker.reverseWalk(_builder->grid().width()); @@ -1284,7 +1280,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; // if DEBUG is defined, a GraphViz file is written to kGraphVizOutputfile #if DEBUG - string dotDump = _builder->grid().dumpDOT(); + std::string dotDump = _builder->grid().dumpDOT(); NSString *dotStr = [NSString stringWithUTF8String:dotDump.c_str()]; NSError *error = nil; @@ -1307,7 +1303,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; if (_builder->grid().width() > (size_t) composingBufferSize) { if (_walkedNodes.size() > 0) { - NodeAnchor &anchor = _walkedNodes[0]; + Taiyan::Gramambular::NodeAnchor &anchor = _walkedNodes[0]; poppedText = [NSString stringWithUTF8String:anchor.node->currentKeyValue().value.c_str()]; _builder->removeHeadReadings(anchor.spanningLength); } @@ -1322,15 +1318,15 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; NSMutableArray *candidatesArray = [[NSMutableArray alloc] init]; size_t cursorIndex = [self _actualCandidateCursorIndex]; - vector nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); + std::vector nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); // sort the nodes, so that longer nodes (representing longer phrases) are placed at the top of the candidate list stable_sort(nodes.begin(), nodes.end(), NodeAnchorDescendingSorter()); // then use the C++ trick to retrieve the candidates for each node at/crossing the cursor - for (vector::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) { - const vector &candidates = (*ni).node->candidates(); - for (vector::const_iterator ci = candidates.begin(), ce = candidates.end(); ci != ce; ++ci) { + for (std::vector::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) { + const std::vector &candidates = (*ni).node->candidates(); + for (std::vector::const_iterator ci = candidates.begin(), ce = candidates.end(); ci != ce; ++ci) { [candidatesArray addObject:[NSString stringWithUTF8String:(*ci).value.c_str()]]; } } @@ -1359,8 +1355,8 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; - (NSArray *)_currentReadings { NSMutableArray *readingsArray = [[NSMutableArray alloc] init]; - vector v = _builder->readings(); - for (vector::iterator it_i = v.begin(); it_i != v.end(); ++it_i) { + std::vector v = _builder->readings(); + for (std::vector::iterator it_i = v.begin(); it_i != v.end(); ++it_i) { [readingsArray addObject:[NSString stringWithUTF8String:it_i->c_str()]]; } return readingsArray; @@ -1368,9 +1364,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot"; - (nullable InputState *)buildAssociatePhraseStateWithKey:(NSString *)key useVerticalMode:(BOOL)useVerticalMode { - string cppKey = string(key.UTF8String); + std::string cppKey = std::string(key.UTF8String); if (_languageModel->hasAssociatedPhrasesForKey(cppKey)) { - vector phrases = _languageModel->associatedPhrasesForKey(cppKey); + std::vector phrases = _languageModel->associatedPhrasesForKey(cppKey); NSMutableArray *array = [NSMutableArray array]; for (auto phrase: phrases) { NSString *item = [[NSString alloc] initWithUTF8String:phrase.c_str()]; diff --git a/Source/Modules/FileHandlers/LMConsolidator.h b/Source/Modules/FileHandlers/LMConsolidator.h index 1007c92b..3dd481ca 100644 --- a/Source/Modules/FileHandlers/LMConsolidator.h +++ b/Source/Modules/FileHandlers/LMConsolidator.h @@ -37,7 +37,7 @@ class LMConsolidator public: static bool CheckPragma(const char *path); static bool FixEOF(const char *path); - static bool ConsolidateContent(const char *path, bool shouldsort); + static bool ConsolidateContent(const char *path, bool shouldsort, bool shouldCheckPragma); }; } // namespace vChewing diff --git a/Source/Modules/FileHandlers/LMConsolidator.mm b/Source/Modules/FileHandlers/LMConsolidator.mm index 7cd0f147..d3350e2f 100644 --- a/Source/Modules/FileHandlers/LMConsolidator.mm +++ b/Source/Modules/FileHandlers/LMConsolidator.mm @@ -71,8 +71,8 @@ bool LMConsolidator::FixEOF(const char *path) } // END: EOF FIXER. // CONTENT CONSOLIDATOR. CREDIT: Shiki Suen. -bool LMConsolidator::ConsolidateContent(const char *path, bool shouldsort) { - if (LMConsolidator::CheckPragma(path) && !shouldsort){ +bool LMConsolidator::ConsolidateContent(const char *path, bool shouldsort, bool shouldCheckPragma) { + if (LMConsolidator::CheckPragma(path) && !shouldsort && shouldCheckPragma){ return true; } diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index ed0a0b0f..48af8aa4 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -47,6 +47,13 @@ class ctlInputMethod: IMKInputController { private var keyHandler: KeyHandler = KeyHandler() private var state: InputState = InputState.Empty() + // 想讓 keyHandler 能夠被外界調查狀態與參數的話,就得對 keyHandler 做常態處理。 + // 這樣 InputState 可以藉由這個 ctlInputMethod 了解到當前的輸入模式是簡體中文還是繁體中文。 + // 然而,要是直接對 keyHandler 做常態處理的話,反而會導致 keyHandlerInput 無法協同處理。 + // 所以才需要「currentKeyHandler」這個假 keyHandler。 + // 這個「currentKeyHandler」僅用來讓其他模組知道當前的輸入模式是什麼模式,除此之外別無屌用。 + static var currentKeyHandler: KeyHandler = KeyHandler() + // MARK: - IMKInputController methods override init!(server: IMKServer!, delegate: Any!, client inputClient: Any!) { @@ -157,6 +164,8 @@ class ctlInputMethod: IMKInputController { keyHandler.inputMode = newInputMode self.handle(state: .Empty(), client: client) } + // 讓外界知道目前的簡繁體輸入模式。 + ctlInputMethod.currentKeyHandler.inputMode = keyHandler.inputMode } // MARK: - IMKServerInput protocol methods @@ -603,7 +612,7 @@ extension ctlInputMethod: KeyHandlerDelegate { if !state.validToWrite { return false } - mgrLangModel.writeUserPhrase(state.userPhrase, inputMode: keyHandler.inputMode) + mgrLangModel.writeUserPhrase(state.userPhrase, inputMode: keyHandler.inputMode, areWeDuplicating: state.chkIfUserPhraseExists) return true } } diff --git a/Source/Modules/LangModelRelated/vChewingLM.h b/Source/Modules/LangModelRelated/LMInstantiator.h similarity index 82% rename from Source/Modules/LangModelRelated/vChewingLM.h rename to Source/Modules/LangModelRelated/LMInstantiator.h index 6ab58fa2..d4f49eb9 100644 --- a/Source/Modules/LangModelRelated/vChewingLM.h +++ b/Source/Modules/LangModelRelated/LMInstantiator.h @@ -17,22 +17,22 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef VCHEWINGLM_H -#define VCHEWINGLM_H +#ifndef LMInstantiator_H +#define LMInstantiator_H -#include -#include "UserPhrasesLM.h" -#include "ParselessLM.h" -#include "CNSLM.h" -#include "PhraseReplacementMap.h" #include "AssociatedPhrases.h" +#include "CNSLM.h" +#include "ParselessLM.h" +#include "PhraseReplacementMap.h" +#include "UserPhrasesLM.h" +#include #include namespace vChewing { using namespace Taiyan::Gramambular; -/// vChewingLM is a facade for managing a set of models including +/// LMInstantiator is a facade for managing a set of models including /// the input method language model, user phrases and excluded phrases. /// /// It is the primary model class that the input controller and grammar builder @@ -41,7 +41,7 @@ using namespace Taiyan::Gramambular; /// if there are valid unigrams, and use returned unigrams to produce the final /// results. /// -/// vChewingLM combine and transform the unigrams from the primary language +/// LMInstantiator combine and transform the unigrams from the primary language /// model and user phrases. The process is /// /// 1) Get the original unigrams. @@ -54,10 +54,10 @@ using namespace Taiyan::Gramambular; /// model while launching and to load the user phrases anytime if the custom /// files are modified. It does not keep the reference of the data pathes but /// you have to pass the paths when you ask it to do loading. -class vChewingLM : public LanguageModel { +class LMInstantiator : public Taiyan::Gramambular::LanguageModel { public: - vChewingLM(); - ~vChewingLM(); + LMInstantiator(); + ~LMInstantiator(); /// Asks to load the primary language model at the given path. /// @param languageModelPath The path of the language model. @@ -83,14 +83,14 @@ public: void loadPhraseReplacementMap(const char* phraseReplacementPath); /// Not implemented since we do not have data to provide bigram function. - const vector bigramsForKeys(const string& preceedingKey, const string& key); + const std::vector bigramsForKeys(const std::string& preceedingKey, const std::string& key); /// Returns a list of available unigram for the given key. - /// @param key A string represents the BPMF reading or a symbol key. For + /// @param key A std::string represents the BPMF reading or a symbol key. For /// example, it you pass "ㄇㄚ", it returns "嗎", "媽", and so on. - const vector unigramsForKey(const string& key); + const std::vector unigramsForKey(const std::string& key); /// If the model has unigrams for the given key. /// @param key The key. - bool hasUnigramsForKey(const string& key); + bool hasUnigramsForKey(const std::string& key); /// Enables or disables phrase replacement. void setPhraseReplacementEnabled(bool enabled); @@ -107,10 +107,10 @@ public: /// If the external converted is enabled or not. bool externalConverterEnabled(); /// Sets a lambda to let the values of unigrams could be converted by it. - void setExternalConverter(std::function externalConverter); + void setExternalConverter(std::function externalConverter); - const vector associatedPhrasesForKey(const string& key); - bool hasAssociatedPhrasesForKey(const string& key); + const std::vector associatedPhrasesForKey(const std::string& key); + bool hasAssociatedPhrasesForKey(const std::string& key); protected: @@ -121,9 +121,9 @@ protected: /// @param insertedValues The values for unigrams already in the results. /// It helps to prevent duplicated unigrams. Please note that the method /// has a side effect that it inserts values to `insertedValues`. - const vector filterAndTransformUnigrams(const vector unigrams, - const std::unordered_set& excludedValues, - std::unordered_set& insertedValues); + const std::vector filterAndTransformUnigrams(const std::vector unigrams, + const std::unordered_set& excludedValues, + std::unordered_set& insertedValues); ParselessLM m_languageModel; CNSLM m_cnsModel; @@ -134,7 +134,7 @@ protected: bool m_phraseReplacementEnabled; bool m_cnsEnabled; bool m_externalConverterEnabled; - std::function m_externalConverter; + std::function m_externalConverter; }; }; diff --git a/Source/Modules/LangModelRelated/vChewingLM.mm b/Source/Modules/LangModelRelated/LMInstantiator.mm similarity index 62% rename from Source/Modules/LangModelRelated/vChewingLM.mm rename to Source/Modules/LangModelRelated/LMInstantiator.mm index 99f6a2e3..871206d7 100644 --- a/Source/Modules/LangModelRelated/vChewingLM.mm +++ b/Source/Modules/LangModelRelated/LMInstantiator.mm @@ -17,17 +17,17 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "vChewingLM.h" +#include "LMInstantiator.h" #include #include -using namespace vChewing; +namespace vChewing { -vChewingLM::vChewingLM() +LMInstantiator::LMInstantiator() { } -vChewingLM::~vChewingLM() +LMInstantiator::~LMInstantiator() { m_languageModel.close(); m_userPhrases.close(); @@ -37,7 +37,7 @@ vChewingLM::~vChewingLM() m_associatedPhrases.close(); } -void vChewingLM::loadLanguageModel(const char* languageModelDataPath) +void LMInstantiator::loadLanguageModel(const char* languageModelDataPath) { if (languageModelDataPath) { m_languageModel.close(); @@ -45,12 +45,12 @@ void vChewingLM::loadLanguageModel(const char* languageModelDataPath) } } -bool vChewingLM::isDataModelLoaded() +bool LMInstantiator::isDataModelLoaded() { return m_languageModel.isLoaded(); } -void vChewingLM::loadCNSData(const char* cnsDataPath) +void LMInstantiator::loadCNSData(const char* cnsDataPath) { if (cnsDataPath) { m_cnsModel.close(); @@ -58,12 +58,12 @@ void vChewingLM::loadCNSData(const char* cnsDataPath) } } -bool vChewingLM::isCNSDataLoaded() +bool LMInstantiator::isCNSDataLoaded() { return m_cnsModel.isLoaded(); } -void vChewingLM::loadUserPhrases(const char* userPhrasesDataPath, +void LMInstantiator::loadUserPhrases(const char* userPhrasesDataPath, const char* excludedPhrasesDataPath) { if (userPhrasesDataPath) { @@ -76,7 +76,7 @@ void vChewingLM::loadUserPhrases(const char* userPhrasesDataPath, } } -void vChewingLM::loadUserAssociatedPhrases(const char *userAssociatedPhrasesPath) +void LMInstantiator::loadUserAssociatedPhrases(const char *userAssociatedPhrasesPath) { if (userAssociatedPhrasesPath) { m_associatedPhrases.close(); @@ -84,7 +84,7 @@ void vChewingLM::loadUserAssociatedPhrases(const char *userAssociatedPhrasesPath } } -void vChewingLM::loadPhraseReplacementMap(const char* phraseReplacementPath) +void LMInstantiator::loadPhraseReplacementMap(const char* phraseReplacementPath) { if (phraseReplacementPath) { m_phraseReplacement.close(); @@ -92,49 +92,49 @@ void vChewingLM::loadPhraseReplacementMap(const char* phraseReplacementPath) } } -const vector vChewingLM::bigramsForKeys(const string& preceedingKey, const string& key) +const std::vector LMInstantiator::bigramsForKeys(const std::string& preceedingKey, const std::string& key) { - return vector(); + return std::vector(); } -const vector vChewingLM::unigramsForKey(const string& key) +const std::vector LMInstantiator::unigramsForKey(const std::string& key) { if (key == " ") { - vector spaceUnigrams; - Unigram g; + std::vector spaceUnigrams; + Taiyan::Gramambular::Unigram g; g.keyValue.key = " "; - g.keyValue.value= " "; + g.keyValue.value = " "; g.score = 0; spaceUnigrams.push_back(g); return spaceUnigrams; } - vector allUnigrams; - vector userUnigrams; - vector cnsUnigrams; + std::vector allUnigrams; + std::vector userUnigrams; + std::vector cnsUnigrams; - unordered_set excludedValues; - unordered_set insertedValues; + std::unordered_set excludedValues; + std::unordered_set insertedValues; if (m_excludedPhrases.hasUnigramsForKey(key)) { - vector excludedUnigrams = m_excludedPhrases.unigramsForKey(key); + std::vector excludedUnigrams = m_excludedPhrases.unigramsForKey(key); transform(excludedUnigrams.begin(), excludedUnigrams.end(), inserter(excludedValues, excludedValues.end()), - [](const Unigram& u) { return u.keyValue.value; }); + [](const Taiyan::Gramambular::Unigram& u) { return u.keyValue.value; }); } if (m_userPhrases.hasUnigramsForKey(key)) { - vector rawUserUnigrams = m_userPhrases.unigramsForKey(key); + std::vector rawUserUnigrams = m_userPhrases.unigramsForKey(key); userUnigrams = filterAndTransformUnigrams(rawUserUnigrams, excludedValues, insertedValues); } if (m_languageModel.hasUnigramsForKey(key)) { - vector rawGlobalUnigrams = m_languageModel.unigramsForKey(key); + std::vector rawGlobalUnigrams = m_languageModel.unigramsForKey(key); allUnigrams = filterAndTransformUnigrams(rawGlobalUnigrams, excludedValues, insertedValues); } if (m_cnsModel.hasUnigramsForKey(key) && m_cnsEnabled) { - vector rawCNSUnigrams = m_cnsModel.unigramsForKey(key); + std::vector rawCNSUnigrams = m_cnsModel.unigramsForKey(key); cnsUnigrams = filterAndTransformUnigrams(rawCNSUnigrams, excludedValues, insertedValues); } @@ -143,7 +143,7 @@ const vector vChewingLM::unigramsForKey(const string& key) return allUnigrams; } -bool vChewingLM::hasUnigramsForKey(const string& key) +bool LMInstantiator::hasUnigramsForKey(const std::string& key) { if (key == " ") { return true; @@ -156,65 +156,65 @@ bool vChewingLM::hasUnigramsForKey(const string& key) return unigramsForKey(key).size() > 0; } -void vChewingLM::setPhraseReplacementEnabled(bool enabled) +void LMInstantiator::setPhraseReplacementEnabled(bool enabled) { m_phraseReplacementEnabled = enabled; } -bool vChewingLM::phraseReplacementEnabled() +bool LMInstantiator::phraseReplacementEnabled() { return m_phraseReplacementEnabled; } -void vChewingLM::setCNSEnabled(bool enabled) +void LMInstantiator::setCNSEnabled(bool enabled) { m_cnsEnabled = enabled; } -bool vChewingLM::cnsEnabled() +bool LMInstantiator::cnsEnabled() { return m_cnsEnabled; } -void vChewingLM::setExternalConverterEnabled(bool enabled) +void LMInstantiator::setExternalConverterEnabled(bool enabled) { m_externalConverterEnabled = enabled; } -bool vChewingLM::externalConverterEnabled() +bool LMInstantiator::externalConverterEnabled() { return m_externalConverterEnabled; } -void vChewingLM::setExternalConverter(std::function externalConverter) +void LMInstantiator::setExternalConverter(std::function externalConverter) { m_externalConverter = externalConverter; } -const vector vChewingLM::filterAndTransformUnigrams(const vector unigrams, const unordered_set& excludedValues, unordered_set& insertedValues) +const std::vector LMInstantiator::filterAndTransformUnigrams(const std::vector unigrams, const std::unordered_set& excludedValues, std::unordered_set& insertedValues) { - vector results; + std::vector results; for (auto&& unigram : unigrams) { // excludedValues filters out the unigrams with the original value. // insertedValues filters out the ones with the converted value - string originalValue = unigram.keyValue.value; + std::string originalValue = unigram.keyValue.value; if (excludedValues.find(originalValue) != excludedValues.end()) { continue; } - string value = originalValue; + std::string value = originalValue; if (m_phraseReplacementEnabled) { - string replacement = m_phraseReplacement.valueForKey(value); + std::string replacement = m_phraseReplacement.valueForKey(value); if (replacement != "") { value = replacement; } } if (m_externalConverterEnabled && m_externalConverter) { - string replacement = m_externalConverter(value); + std::string replacement = m_externalConverter(value); value = replacement; } if (insertedValues.find(value) == insertedValues.end()) { - Unigram g; + Taiyan::Gramambular::Unigram g; g.keyValue.value = value; g.keyValue.key = unigram.keyValue.key; g.score = unigram.score; @@ -225,12 +225,14 @@ const vector vChewingLM::filterAndTransformUnigrams(const vector vChewingLM::associatedPhrasesForKey(const string& key) +const std::vector LMInstantiator::associatedPhrasesForKey(const std::string& key) { return m_associatedPhrases.valuesForKey(key); } -bool vChewingLM::hasAssociatedPhrasesForKey(const string& key) +bool LMInstantiator::hasAssociatedPhrasesForKey(const std::string& key) { return m_associatedPhrases.hasValuesForKey(key); } + +} // namespace vChewing diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/AssociatedPhrases.mm b/Source/Modules/LangModelRelated/SubLanguageModels/AssociatedPhrases.mm index 53ae599a..4970f8a3 100644 --- a/Source/Modules/LangModelRelated/SubLanguageModels/AssociatedPhrases.mm +++ b/Source/Modules/LangModelRelated/SubLanguageModels/AssociatedPhrases.mm @@ -59,12 +59,7 @@ bool AssociatedPhrases::open(const char *path) } LMConsolidator::FixEOF(path); - - if (Preferences.shouldAutoSortAssociatedPhrasesOnLoad) { - LMConsolidator::ConsolidateContent(path, true); - } else { - LMConsolidator::ConsolidateContent(path, false); - } + LMConsolidator::ConsolidateContent(path, Preferences.shouldAutoSortAssociatedPhrasesOnLoad, true); fd = ::open(path, O_RDONLY); if (fd == -1) { diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.h b/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.h index 661cfe15..178ee21a 100644 --- a/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.h +++ b/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.h @@ -45,8 +45,8 @@ public: void close(); void dump(); - virtual const vector bigramsForKeys(const string& preceedingKey, const string& key); - virtual const vector unigramsForKey(const string& key); + virtual const std::vector bigramsForKeys(const string& preceedingKey, const string& key); + virtual const std::vector unigramsForKey(const string& key); virtual bool hasUnigramsForKey(const string& key); protected: diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.mm b/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.mm index 14d6cd63..683106ce 100644 --- a/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.mm +++ b/Source/Modules/LangModelRelated/SubLanguageModels/CoreLM.mm @@ -281,14 +281,14 @@ void vChewing::CoreLM::dump() } } -const vector vChewing::CoreLM::bigramsForKeys(const string& preceedingKey, const string& key) +const std::vector vChewing::CoreLM::bigramsForKeys(const string& preceedingKey, const string& key) { - return vector(); + return std::vector(); } -const vector vChewing::CoreLM::unigramsForKey(const string& key) +const std::vector vChewing::CoreLM::unigramsForKey(const string& key) { - vector v; + std::vector v; map >::const_iterator i = keyRowMap.find(key.c_str()); if (i != keyRowMap.end()) { diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/PhraseReplacementMap.mm b/Source/Modules/LangModelRelated/SubLanguageModels/PhraseReplacementMap.mm index 67aa2870..64d2071e 100644 --- a/Source/Modules/LangModelRelated/SubLanguageModels/PhraseReplacementMap.mm +++ b/Source/Modules/LangModelRelated/SubLanguageModels/PhraseReplacementMap.mm @@ -54,12 +54,7 @@ bool PhraseReplacementMap::open(const char *path) } LMConsolidator::FixEOF(path); - - if (Preferences.shouldAutoSortPhraseReplacementMapOnLoad) { - LMConsolidator::ConsolidateContent(path, true); - } else { - LMConsolidator::ConsolidateContent(path, false); - } + LMConsolidator::ConsolidateContent(path, Preferences.shouldAutoSortPhraseReplacementMapOnLoad, true); fd = ::open(path, O_RDONLY); if (fd == -1) { diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.cpp b/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.cpp index 9571176c..2e0a7096 100644 --- a/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.cpp +++ b/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.cpp @@ -23,7 +23,7 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH #include #include -using namespace vChewing; +namespace vChewing { // About 20 generations. static const double DecayThreshould = 1.0 / 1048576.0; @@ -33,8 +33,8 @@ static double Score(size_t eventCount, double eventTimestamp, double timestamp, double lambda); -static bool IsEndingPunctuation(const string& value); -static string WalkedNodesToKey(const std::vector& walkedNodes, +static bool IsEndingPunctuation(const std::string& value); +static std::string WalkedNodesToKey(const std::vector& walkedNodes, size_t cursorIndex); UserOverrideModel::UserOverrideModel(size_t capacity, double decayConstant) @@ -43,11 +43,11 @@ UserOverrideModel::UserOverrideModel(size_t capacity, double decayConstant) m_decayExponent = log(0.5) / decayConstant; } -void UserOverrideModel::observe(const std::vector& walkedNodes, +void UserOverrideModel::observe(const std::vector& walkedNodes, size_t cursorIndex, - const string& candidate, + const std::string& candidate, double timestamp) { - string key = WalkedNodesToKey(walkedNodes, cursorIndex); + std::string key = WalkedNodesToKey(walkedNodes, cursorIndex); auto mapIter = m_lruMap.find(key); if (mapIter == m_lruMap.end()) { auto keyValuePair = KeyObservationPair(key, Observation()); @@ -76,20 +76,20 @@ void UserOverrideModel::observe(const std::vector& walkedNodes, } } -string UserOverrideModel::suggest(const std::vector& walkedNodes, +std::string UserOverrideModel::suggest(const std::vector& walkedNodes, size_t cursorIndex, double timestamp) { - string key = WalkedNodesToKey(walkedNodes, cursorIndex); + std::string key = WalkedNodesToKey(walkedNodes, cursorIndex); auto mapIter = m_lruMap.find(key); if (mapIter == m_lruMap.end()) { - return string(); + return std::string(); } auto listIter = mapIter->second; auto& keyValuePair = *listIter; const Observation& observation = keyValuePair.second; - string candidate; + std::string candidate; double score = 0.0; for (auto i = observation.overrides.begin(); i != observation.overrides.end(); @@ -112,7 +112,7 @@ string UserOverrideModel::suggest(const std::vector& walkedNodes, return candidate; } -void UserOverrideModel::Observation::update(const string& candidate, +void UserOverrideModel::Observation::update(const std::string& candidate, double timestamp) { count++; auto& o = overrides[candidate]; @@ -134,16 +134,16 @@ static double Score(size_t eventCount, return prob * decay; } -static bool IsEndingPunctuation(const string& value) { +static bool IsEndingPunctuation(const std::string& value) { return value == "," || value == "。" || value== "!" || value == "?" || value == "」" || value == "』" || value== "”" || value == "’"; } -static string WalkedNodesToKey(const std::vector& walkedNodes, +static std::string WalkedNodesToKey(const std::vector& walkedNodes, size_t cursorIndex) { std::stringstream s; - std::vector n; + std::vector n; size_t ll = 0; - for (std::vector::const_iterator i = walkedNodes.begin(); + for (std::vector::const_iterator i = walkedNodes.begin(); i != walkedNodes.end(); ++i) { const auto& nn = *i; @@ -154,19 +154,19 @@ static string WalkedNodesToKey(const std::vector& walkedNodes, } } - std::vector::const_reverse_iterator r = n.rbegin(); + std::vector::const_reverse_iterator r = n.rbegin(); if (r == n.rend()) { return ""; } - string current = (*r).node->currentKeyValue().key; + std::string current = (*r).node->currentKeyValue().key; ++r; s.clear(); s.str(std::string()); if (r != n.rend()) { - string value = (*r).node->currentKeyValue().value; + std::string value = (*r).node->currentKeyValue().value; if (IsEndingPunctuation(value)) { s << "()"; r = n.rend(); @@ -181,12 +181,12 @@ static string WalkedNodesToKey(const std::vector& walkedNodes, } else { s << "()"; } - string prev = s.str(); + std::string prev = s.str(); s.clear(); s.str(std::string()); if (r != n.rend()) { - string value = (*r).node->currentKeyValue().value; + std::string value = (*r).node->currentKeyValue().value; if (IsEndingPunctuation(value)) { s << "()"; r = n.rend(); @@ -201,7 +201,7 @@ static string WalkedNodesToKey(const std::vector& walkedNodes, } else { s << "()"; } - string anterior = s.str(); + std::string anterior = s.str(); s.clear(); s.str(std::string()); @@ -209,3 +209,5 @@ static string WalkedNodesToKey(const std::vector& walkedNodes, return s.str(); } + +} // namespace vChewing diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.h b/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.h index aed9992e..7189f5d2 100644 --- a/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.h +++ b/Source/Modules/LangModelRelated/SubLanguageModels/UserOverrideModel.h @@ -22,7 +22,6 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH #include #include -#include #include "Gramambular.h" @@ -34,12 +33,12 @@ class UserOverrideModel { public: UserOverrideModel(size_t capacity, double decayConstant); - void observe(const std::vector& walkedNodes, + void observe(const std::vector& walkedNodes, size_t cursorIndex, - const string& candidate, + const std::string& candidate, double timestamp); - string suggest(const std::vector& walkedNodes, + std::string suggest(const std::vector& walkedNodes, size_t cursorIndex, double timestamp); @@ -56,7 +55,7 @@ private: std::map overrides; Observation() : count(0) {} - void update(const string& candidate, double timestamp); + void update(const std::string& candidate, double timestamp); }; typedef std::pair KeyObservationPair; @@ -67,7 +66,7 @@ private: std::map::iterator> m_lruMap; }; -}; // namespace vChewing +}; // namespace vChewing #endif diff --git a/Source/Modules/LangModelRelated/SubLanguageModels/UserPhrasesLM.mm b/Source/Modules/LangModelRelated/SubLanguageModels/UserPhrasesLM.mm index 2219117d..f23206f8 100644 --- a/Source/Modules/LangModelRelated/SubLanguageModels/UserPhrasesLM.mm +++ b/Source/Modules/LangModelRelated/SubLanguageModels/UserPhrasesLM.mm @@ -60,12 +60,7 @@ bool UserPhrasesLM::open(const char *path) } LMConsolidator::FixEOF(path); - - if (Preferences.shouldAutoSortUserPhrasesAndExclListOnLoad) { - LMConsolidator::ConsolidateContent(path, true); - } else { - LMConsolidator::ConsolidateContent(path, false); - } + LMConsolidator::ConsolidateContent(path, Preferences.shouldAutoSortUserPhrasesAndExclListOnLoad, true); fd = ::open(path, O_RDONLY); if (fd == -1) { diff --git a/Source/Modules/LangModelRelated/mgrLangModel.h b/Source/Modules/LangModelRelated/mgrLangModel.h index 5a7ac5e7..0aa14424 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel.h +++ b/Source/Modules/LangModelRelated/mgrLangModel.h @@ -32,8 +32,8 @@ NS_ASSUME_NONNULL_BEGIN + (BOOL)checkIfUserLanguageModelFilesExist; + (BOOL)checkIfUserDataFolderExists; -+ (BOOL)checkIfUserPhraseExist:(NSString *)userPhrase key:(NSString *)key NS_SWIFT_NAME(checkIfExist(userPhrase:key:)); -+ (BOOL)writeUserPhrase:(NSString *)userPhrase inputMode:(InputMode)mode; ++ (BOOL)checkIfUserPhraseExist:(NSString *)userPhrase inputMode:(InputMode)mode key:(NSString *)key NS_SWIFT_NAME(checkIfUserPhraseExist(userPhrase:mode:key:)); ++ (BOOL)writeUserPhrase:(NSString *)userPhrase inputMode:(InputMode)mode areWeDuplicating:(BOOL)areWeDuplicating; + (void)setPhraseReplacementEnabled:(BOOL)phraseReplacementEnabled; + (void)setCNSEnabled:(BOOL)cnsEnabled; + (NSString *)userPhrasesDataPath:(InputMode)mode; diff --git a/Source/Modules/LangModelRelated/mgrLangModel.mm b/Source/Modules/LangModelRelated/mgrLangModel.mm index e950c1e6..2564a8e5 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel.mm +++ b/Source/Modules/LangModelRelated/mgrLangModel.mm @@ -20,17 +20,15 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH #import "mgrLangModel.h" #import "mgrLangModel_Privates.h" #import "vChewing-Swift.h" - -using namespace std; -using namespace vChewing; +#import "LMConsolidator.h" static const int kUserOverrideModelCapacity = 500; static const double kObservedOverrideHalflife = 5400.0; -static vChewingLM gLangModelCHT; -static vChewingLM gLangModelCHS; -static UserOverrideModel gUserOverrideModelCHT(kUserOverrideModelCapacity, kObservedOverrideHalflife); -static UserOverrideModel gUserOverrideModelCHS(kUserOverrideModelCapacity, kObservedOverrideHalflife); +static vChewing::LMInstantiator gLangModelCHT; +static vChewing::LMInstantiator gLangModelCHS; +static vChewing::UserOverrideModel gUserOverrideModelCHT(kUserOverrideModelCapacity, kObservedOverrideHalflife); +static vChewing::UserOverrideModel gUserOverrideModelCHS(kUserOverrideModelCapacity, kObservedOverrideHalflife); static NSString *const kUserDataTemplateName = @"template-data"; static NSString *const kUserAssDataTemplateName = @"template-data"; @@ -40,7 +38,7 @@ static NSString *const kTemplateExtension = @".txt"; @implementation mgrLangModel -static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewingLM &lm) +static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing::LMInstantiator &lm) { Class cls = NSClassFromString(@"ctlInputMethod"); NSString *dataPath = [[NSBundle bundleForClass:cls] pathForResource:filenameWithoutExtension ofType:@"txt"]; @@ -206,10 +204,10 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing return YES; } -+ (BOOL)checkIfUserPhraseExist:(NSString *)userPhrase key:(NSString *)key NS_SWIFT_NAME(checkIfExist(userPhrase:key:)) ++ (BOOL)checkIfUserPhraseExist:(NSString *)userPhrase inputMode:(InputMode)mode key:(NSString *)key NS_SWIFT_NAME(checkIfUserPhraseExist(userPhrase:mode:key:)) { string unigramKey = string(key.UTF8String); - vector unigrams = gLangModelCHT.unigramsForKey(unigramKey); + vector unigrams = [mode isEqualToString:imeModeCHT] ? gLangModelCHT.unigramsForKey(unigramKey): gLangModelCHS.unigramsForKey(unigramKey); string userPhraseString = string(userPhrase.UTF8String); for (auto unigram: unigrams) { if (unigram.keyValue.value == userPhraseString) { @@ -219,7 +217,7 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing return NO; } -+ (BOOL)writeUserPhrase:(NSString *)userPhrase inputMode:(InputMode)mode; ++ (BOOL)writeUserPhrase:(NSString *)userPhrase inputMode:(InputMode)mode areWeDuplicating:(BOOL)areWeDuplicating { if (![self checkIfUserLanguageModelFilesExist]) { return NO; @@ -251,6 +249,11 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing // [currentMarkedPhrase appendString:@"\n"]; // } [currentMarkedPhrase appendString:userPhrase]; + if (areWeDuplicating) { + // Do not use ASCII characters to comment here. + // Otherwise, it will be scrambled by HYPY2BPMF module shipped in the vChewing Phrase Editor. + [currentMarkedPhrase appendString:@"\t#𝙾𝚟𝚎𝚛𝚛𝚒𝚍𝚎"]; + } [currentMarkedPhrase appendString:@"\n"]; NSFileHandle *writeFile = [NSFileHandle fileHandleForUpdatingAtPath:path]; @@ -262,9 +265,14 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing [writeFile writeData:data]; [writeFile closeFile]; -// We use FSEventStream to monitor the change of the user phrase folder, -// so we don't have to load data here. -// [self loadUserPhrases]; + // We enforce the format consolidation here, since the pragma header will let the UserPhraseLM bypasses the consolidating process on load. + vChewing::LMConsolidator::ConsolidateContent([path UTF8String], Preferences.shouldAutoSortUserPhrasesAndExclListOnLoad, false); + + // We use FSEventStream to monitor the change of the user phrase folder, + // so we don't have to load data here unless FSEventStream is disabled by user. + if (!Preferences.shouldAutoReloadUserDataFiles) { + [self loadUserPhrases]; + } return YES; } @@ -306,12 +314,12 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing return [[NSBundle bundleForClass:cls] pathForResource:@"char-kanji-cns" ofType:@"txt"]; } - + (vChewingLM *)lmCHT + + (vChewing::LMInstantiator *)lmCHT { return &gLangModelCHT; } -+ (vChewingLM *)lmCHS ++ (vChewing::LMInstantiator *)lmCHS { return &gLangModelCHS; } diff --git a/Source/Modules/LangModelRelated/mgrLangModel_Privates.h b/Source/Modules/LangModelRelated/mgrLangModel_Privates.h index 49cd0de8..22077d25 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel_Privates.h +++ b/Source/Modules/LangModelRelated/mgrLangModel_Privates.h @@ -19,13 +19,13 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH #import "mgrLangModel.h" #import "UserOverrideModel.h" -#import "vChewingLM.h" +#import "LMInstantiator.h" NS_ASSUME_NONNULL_BEGIN @interface mgrLangModel () -@property (class, readonly, nonatomic) vChewing::vChewingLM *lmCHT; -@property (class, readonly, nonatomic) vChewing::vChewingLM *lmCHS; +@property (class, readonly, nonatomic) vChewing::LMInstantiator *lmCHT; +@property (class, readonly, nonatomic) vChewing::LMInstantiator *lmCHS; @property (class, readonly, nonatomic) vChewing::UserOverrideModel *userOverrideModelCHS; @property (class, readonly, nonatomic) vChewing::UserOverrideModel *userOverrideModelCHT; @end diff --git a/Source/Modules/LanguageParsers/Gramambular/Bigram.h b/Source/Modules/LanguageParsers/Gramambular/Bigram.h index 3f232750..5995238d 100644 --- a/Source/Modules/LanguageParsers/Gramambular/Bigram.h +++ b/Source/Modules/LanguageParsers/Gramambular/Bigram.h @@ -17,82 +17,77 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef Bigram_h -#define Bigram_h +#ifndef BIGRAM_H_ +#define BIGRAM_H_ #include #include "KeyValuePair.h" namespace Taiyan { - namespace Gramambular { - class Bigram { - public: - Bigram(); - - KeyValuePair preceedingKeyValue; - KeyValuePair keyValue; - double score; - - bool operator==(const Bigram& inAnother) const; - bool operator<(const Bigram& inAnother) const; - }; +namespace Gramambular { +class Bigram { +public: + Bigram(); + + KeyValuePair preceedingKeyValue; + KeyValuePair keyValue; + double score; + + bool operator==(const Bigram& another) const; + bool operator<(const Bigram& another) const; +}; - inline ostream& operator<<(ostream& inStream, const Bigram& inGram) - { - streamsize p = inStream.precision(); - inStream.precision(6); - inStream << "(" << inGram.keyValue << "|" <& inGrams) - { - inStream << "[" << inGrams.size() << "]=>{"; - - size_t index = 0; - - for (vector::const_iterator gi = inGrams.begin() ; gi != inGrams.end() ; ++gi, ++index) { - inStream << index << "=>"; - inStream << *gi; - if (gi + 1 != inGrams.end()) { - inStream << ","; - } - } - - inStream << "}"; - return inStream; - } - - inline Bigram::Bigram() - : score(0.0) - { - } - - inline bool Bigram::operator==(const Bigram& inAnother) const - { - return preceedingKeyValue == inAnother.preceedingKeyValue && keyValue == inAnother.keyValue && score == inAnother.score; - } - - inline bool Bigram::operator<(const Bigram& inAnother) const - { - if (preceedingKeyValue < inAnother.preceedingKeyValue) { - return true; - } - else if (preceedingKeyValue == inAnother.preceedingKeyValue) { - if (keyValue < inAnother.keyValue) { - return true; - } - else if (keyValue == inAnother.keyValue) { - return score < inAnother.score; - } - return false; - } - - return false; - } - } +inline std::ostream& operator<<(std::ostream& stream, const Bigram& gram) { + std::streamsize p = stream.precision(); + stream.precision(6); + stream << "(" << gram.keyValue << "|" << gram.preceedingKeyValue << "," + << gram.score << ")"; + stream.precision(p); + return stream; } +inline std::ostream& operator<<(std::ostream& stream, + const std::vector& grams) { + stream << "[" << grams.size() << "]=>{"; + + size_t index = 0; + + for (std::vector::const_iterator gi = grams.begin(); + gi != grams.end(); ++gi, ++index) { + stream << index << "=>"; + stream << *gi; + if (gi + 1 != grams.end()) { + stream << ","; + } + } + + stream << "}"; + return stream; +} + +inline Bigram::Bigram() : score(0.0) {} + +inline bool Bigram::operator==(const Bigram& another) const { + return preceedingKeyValue == another.preceedingKeyValue && + keyValue == another.keyValue && score == another.score; +} + +inline bool Bigram::operator<(const Bigram& another) const { + if (preceedingKeyValue < another.preceedingKeyValue) { + return true; + } else if (preceedingKeyValue == another.preceedingKeyValue) { + if (keyValue < another.keyValue) { + return true; + } else if (keyValue == another.keyValue) { + return score < another.score; + } + return false; + } + + return false; +} +} // namespace Gramambular +} // namespace Taiyan + #endif diff --git a/Source/Modules/LanguageParsers/Gramambular/BlockReadingBuilder.h b/Source/Modules/LanguageParsers/Gramambular/BlockReadingBuilder.h index 039a7f88..07fc9add 100644 --- a/Source/Modules/LanguageParsers/Gramambular/BlockReadingBuilder.h +++ b/Source/Modules/LanguageParsers/Gramambular/BlockReadingBuilder.h @@ -17,202 +17,190 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef BlockReadingBuilder_h -#define BlockReadingBuilder_h +#ifndef BLOCKREADINGBUILDER_H_ +#define BLOCKREADINGBUILDER_H_ +#include #include + #include "Grid.h" #include "LanguageModel.h" namespace Taiyan { - namespace Gramambular { - using namespace std; - - class BlockReadingBuilder { - public: - BlockReadingBuilder(LanguageModel *inLM); - void clear(); - - size_t length() const; - size_t cursorIndex() const; - void setCursorIndex(size_t inNewIndex); - void insertReadingAtCursor(const string& inReading); - bool deleteReadingBeforeCursor(); // backspace - bool deleteReadingAfterCursor(); // delete - - bool removeHeadReadings(size_t count); - - void setJoinSeparator(const string& separator); - const string joinSeparator() const; +namespace Gramambular { - vector readings() const; +class BlockReadingBuilder { +public: + explicit BlockReadingBuilder(LanguageModel* lm); + void clear(); + + size_t length() const; + size_t cursorIndex() const; + void setCursorIndex(size_t newIndex); + void insertReadingAtCursor(const std::string& reading); + bool deleteReadingBeforeCursor(); // backspace + bool deleteReadingAfterCursor(); // delete + + bool removeHeadReadings(size_t count); + + void setJoinSeparator(const std::string& separator); + const std::string joinSeparator() const; + + std::vector readings() const; + + Grid& grid(); + +protected: + void build(); + + static const std::string Join(std::vector::const_iterator begin, + std::vector::const_iterator end, + const std::string& separator); + + // 最多使用六個字組成一個詞 + static const size_t MaximumBuildSpanLength = 6; + + size_t m_cursorIndex; + std::vector m_readings; + + Grid m_grid; + LanguageModel* m_LM; + std::string m_joinSeparator; +}; - Grid& grid(); - - protected: - void build(); - - static const string Join(vector::const_iterator begin, vector::const_iterator end, const string& separator); - - //最多使用六個字組成一個詞 - static const size_t MaximumBuildSpanLength = 6; - - size_t m_cursorIndex; - vector m_readings; - - Grid m_grid; - LanguageModel *m_LM; - string m_joinSeparator; - }; - - inline BlockReadingBuilder::BlockReadingBuilder(LanguageModel *inLM) - : m_LM(inLM) - , m_cursorIndex(0) - { - } - - inline void BlockReadingBuilder::clear() - { - m_cursorIndex = 0; - m_readings.clear(); - m_grid.clear(); - } - - inline size_t BlockReadingBuilder::length() const - { - return m_readings.size(); - } - - inline size_t BlockReadingBuilder::cursorIndex() const - { - return m_cursorIndex; - } +inline BlockReadingBuilder::BlockReadingBuilder(LanguageModel* lm) +: m_LM(lm), m_cursorIndex(0) {} - inline void BlockReadingBuilder::setCursorIndex(size_t inNewIndex) - { - m_cursorIndex = inNewIndex > m_readings.size() ? m_readings.size() : inNewIndex; - } - - inline void BlockReadingBuilder::insertReadingAtCursor(const string& inReading) - { - m_readings.insert(m_readings.begin() + m_cursorIndex, inReading); - - m_grid.expandGridByOneAtLocation(m_cursorIndex); - build(); - m_cursorIndex++; - } +inline void BlockReadingBuilder::clear() { + m_cursorIndex = 0; + m_readings.clear(); + m_grid.clear(); +} - inline vector BlockReadingBuilder::readings() const - { - return m_readings; - } - - inline bool BlockReadingBuilder::deleteReadingBeforeCursor() - { - if (!m_cursorIndex) { - return false; - } - - m_readings.erase(m_readings.begin() + m_cursorIndex - 1, m_readings.begin() + m_cursorIndex); +inline size_t BlockReadingBuilder::length() const { return m_readings.size(); } + +inline size_t BlockReadingBuilder::cursorIndex() const { return m_cursorIndex; } + +inline void BlockReadingBuilder::setCursorIndex(size_t newIndex) { + m_cursorIndex = newIndex > m_readings.size() ? m_readings.size() : newIndex; +} + +inline void BlockReadingBuilder::insertReadingAtCursor( + const std::string& reading) { + m_readings.insert(m_readings.begin() + m_cursorIndex, reading); + + m_grid.expandGridByOneAtLocation(m_cursorIndex); + build(); + m_cursorIndex++; +} + +inline std::vector BlockReadingBuilder::readings() const { + return m_readings; +} + +inline bool BlockReadingBuilder::deleteReadingBeforeCursor() { + if (!m_cursorIndex) { + return false; + } + + m_readings.erase(m_readings.begin() + m_cursorIndex - 1, + m_readings.begin() + m_cursorIndex); + m_cursorIndex--; + m_grid.shrinkGridByOneAtLocation(m_cursorIndex); + build(); + return true; +} + +inline bool BlockReadingBuilder::deleteReadingAfterCursor() { + if (m_cursorIndex == m_readings.size()) { + return false; + } + + m_readings.erase(m_readings.begin() + m_cursorIndex, + m_readings.begin() + m_cursorIndex + 1); + m_grid.shrinkGridByOneAtLocation(m_cursorIndex); + build(); + return true; +} + +inline bool BlockReadingBuilder::removeHeadReadings(size_t count) { + if (count > length()) { + return false; + } + + for (size_t i = 0; i < count; i++) { + if (m_cursorIndex) { m_cursorIndex--; - m_grid.shrinkGridByOneAtLocation(m_cursorIndex); - build(); - return true; - } - - inline bool BlockReadingBuilder::deleteReadingAfterCursor() - { - if (m_cursorIndex == m_readings.size()) { - return false; - } - - m_readings.erase(m_readings.begin() + m_cursorIndex, m_readings.begin() + m_cursorIndex + 1); - m_grid.shrinkGridByOneAtLocation(m_cursorIndex); - build(); - return true; - } - - inline bool BlockReadingBuilder::removeHeadReadings(size_t count) - { - if (count > length()) { - return false; - } - - for (size_t i = 0; i < count; i++) { - if (m_cursorIndex) { - m_cursorIndex--; - } - m_readings.erase(m_readings.begin(), m_readings.begin() + 1); - m_grid.shrinkGridByOneAtLocation(0); - build(); - } - - return true; - } - - inline void BlockReadingBuilder::setJoinSeparator(const string& separator) - { - m_joinSeparator = separator; - } - - inline const string BlockReadingBuilder::joinSeparator() const - { - return m_joinSeparator; } + m_readings.erase(m_readings.begin(), m_readings.begin() + 1); + m_grid.shrinkGridByOneAtLocation(0); + build(); + } + + return true; +} - inline Grid& BlockReadingBuilder::grid() - { - return m_grid; - } +inline void BlockReadingBuilder::setJoinSeparator( + const std::string& separator) { + m_joinSeparator = separator; +} - inline void BlockReadingBuilder::build() - { - if (!m_LM) { - return; - } - - size_t begin = 0; - size_t end = m_cursorIndex + MaximumBuildSpanLength; - - if (m_cursorIndex < MaximumBuildSpanLength) { - begin = 0; - } - else { - begin = m_cursorIndex - MaximumBuildSpanLength; - } - - if (end > m_readings.size()) { - end = m_readings.size(); - } - - for (size_t p = begin ; p < end ; p++) { - for (size_t q = 1 ; q <= MaximumBuildSpanLength && p+q <= end ; q++) { - string combinedReading = Join(m_readings.begin() + p, m_readings.begin() + p + q, m_joinSeparator); - if (!m_grid.hasNodeAtLocationSpanningLengthMatchingKey(p, q, combinedReading)) { - vector unigrams = m_LM->unigramsForKey(combinedReading); +inline const std::string BlockReadingBuilder::joinSeparator() const { + return m_joinSeparator; +} - if (unigrams.size() > 0) { - Node n(combinedReading, unigrams, vector()); - m_grid.insertNode(n, p, q); - } - } +inline Grid& BlockReadingBuilder::grid() { return m_grid; } + +inline void BlockReadingBuilder::build() { + if (!m_LM) { + return; + } + + size_t begin = 0; + size_t end = m_cursorIndex + MaximumBuildSpanLength; + + if (m_cursorIndex < MaximumBuildSpanLength) { + begin = 0; + } else { + begin = m_cursorIndex - MaximumBuildSpanLength; + } + + if (end > m_readings.size()) { + end = m_readings.size(); + } + + for (size_t p = begin; p < end; p++) { + for (size_t q = 1; q <= MaximumBuildSpanLength && p + q <= end; q++) { + std::string combinedReading = Join( + m_readings.begin() + p, m_readings.begin() + p + q, m_joinSeparator); + if (!m_grid.hasNodeAtLocationSpanningLengthMatchingKey(p, q, + combinedReading)) { + std::vector unigrams = m_LM->unigramsForKey(combinedReading); + + if (unigrams.size() > 0) { + Node n(combinedReading, unigrams, std::vector()); + m_grid.insertNode(n, p, q); } } } - - inline const string BlockReadingBuilder::Join(vector::const_iterator begin, vector::const_iterator end, const string& separator) - { - string result; - for (vector::const_iterator iter = begin ; iter != end ; ) { - result += *iter; - ++iter; - if (iter != end) { - result += separator; - } - } - return result; - } } } +inline const std::string BlockReadingBuilder::Join( + std::vector::const_iterator begin, + std::vector::const_iterator end, + const std::string& separator) { + std::string result; + for (std::vector::const_iterator iter = begin; iter != end;) { + result += *iter; + ++iter; + if (iter != end) { + result += separator; + } + } + return result; +} +} // namespace Gramambular +} // namespace Taiyan + #endif diff --git a/Source/Modules/LanguageParsers/Gramambular/Gramambular.h b/Source/Modules/LanguageParsers/Gramambular/Gramambular.h index bf40892f..d2601d3f 100644 --- a/Source/Modules/LanguageParsers/Gramambular/Gramambular.h +++ b/Source/Modules/LanguageParsers/Gramambular/Gramambular.h @@ -17,8 +17,8 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef Gramambular_h -#define Gramambular_h +#ifndef GRAMAMBULAR_H_ +#define GRAMAMBULAR_H_ #include "Bigram.h" #include "BlockReadingBuilder.h" diff --git a/Source/Modules/LanguageParsers/Gramambular/Grid.h b/Source/Modules/LanguageParsers/Gramambular/Grid.h index 8872cfae..f81c9301 100644 --- a/Source/Modules/LanguageParsers/Gramambular/Grid.h +++ b/Source/Modules/LanguageParsers/Gramambular/Grid.h @@ -17,248 +17,207 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef Grid_h -#define Grid_h +#ifndef GRID_H_ +#define GRID_H_ #include +#include +#include + #include "NodeAnchor.h" #include "Span.h" namespace Taiyan { - namespace Gramambular { +namespace Gramambular { + +class Grid { +public: + void clear(); + void insertNode(const Node& node, size_t location, size_t spanningLength); + bool hasNodeAtLocationSpanningLengthMatchingKey(size_t location, + size_t spanningLength, + const std::string& key); + + void expandGridByOneAtLocation(size_t location); + void shrinkGridByOneAtLocation(size_t location); + + size_t width() const; + std::vector nodesEndingAt(size_t location); + std::vector nodesCrossingOrEndingAt(size_t location); + + // "Freeze" the node with the unigram that represents the selected candidate + // value. After this, the node that contains the unigram will always be + // evaluated to that unigram, while all other overlapping nodes will be reset + // to their initial state (that is, if any of those nodes were "frozen" or + // fixed, they will be unfrozen.) + NodeAnchor fixNodeSelectedCandidate(size_t location, + const std::string& value); + + // Similar to fixNodeSelectedCandidate, but instead of "freezing" the node, + // only boost the unigram that represents the value with an overriding score. + // This has the same side effect as fixNodeSelectedCandidate, which is that + // all other overlapping nodes will be reset to their initial state. + void overrideNodeScoreForSelectedCandidate(size_t location, + const std::string& value, + float overridingScore); + + std::string dumpDOT(); + +protected: + std::vector m_spans; +}; + +inline void Grid::clear() { m_spans.clear(); } + +inline void Grid::insertNode(const Node& node, size_t location, + size_t spanningLength) { + if (location >= m_spans.size()) { + size_t diff = location - m_spans.size() + 1; - class Grid { - public: - void clear(); - void insertNode(const Node& inNode, size_t inLocation, size_t inSpanningLength); - bool hasNodeAtLocationSpanningLengthMatchingKey(size_t inLocation, size_t inSpanningLength, const string& inKey); - - void expandGridByOneAtLocation(size_t inLocation); - void shrinkGridByOneAtLocation(size_t inLocation); - - size_t width() const; - vector nodesEndingAt(size_t inLocation); - vector nodesCrossingOrEndingAt(size_t inLocation); - - // "Freeze" the node with the unigram that represents the selected candidate value. - // After this, the node that contains the unigram will always be evaluated to that - // unigram, while all other overlapping nodes will be reset to their initial state - // (that is, if any of those nodes were "frozen" or fixed, they will be unfrozen.) - NodeAnchor fixNodeSelectedCandidate(size_t location, const string& value); - - // Similar to fixNodeSelectedCandidate, but instead of "freezing" the node, only - // boost the unigram that represents the value with an overriding score. This - // has the same side effect as fixNodeSelectedCandidate, which is that all other - // overlapping nodes will be reset to their initial state. - void overrideNodeScoreForSelectedCandidate(size_t location, const string& value, float overridingScore); - - const string dumpDOT(); - - protected: - vector m_spans; - }; - - inline void Grid::clear() - { - m_spans.clear(); + for (size_t i = 0; i < diff; i++) { + m_spans.push_back(Span()); } - - inline void Grid::insertNode(const Node& inNode, size_t inLocation, size_t inSpanningLength) - { - if (inLocation >= m_spans.size()) { - size_t diff = inLocation - m_spans.size() + 1; - - for (size_t i = 0 ; i < diff ; i++) { - m_spans.push_back(Span()); - } - } + } + + m_spans[location].insertNodeOfLength(node, spanningLength); +} - m_spans[inLocation].insertNodeOfLength(inNode, inSpanningLength); - } +inline bool Grid::hasNodeAtLocationSpanningLengthMatchingKey( + size_t location, size_t spanningLength, const std::string& key) { + if (location > m_spans.size()) { + return false; + } + + const Node* n = m_spans[location].nodeOfLength(spanningLength); + if (!n) { + return false; + } + + return key == n->key(); +} - inline bool Grid::hasNodeAtLocationSpanningLengthMatchingKey(size_t inLocation, size_t inSpanningLength, const string& inKey) - { - if (inLocation > m_spans.size()) { - return false; - } - - const Node *n = m_spans[inLocation].nodeOfLength(inSpanningLength); - if (!n) { - return false; - } - - return inKey == n->key(); - } - - inline void Grid::expandGridByOneAtLocation(size_t inLocation) - { - if (!inLocation || inLocation == m_spans.size()) { - m_spans.insert(m_spans.begin() + inLocation, Span()); - } - else { - m_spans.insert(m_spans.begin() + inLocation, Span()); - for (size_t i = 0 ; i < inLocation ; i++) { - // zaps overlapping spans - m_spans[i].removeNodeOfLengthGreaterThan(inLocation - i); - } - } - } - - inline void Grid::shrinkGridByOneAtLocation(size_t inLocation) - { - if (inLocation >= m_spans.size()) { - return; - } - - m_spans.erase(m_spans.begin() + inLocation); - for (size_t i = 0 ; i < inLocation ; i++) { - // zaps overlapping spans - m_spans[i].removeNodeOfLengthGreaterThan(inLocation - i); - } - } - - inline size_t Grid::width() const - { - return m_spans.size(); - } - - inline vector Grid::nodesEndingAt(size_t inLocation) - { - vector result; - - if (m_spans.size() && inLocation <= m_spans.size()) { - for (size_t i = 0 ; i < inLocation ; i++) { - Span& span = m_spans[i]; - if (i + span.maximumLength() >= inLocation) { - Node *np = span.nodeOfLength(inLocation - i); - if (np) { - NodeAnchor na; - na.node = np; - na.location = i; - na.spanningLength = inLocation - i; - - result.push_back(na); - } - } - } - } - - return result; - } - - inline vector Grid::nodesCrossingOrEndingAt(size_t inLocation) - { - vector result; - - if (m_spans.size() && inLocation <= m_spans.size()) { - for (size_t i = 0 ; i < inLocation ; i++) { - Span& span = m_spans[i]; - - if (i + span.maximumLength() >= inLocation) { - - for (size_t j = 1, m = span.maximumLength(); j <= m ; j++) { - - if (i + j < inLocation) { - continue; - } - - Node *np = span.nodeOfLength(j); - if (np) { - NodeAnchor na; - na.node = np; - na.location = i; - na.spanningLength = inLocation - i; - - result.push_back(na); - } - } - } - } - } - - return result; - } - - // For nodes found at the location, fix their currently-selected candidate using the supplied string value. - inline NodeAnchor Grid::fixNodeSelectedCandidate(size_t location, const string& value) - { - vector nodes = nodesCrossingOrEndingAt(location); - NodeAnchor node; - for (auto nodeAnchor : nodes) { - auto candidates = nodeAnchor.node->candidates(); - - // Reset the candidate-fixed state of every node at the location. - const_cast(nodeAnchor.node)->resetCandidate(); - - for (size_t i = 0, c = candidates.size(); i < c; ++i) { - if (candidates[i].value == value) { - const_cast(nodeAnchor.node)->selectCandidateAtIndex(i); - node = nodeAnchor; - break;; - } - } - } - return node; - } - - inline void Grid::overrideNodeScoreForSelectedCandidate(size_t location, const string& value, float overridingScore) - { - vector nodes = nodesCrossingOrEndingAt(location); - for (auto nodeAnchor : nodes) { - auto candidates = nodeAnchor.node->candidates(); - - // Reset the candidate-fixed state of every node at the location. - const_cast(nodeAnchor.node)->resetCandidate(); - - for (size_t i = 0, c = candidates.size(); i < c; ++i) { - if (candidates[i].value == value) { - const_cast(nodeAnchor.node)->selectFloatingCandidateAtIndex(i, overridingScore); - break; - } - } - } - } - - inline const string Grid::dumpDOT() - { - stringstream sst; - sst << "digraph {" << endl; - sst << "graph [ rankdir=LR ];" << endl; - sst << "BOS;" << endl; - - for (size_t p = 0 ; p < m_spans.size() ; p++) { - Span& span = m_spans[p]; - for (size_t ni = 0 ; ni <= span.maximumLength() ; ni++) { - Node* np = span.nodeOfLength(ni); - if (np) { - if (!p) { - sst << "BOS -> " << np->currentKeyValue().value << ";" << endl; - } - - sst << np->currentKeyValue().value << ";" << endl; - - if (p + ni < m_spans.size()) { - Span& dstSpan = m_spans[p+ni]; - for (size_t q = 0 ; q <= dstSpan.maximumLength() ; q++) { - Node *dn = dstSpan.nodeOfLength(q); - if (dn) { - sst << np->currentKeyValue().value << " -> " << dn->currentKeyValue().value << ";" << endl; - } - } - } - - if (p + ni == m_spans.size()) { - sst << np->currentKeyValue().value << " -> " << "EOS;" << endl; - } - } - } - } - - sst << "EOS;" << endl; - sst << "}"; - return sst.str(); +inline void Grid::expandGridByOneAtLocation(size_t location) { + if (!location || location == m_spans.size()) { + m_spans.insert(m_spans.begin() + location, Span()); + } else { + m_spans.insert(m_spans.begin() + location, Span()); + for (size_t i = 0; i < location; i++) { + // zaps overlapping spans + m_spans[i].removeNodeOfLengthGreaterThan(location - i); } } } +inline void Grid::shrinkGridByOneAtLocation(size_t location) { + if (location >= m_spans.size()) { + return; + } + + m_spans.erase(m_spans.begin() + location); + for (size_t i = 0; i < location; i++) { + // zaps overlapping spans + m_spans[i].removeNodeOfLengthGreaterThan(location - i); + } +} + +inline size_t Grid::width() const { return m_spans.size(); } + +inline std::vector Grid::nodesEndingAt(size_t location) { + std::vector result; + + if (m_spans.size() && location <= m_spans.size()) { + for (size_t i = 0; i < location; i++) { + Span& span = m_spans[i]; + if (i + span.maximumLength() >= location) { + Node* np = span.nodeOfLength(location - i); + if (np) { + NodeAnchor na; + na.node = np; + na.location = i; + na.spanningLength = location - i; + + result.push_back(na); + } + } + } + } + + return result; +} + +inline std::vector Grid::nodesCrossingOrEndingAt(size_t location) { + std::vector result; + + if (m_spans.size() && location <= m_spans.size()) { + for (size_t i = 0; i < location; i++) { + Span& span = m_spans[i]; + + if (i + span.maximumLength() >= location) { + for (size_t j = 1, m = span.maximumLength(); j <= m; j++) { + if (i + j < location) { + continue; + } + + Node* np = span.nodeOfLength(j); + if (np) { + NodeAnchor na; + na.node = np; + na.location = i; + na.spanningLength = location - i; + + result.push_back(na); + } + } + } + } + } + + return result; +} + +// For nodes found at the location, fix their currently-selected candidate using +// the supplied string value. +inline NodeAnchor Grid::fixNodeSelectedCandidate(size_t location, + const std::string& value) { + std::vector nodes = nodesCrossingOrEndingAt(location); + NodeAnchor node; + for (auto nodeAnchor : nodes) { + auto candidates = nodeAnchor.node->candidates(); + + // Reset the candidate-fixed state of every node at the location. + const_cast(nodeAnchor.node)->resetCandidate(); + + for (size_t i = 0, c = candidates.size(); i < c; ++i) { + if (candidates[i].value == value) { + const_cast(nodeAnchor.node)->selectCandidateAtIndex(i); + node = nodeAnchor; + break; + } + } + } + return node; +} + +inline void Grid::overrideNodeScoreForSelectedCandidate( + size_t location, const std::string& value, float overridingScore) { + std::vector nodes = nodesCrossingOrEndingAt(location); + for (auto nodeAnchor : nodes) { + auto candidates = nodeAnchor.node->candidates(); + + // Reset the candidate-fixed state of every node at the location. + const_cast(nodeAnchor.node)->resetCandidate(); + + for (size_t i = 0, c = candidates.size(); i < c; ++i) { + if (candidates[i].value == value) { + const_cast(nodeAnchor.node) + ->selectFloatingCandidateAtIndex(i, overridingScore); + break; + } + } + } +} + +} // namespace Gramambular +} // namespace Taiyan + #endif diff --git a/Source/Modules/LanguageParsers/Gramambular/Grid.mm b/Source/Modules/LanguageParsers/Gramambular/Grid.mm new file mode 100644 index 00000000..ba76a6e0 --- /dev/null +++ b/Source/Modules/LanguageParsers/Gramambular/Grid.mm @@ -0,0 +1,70 @@ +// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License). +// All possible vChewing-specific modifications are (c) 2021 and onwards The vChewing Project (MIT-NTL 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. +*/ + +#include "Grid.h" + +#include +#include + +namespace Taiyan { +namespace Gramambular { + +std::string Grid::dumpDOT() { + std::stringstream sst; + sst << "digraph {" << std::endl; + sst << "graph [ rankdir=LR ];" << std::endl; + sst << "BOS;" << std::endl; + + for (size_t p = 0; p < m_spans.size(); p++) { + Span& span = m_spans[p]; + for (size_t ni = 0; ni <= span.maximumLength(); ni++) { + Node* np = span.nodeOfLength(ni); + if (np) { + if (!p) { + sst << "BOS -> " << np->currentKeyValue().value << ";" << std::endl; + } + + sst << np->currentKeyValue().value << ";" << std::endl; + + if (p + ni < m_spans.size()) { + Span& dstSpan = m_spans[p + ni]; + for (size_t q = 0; q <= dstSpan.maximumLength(); q++) { + Node* dn = dstSpan.nodeOfLength(q); + if (dn) { + sst << np->currentKeyValue().value << " -> " + << dn->currentKeyValue().value << ";" << std::endl; + } + } + } + + if (p + ni == m_spans.size()) { + sst << np->currentKeyValue().value << " -> " + << "EOS;" << std::endl; + } + } + } + } + + sst << "EOS;" << std::endl; + sst << "}"; + return sst.str(); +} + +} // namespace Gramambular +} // namespace Taiyan diff --git a/Source/Modules/LanguageParsers/Gramambular/KeyValuePair.h b/Source/Modules/LanguageParsers/Gramambular/KeyValuePair.h index 1b6bdded..e22a96bd 100644 --- a/Source/Modules/LanguageParsers/Gramambular/KeyValuePair.h +++ b/Source/Modules/LanguageParsers/Gramambular/KeyValuePair.h @@ -17,47 +17,43 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef KeyValuePair_h -#define KeyValuePair_h +#ifndef KEYVALUEPAIR_H_ +#define KEYVALUEPAIR_H_ #include #include namespace Taiyan { - namespace Gramambular { - using namespace std; - - class KeyValuePair { - public: - string key; - string value; +namespace Gramambular { - bool operator==(const KeyValuePair& inAnother) const; - bool operator<(const KeyValuePair& inAnother) const; - }; +class KeyValuePair { +public: + std::string key; + std::string value; + + bool operator==(const KeyValuePair& another) const; + bool operator<(const KeyValuePair& another) const; +}; - inline ostream& operator<<(ostream& inStream, const KeyValuePair& inPair) - { - inStream << "(" << inPair.key << "," << inPair.value << ")"; - return inStream; - } - - inline bool KeyValuePair::operator==(const KeyValuePair& inAnother) const - { - return key == inAnother.key && value == inAnother.value; - } - - inline bool KeyValuePair::operator<(const KeyValuePair& inAnother) const - { - if (key < inAnother.key) { - return true; - } - else if (key == inAnother.key) { - return value < inAnother.value; - } - return false; - } - } +inline std::ostream& operator<<(std::ostream& stream, + const KeyValuePair& pair) { + stream << "(" << pair.key << "," << pair.value << ")"; + return stream; } +inline bool KeyValuePair::operator==(const KeyValuePair& another) const { + return key == another.key && value == another.value; +} + +inline bool KeyValuePair::operator<(const KeyValuePair& another) const { + if (key < another.key) { + return true; + } else if (key == another.key) { + return value < another.value; + } + return false; +} +} // namespace Gramambular +} // namespace Taiyan + #endif diff --git a/Source/Modules/LanguageParsers/Gramambular/LanguageModel.h b/Source/Modules/LanguageParsers/Gramambular/LanguageModel.h index bea86f7b..b24f7fff 100644 --- a/Source/Modules/LanguageParsers/Gramambular/LanguageModel.h +++ b/Source/Modules/LanguageParsers/Gramambular/LanguageModel.h @@ -17,28 +17,28 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef LanguageModel_h -#define LanguageModel_h +#ifndef LANGUAGEMODEL_H_ +#define LANGUAGEMODEL_H_ +#include #include + #include "Bigram.h" #include "Unigram.h" namespace Taiyan { - namespace Gramambular { - - using namespace std; - - class LanguageModel { - public: - virtual ~LanguageModel() {} - - virtual const vector bigramsForKeys(const string &preceedingKey, const string& key) = 0; - virtual const vector unigramsForKey(const string &key) = 0; - virtual bool hasUnigramsForKey(const string& key) = 0; - }; - } -} +namespace Gramambular { +class LanguageModel { +public: + virtual ~LanguageModel() {} + + virtual const std::vector bigramsForKeys( + const std::string& preceedingKey, const std::string& key) = 0; + virtual const std::vector unigramsForKey(const std::string& key) = 0; + virtual bool hasUnigramsForKey(const std::string& key) = 0; +}; +} // namespace Gramambular +} // namespace Taiyan #endif diff --git a/Source/Modules/LanguageParsers/Gramambular/Node.h b/Source/Modules/LanguageParsers/Gramambular/Node.h index bf9e568f..ff1d3fd2 100644 --- a/Source/Modules/LanguageParsers/Gramambular/Node.h +++ b/Source/Modules/LanguageParsers/Gramambular/Node.h @@ -17,208 +17,198 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef Node_h -#define Node_h +#ifndef NODE_H_ +#define NODE_H_ #include +#include +#include #include + #include "LanguageModel.h" namespace Taiyan { - namespace Gramambular { - using namespace std; +namespace Gramambular { - class Node { - public: - Node(); - Node(const string& inKey, const vector& inUnigrams, const vector& inBigrams); - - void primeNodeWithPreceedingKeyValues(const vector& inKeyValues); - - bool isCandidateFixed() const; - const vector& candidates() const; - void selectCandidateAtIndex(size_t inIndex = 0, bool inFix = true); - void resetCandidate(); - void selectFloatingCandidateAtIndex(size_t index, double score); - - const string& key() const; - double score() const; - // double scoreForCandidate(string &candidate) const; // Prevents the override model to remember symbols with scode -X or lower. - const KeyValuePair currentKeyValue() const; - double highestUnigramScore() const; - - protected: - const LanguageModel* m_LM; - - string m_key; - double m_score; - - vector m_unigrams; - vector m_candidates; - map m_valueUnigramIndexMap; - map > m_preceedingGramBigramMap; - - bool m_candidateFixed; - size_t m_selectedUnigramIndex; - - friend ostream& operator<<(ostream& inStream, const Node& inNode); - }; +class Node { +public: + Node(); + Node(const std::string& key, const std::vector& unigrams, + const std::vector& bigrams); + + void primeNodeWithPreceedingKeyValues( + const std::vector& keyValues); + + bool isCandidateFixed() const; + const std::vector& candidates() const; + void selectCandidateAtIndex(size_t index = 0, bool fix = true); + void resetCandidate(); + void selectFloatingCandidateAtIndex(size_t index, double score); + + const std::string& key() const; + double score() const; + double scoreForCandidate(const std::string& candidate) const; + const KeyValuePair currentKeyValue() const; + double highestUnigramScore() const; + +protected: + const LanguageModel* m_LM; + + std::string m_key; + double m_score; + + std::vector m_unigrams; + std::vector m_candidates; + std::map m_valueUnigramIndexMap; + std::map > m_preceedingGramBigramMap; + + bool m_candidateFixed; + size_t m_selectedUnigramIndex; + + friend std::ostream& operator<<(std::ostream& stream, const Node& node); +}; - inline ostream& operator<<(ostream& inStream, const Node& inNode) - { - inStream << "(node,key:" << inNode.m_key << ",fixed:" << (inNode.m_candidateFixed ? "true" : "false") - << ",selected:" << inNode.m_selectedUnigramIndex - << "," << inNode.m_unigrams << ")"; - return inStream; - } +inline std::ostream& operator<<(std::ostream& stream, const Node& node) { + stream << "(node,key:" << node.m_key + << ",fixed:" << (node.m_candidateFixed ? "true" : "false") + << ",selected:" << node.m_selectedUnigramIndex << "," + << node.m_unigrams << ")"; + return stream; +} - inline Node::Node() - : m_candidateFixed(false) - , m_selectedUnigramIndex(0) - , m_score(0.0) - { - } +inline Node::Node() +: m_candidateFixed(false), m_selectedUnigramIndex(0), m_score(0.0) {} - inline Node::Node(const string& inKey, const vector& inUnigrams, const vector& inBigrams) - : m_key(inKey) - , m_unigrams(inUnigrams) - , m_candidateFixed(false) - , m_selectedUnigramIndex(0) - , m_score(0.0) - { - stable_sort(m_unigrams.begin(), m_unigrams.end(), Unigram::ScoreCompare); - - if (m_unigrams.size()) { - m_score = m_unigrams[0].score; - } - - size_t i = 0; - for (vector::const_iterator ui = m_unigrams.begin() ; ui != m_unigrams.end() ; ++ui) { - m_valueUnigramIndexMap[(*ui).keyValue.value] = i; - i++; - - m_candidates.push_back((*ui).keyValue); - } - - for (vector::const_iterator bi = inBigrams.begin() ; bi != inBigrams.end() ; ++bi) { - m_preceedingGramBigramMap[(*bi).preceedingKeyValue].push_back(*bi); - } - } +inline Node::Node(const std::string& key, const std::vector& unigrams, + const std::vector& bigrams) +: m_key(key), +m_unigrams(unigrams), +m_candidateFixed(false), +m_selectedUnigramIndex(0), +m_score(0.0) { + stable_sort(m_unigrams.begin(), m_unigrams.end(), Unigram::ScoreCompare); + + if (m_unigrams.size()) { + m_score = m_unigrams[0].score; + } + + size_t i = 0; + for (std::vector::const_iterator ui = m_unigrams.begin(); + ui != m_unigrams.end(); ++ui) { + m_valueUnigramIndexMap[(*ui).keyValue.value] = i; + i++; - inline void Node::primeNodeWithPreceedingKeyValues(const vector& inKeyValues) - { - size_t newIndex = m_selectedUnigramIndex; - double max = m_score; + m_candidates.push_back((*ui).keyValue); + } + + for (std::vector::const_iterator bi = bigrams.begin(); + bi != bigrams.end(); ++bi) { + m_preceedingGramBigramMap[(*bi).preceedingKeyValue].push_back(*bi); + } +} - if (!isCandidateFixed()) { - for (vector::const_iterator kvi = inKeyValues.begin() ; kvi != inKeyValues.end() ; ++kvi) { - map >::const_iterator f = m_preceedingGramBigramMap.find(*kvi); - if (f != m_preceedingGramBigramMap.end()) { - const vector& bigrams = (*f).second; - - for (vector::const_iterator bi = bigrams.begin() ; bi != bigrams.end() ; ++bi) { - const Bigram& bigram = *bi; - if (bigram.score > max) { - map::const_iterator uf = m_valueUnigramIndexMap.find((*bi).keyValue.value); - if (uf != m_valueUnigramIndexMap.end()) { - newIndex = (*uf).second; - max = bigram.score; - } - } +inline void Node::primeNodeWithPreceedingKeyValues( + const std::vector& keyValues) { + size_t newIndex = m_selectedUnigramIndex; + double max = m_score; + + if (!isCandidateFixed()) { + for (std::vector::const_iterator kvi = keyValues.begin(); + kvi != keyValues.end(); ++kvi) { + std::map >::const_iterator f = + m_preceedingGramBigramMap.find(*kvi); + if (f != m_preceedingGramBigramMap.end()) { + const std::vector& bigrams = (*f).second; + + for (std::vector::const_iterator bi = bigrams.begin(); + bi != bigrams.end(); ++bi) { + const Bigram& bigram = *bi; + if (bigram.score > max) { + std::map::const_iterator uf = + m_valueUnigramIndexMap.find((*bi).keyValue.value); + if (uf != m_valueUnigramIndexMap.end()) { + newIndex = (*uf).second; + max = bigram.score; } } } } - - if (m_score != max) { - m_score = max; - } - - if (newIndex != m_selectedUnigramIndex) { - m_selectedUnigramIndex = newIndex; - } } - - inline bool Node::isCandidateFixed() const - { - return m_candidateFixed; - } - - inline const vector& Node::candidates() const - { - return m_candidates; - } - - inline void Node::selectCandidateAtIndex(size_t inIndex, bool inFix) - { - if (inIndex >= m_unigrams.size()) { - m_selectedUnigramIndex = 0; - } - else { - m_selectedUnigramIndex = inIndex; - } - - m_candidateFixed = inFix; - m_score = 99; - } - - inline void Node::resetCandidate() - { - m_selectedUnigramIndex = 0; - m_candidateFixed = 0; - if (m_unigrams.size()) { - m_score = m_unigrams[0].score; - } - } - - inline void Node::selectFloatingCandidateAtIndex(size_t index, double score) { - if (index >= m_unigrams.size()) { - m_selectedUnigramIndex = 0; - } else { - m_selectedUnigramIndex = index; - } - m_candidateFixed = false; - m_score = score; - } - - inline const string& Node::key() const - { - return m_key; - } - - inline double Node::score() const - { - return m_score; - } - - // Prevents the override model to remember symbols with scode -X or lower. -// inline double Node::scoreForCandidate(string &candidate) const -// { -// for (auto unigram : m_unigrams) { -// if (unigram.keyValue.value == candidate) { -// return unigram.score; -// } -// } -// return 0.0; -// } - - inline double Node::highestUnigramScore() const { - if (m_unigrams.empty()) { - return 0.0; - } - return m_unigrams[0].score; - } - - inline const KeyValuePair Node::currentKeyValue() const - { - if(m_selectedUnigramIndex >= m_unigrams.size()) { - return KeyValuePair(); - } - else { - return m_candidates[m_selectedUnigramIndex]; - } - } + } + + if (m_score != max) { + m_score = max; + } + + if (newIndex != m_selectedUnigramIndex) { + m_selectedUnigramIndex = newIndex; } } +inline bool Node::isCandidateFixed() const { return m_candidateFixed; } + +inline const std::vector& Node::candidates() const { + return m_candidates; +} + +inline void Node::selectCandidateAtIndex(size_t index, bool fix) { + if (index >= m_unigrams.size()) { + m_selectedUnigramIndex = 0; + } else { + m_selectedUnigramIndex = index; + } + + m_candidateFixed = fix; + m_score = 99; +} + +inline void Node::resetCandidate() { + m_selectedUnigramIndex = 0; + m_candidateFixed = 0; + if (m_unigrams.size()) { + m_score = m_unigrams[0].score; + } +} + +inline void Node::selectFloatingCandidateAtIndex(size_t index, double score) { + if (index >= m_unigrams.size()) { + m_selectedUnigramIndex = 0; + } else { + m_selectedUnigramIndex = index; + } + m_candidateFixed = false; + m_score = score; +} + +inline const std::string& Node::key() const { return m_key; } + +inline double Node::score() const { return m_score; } + +// Prevents the override model to remember symbols with scode -X or lower. +//inline double Node::scoreForCandidate(const std::string& candidate) const { +// for (auto unigram : m_unigrams) { +// if (unigram.keyValue.value == candidate) { +// return unigram.score; +// } +// } +// return 0.0; +//} + +inline double Node::highestUnigramScore() const { + if (m_unigrams.empty()) { + return 0.0; + } + return m_unigrams[0].score; +} + +inline const KeyValuePair Node::currentKeyValue() const { + if (m_selectedUnigramIndex >= m_unigrams.size()) { + return KeyValuePair(); + } else { + return m_candidates[m_selectedUnigramIndex]; + } +} +} // namespace Gramambular +} // namespace Taiyan + #endif diff --git a/Source/Modules/LanguageParsers/Gramambular/NodeAnchor.h b/Source/Modules/LanguageParsers/Gramambular/NodeAnchor.h index 29462d85..f215c92e 100644 --- a/Source/Modules/LanguageParsers/Gramambular/NodeAnchor.h +++ b/Source/Modules/LanguageParsers/Gramambular/NodeAnchor.h @@ -17,55 +17,48 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef NodeAnchor_h -#define NodeAnchor_h +#ifndef NODEANCHOR_H_ +#define NODEANCHOR_H_ + +#include #include "Node.h" namespace Taiyan { - namespace Gramambular { - class NodeAnchor { - public: - NodeAnchor(); - const Node *node; - size_t location; - size_t spanningLength; - double accumulatedScore; - }; - - inline NodeAnchor::NodeAnchor() - : node(0) - , location(0) - , spanningLength(0) - , accumulatedScore(0.0) - { - } +namespace Gramambular { - inline ostream& operator<<(ostream& inStream, const NodeAnchor& inAnchor) - { - inStream << "{@(" << inAnchor.location << "," << inAnchor.spanningLength << "),"; - if (inAnchor.node) { - inStream << *(inAnchor.node); - } - else { - inStream << "null"; - } - inStream << "}"; - return inStream; - } - - inline ostream& operator<<(ostream& inStream, const vector& inAnchor) - { - for (vector::const_iterator i = inAnchor.begin() ; i != inAnchor.end() ; ++i) { - inStream << *i; - if (i + 1 != inAnchor.end()) { - inStream << "<-"; - } - } - - return inStream; - } +struct NodeAnchor { + const Node* node = nullptr; + size_t location = 0; + size_t spanningLength = 0; + double accumulatedScore = 0.0; +}; + +inline std::ostream& operator<<(std::ostream& stream, + const NodeAnchor& anchor) { + stream << "{@(" << anchor.location << "," << anchor.spanningLength << "),"; + if (anchor.node) { + stream << *(anchor.node); + } else { + stream << "null"; } + stream << "}"; + return stream; } +inline std::ostream& operator<<(std::ostream& stream, + const std::vector& anchor) { + for (std::vector::const_iterator i = anchor.begin(); + i != anchor.end(); ++i) { + stream << *i; + if (i + 1 != anchor.end()) { + stream << "<-"; + } + } + + return stream; +} +} // namespace Gramambular +} // namespace Taiyan + #endif diff --git a/Source/Modules/LanguageParsers/Gramambular/Span.h b/Source/Modules/LanguageParsers/Gramambular/Span.h index d4336d47..e46df777 100644 --- a/Source/Modules/LanguageParsers/Gramambular/Span.h +++ b/Source/Modules/LanguageParsers/Gramambular/Span.h @@ -17,88 +17,77 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef Span_h -#define Span_h +#ifndef SPAN_H_ +#define SPAN_H_ #include #include #include + #include "Node.h" namespace Taiyan { - namespace Gramambular { - class Span { - public: - Span(); +namespace Gramambular { +class Span { +public: + void clear(); + void insertNodeOfLength(const Node& node, size_t length); + void removeNodeOfLengthGreaterThan(size_t length); + + Node* nodeOfLength(size_t length); + size_t maximumLength() const; + +protected: + std::map m_lengthNodeMap; + size_t m_maximumLength = 0; +}; - void clear(); - void insertNodeOfLength(const Node& inNode, size_t inLength); - void removeNodeOfLengthGreaterThan(size_t inLength); - - Node* nodeOfLength(size_t inLength); - size_t maximumLength() const; +inline void Span::clear() { + m_lengthNodeMap.clear(); + m_maximumLength = 0; +} - protected: - map m_lengthNodeMap; - size_t m_maximumLength; - }; - - inline Span::Span() - : m_maximumLength(0) - { - } - - inline void Span::clear() - { - m_lengthNodeMap.clear(); - m_maximumLength = 0; - } - - inline void Span::insertNodeOfLength(const Node& inNode, size_t inLength) - { - m_lengthNodeMap[inLength] = inNode; - if (inLength > m_maximumLength) { - m_maximumLength = inLength; - } - } - - inline void Span::removeNodeOfLengthGreaterThan(size_t inLength) - { - if (inLength > m_maximumLength) { - return; - } - - size_t max = 0; - set removeSet; - for (map::iterator i = m_lengthNodeMap.begin(), e = m_lengthNodeMap.end() ; i != e ; ++i) { - if ((*i).first > inLength) { - removeSet.insert((*i).first); - } - else { - if ((*i).first > max) { - max = (*i).first; - } - } - } - - for (set::iterator i = removeSet.begin(), e = removeSet.end(); i != e; ++i) { - m_lengthNodeMap.erase(*i); - } - - m_maximumLength = max; - } - - inline Node* Span::nodeOfLength(size_t inLength) - { - map::iterator f = m_lengthNodeMap.find(inLength); - return f == m_lengthNodeMap.end() ? 0 : &(*f).second; - } - - inline size_t Span::maximumLength() const - { - return m_maximumLength; - } +inline void Span::insertNodeOfLength(const Node& node, size_t length) { + m_lengthNodeMap[length] = node; + if (length > m_maximumLength) { + m_maximumLength = length; } } +inline void Span::removeNodeOfLengthGreaterThan(size_t length) { + if (length > m_maximumLength) { + return; + } + + size_t max = 0; + std::set removeSet; + for (std::map::iterator i = m_lengthNodeMap.begin(), + e = m_lengthNodeMap.end(); + i != e; ++i) { + if ((*i).first > length) { + removeSet.insert((*i).first); + } else { + if ((*i).first > max) { + max = (*i).first; + } + } + } + + for (std::set::iterator i = removeSet.begin(), e = removeSet.end(); + i != e; ++i) { + m_lengthNodeMap.erase(*i); + } + + m_maximumLength = max; +} + +inline Node* Span::nodeOfLength(size_t length) { + std::map::iterator f = m_lengthNodeMap.find(length); + return f == m_lengthNodeMap.end() ? 0 : &(*f).second; +} + +inline size_t Span::maximumLength() const { return m_maximumLength; } +} // namespace Gramambular +} // namespace Taiyan + #endif diff --git a/Source/Modules/LanguageParsers/Gramambular/Unigram.h b/Source/Modules/LanguageParsers/Gramambular/Unigram.h index 2f4a5b88..b05e55f6 100644 --- a/Source/Modules/LanguageParsers/Gramambular/Unigram.h +++ b/Source/Modules/LanguageParsers/Gramambular/Unigram.h @@ -17,80 +17,75 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef Unigram_h -#define Unigram_h +#ifndef UNIGRAM_H_ +#define UNIGRAM_H_ #include + #include "KeyValuePair.h" namespace Taiyan { - namespace Gramambular { - class Unigram { - public: - Unigram(); +namespace Gramambular { - KeyValuePair keyValue; - double score; - - bool operator==(const Unigram& inAnother) const; - bool operator<(const Unigram& inAnother) const; - - static bool ScoreCompare(const Unigram& a, const Unigram& b); - }; +class Unigram { +public: + Unigram(); + + KeyValuePair keyValue; + double score; + + bool operator==(const Unigram& another) const; + bool operator<(const Unigram& another) const; + + static bool ScoreCompare(const Unigram& a, const Unigram& b); +}; - inline ostream& operator<<(ostream& inStream, const Unigram& inGram) - { - streamsize p = inStream.precision(); - inStream.precision(6); - inStream << "(" << inGram.keyValue << "," << inGram.score << ")"; - inStream.precision(p); - return inStream; - } - - inline ostream& operator<<(ostream& inStream, const vector& inGrams) - { - inStream << "[" << inGrams.size() << "]=>{"; - - size_t index = 0; - - for (vector::const_iterator gi = inGrams.begin() ; gi != inGrams.end() ; ++gi, ++index) { - inStream << index << "=>"; - inStream << *gi; - if (gi + 1 != inGrams.end()) { - inStream << ","; - } - } - - inStream << "}"; - return inStream; - } - - inline Unigram::Unigram() - : score(0.0) - { - } - - inline bool Unigram::operator==(const Unigram& inAnother) const - { - return keyValue == inAnother.keyValue && score == inAnother.score; - } - - inline bool Unigram::operator<(const Unigram& inAnother) const - { - if (keyValue < inAnother.keyValue) { - return true; - } - else if (keyValue == inAnother.keyValue) { - return score < inAnother.score; - } - return false; - } - - inline bool Unigram::ScoreCompare(const Unigram& a, const Unigram& b) - { - return a.score > b.score; - } - } +inline std::ostream& operator<<(std::ostream& stream, const Unigram& gram) { + std::streamsize p = stream.precision(); + stream.precision(6); + stream << "(" << gram.keyValue << "," << gram.score << ")"; + stream.precision(p); + return stream; } +inline std::ostream& operator<<(std::ostream& stream, + const std::vector& grams) { + stream << "[" << grams.size() << "]=>{"; + + size_t index = 0; + + for (std::vector::const_iterator gi = grams.begin(); + gi != grams.end(); ++gi, ++index) { + stream << index << "=>"; + stream << *gi; + if (gi + 1 != grams.end()) { + stream << ","; + } + } + + stream << "}"; + return stream; +} + +inline Unigram::Unigram() : score(0.0) {} + +inline bool Unigram::operator==(const Unigram& another) const { + return keyValue == another.keyValue && score == another.score; +} + +inline bool Unigram::operator<(const Unigram& another) const { + if (keyValue < another.keyValue) { + return true; + } else if (keyValue == another.keyValue) { + return score < another.score; + } + return false; +} + +inline bool Unigram::ScoreCompare(const Unigram& a, const Unigram& b) { + return a.score > b.score; +} +} // namespace Gramambular +} // namespace Taiyan + #endif diff --git a/Source/Modules/LanguageParsers/Gramambular/Walker.h b/Source/Modules/LanguageParsers/Gramambular/Walker.h index 06c2be3d..fdb035d6 100644 --- a/Source/Modules/LanguageParsers/Gramambular/Walker.h +++ b/Source/Modules/LanguageParsers/Gramambular/Walker.h @@ -17,67 +17,69 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef Walker_h -#define Walker_h +#ifndef WALKER_H_ +#define WALKER_H_ #include +#include + #include "Grid.h" namespace Taiyan { - namespace Gramambular { - using namespace std; +namespace Gramambular { - class Walker { - public: - Walker(Grid* inGrid); - const vector reverseWalk(size_t inLocation, double inAccumulatedScore = 0.0); - - protected: - Grid* m_grid; - }; - - inline Walker::Walker(Grid* inGrid) - : m_grid(inGrid) - { +class Walker { +public: + explicit Walker(Grid* inGrid); + const std::vector reverseWalk(size_t location, + double accumulatedScore = 0.0); + +protected: + Grid* m_grid; +}; + +inline Walker::Walker(Grid* inGrid) : m_grid(inGrid) {} + +inline const std::vector Walker::reverseWalk( + size_t location, double accumulatedScore) { + if (!location || location > m_grid->width()) { + return std::vector(); + } + + std::vector > paths; + + std::vector nodes = m_grid->nodesEndingAt(location); + + for (std::vector::iterator ni = nodes.begin(); ni != nodes.end(); + ++ni) { + if (!(*ni).node) { + continue; } - inline const vector Walker::reverseWalk(size_t inLocation, double inAccumulatedScore) - { - if (!inLocation || inLocation > m_grid->width()) { - return vector(); - } - - vector > paths; - - vector nodes = m_grid->nodesEndingAt(inLocation); - - for (vector::iterator ni = nodes.begin() ; ni != nodes.end() ; ++ni) { - if (!(*ni).node) { - continue; - } - - (*ni).accumulatedScore = inAccumulatedScore + (*ni).node->score(); - - vector path = reverseWalk(inLocation - (*ni).spanningLength, (*ni).accumulatedScore); - path.insert(path.begin(), *ni); - - paths.push_back(path); - } - - if (!paths.size()) { - return vector(); - } - - vector* result = &*(paths.begin()); - for (vector >::iterator pi = paths.begin() ; pi != paths.end() ; ++pi) { - if ((*pi).back().accumulatedScore > result->back().accumulatedScore) { - result = &*pi; - } - } - - return *result; + (*ni).accumulatedScore = accumulatedScore + (*ni).node->score(); + + std::vector path = + reverseWalk(location - (*ni).spanningLength, (*ni).accumulatedScore); + path.insert(path.begin(), *ni); + + paths.push_back(path); + } + + if (!paths.size()) { + return std::vector(); + } + + std::vector* result = &*(paths.begin()); + for (std::vector >::iterator pi = paths.begin(); + pi != paths.end(); ++pi) { + if ((*pi).back().accumulatedScore > result->back().accumulatedScore) { + result = &*pi; } } + + return *result; } +} // namespace Gramambular +} // namespace Taiyan #endif diff --git a/Source/README b/Source/README deleted file mode 100644 index 1092f5c7..00000000 --- a/Source/README +++ /dev/null @@ -1,182 +0,0 @@ -. -├── AppDelegate.swift -├── Base.lproj -│   ├── Credits.rtf -│   ├── InfoPlist.strings -│   ├── Localizable.strings -│   ├── MainMenu.xib -│   ├── preferences.xib -│   ├── template-data.txt -│   ├── template-exclude-phrases-plain-bpmf.txt -│   ├── template-exclude-phrases.txt -│   └── template-phrases-replacement.txt -├── Data -│   ├── BPMFBase.txt -│   ├── BPMFMappings.txt -│   ├── BPMFPunctuations.txt -│   ├── Makefile -│   ├── PhraseFreq.txt -│   ├── README -│   ├── Symbols.txt -│   ├── associated-phrases.cin -│   ├── bin -│   │   ├── C_Version -│   │   │   ├── Makefile -│   │   │   ├── count.bash -│   │   │   └── count.occurrence.c -│   │   ├── README -│   │   ├── Sample_Prep -│   │   │   ├── build.bash -│   │   │   └── filter.bash -│   │   ├── bpmfmap.py -│   │   ├── buildFreq.py -│   │   ├── cook-plain-bpmf.py -│   │   ├── cook.py -│   │   ├── cook_util.py -│   │   ├── count.bash -│   │   ├── count.occurrence.py -│   │   ├── disabled -│   │   │   ├── BIG5toUTF8.pl -│   │   │   ├── bpmfmap_human.py -│   │   │   ├── build4wlist.bash -│   │   │   ├── buildFreq.bash -│   │   │   ├── cook.rb -│   │   │   ├── count.occurrence.pl -│   │   │   ├── countphrase.bash -│   │   │   ├── randomShuffle.bash -│   │   │   ├── typocorrection.bash -│   │   │   └── utf8length.pl -│   │   ├── nonCJK_filter.py -│   │   ├── self-score-test.py -│   │   └── textpool.rc -│   ├── data-plain-bpmf.txt -│   ├── data.txt -│   ├── exclusion.txt -│   ├── heterophony1.list -│   ├── heterophony2.list -│   ├── heterophony3.list -│   ├── memo -│   │   ├── blacklist.txt -│   │   ├── covered_by_others.txt -│   │   ├── covered_by_singles.txt -│   │   └── falsecount.txt -│   └── phrase.occ -├── Engine -│   ├── AssociatedPhrases.cpp -│   ├── AssociatedPhrases.h -│   ├── CMakeLists.txt -│   ├── Gramambular -│   │   ├── Bigram.h -│   │   ├── BlockReadingBuilder.h -│   │   ├── Gramambular.h -│   │   ├── Grid.h -│   │   ├── KeyValuePair.h -│   │   ├── LanguageModel.h -│   │   ├── Node.h -│   │   ├── NodeAnchor.h -│   │   ├── Span.h -│   │   ├── Unigram.h -│   │   └── Walker.h -│   ├── KeyValueBlobReader.cpp -│   ├── KeyValueBlobReader.h -│   ├── KeyValueBlobReaderTest.cpp -│   ├── Mandarin -│   │   ├── CMakeLists.txt -│   │   ├── Mandarin.cpp -│   │   ├── Mandarin.h -│   │   └── MandarinTest.cpp -│   ├── McBopomofoLM.cpp -│   ├── McBopomofoLM.h -│   ├── ParselessLM.cpp -│   ├── ParselessLM.h -│   ├── ParselessLMBenchmark.cpp -│   ├── ParselessLMTest.cpp -│   ├── ParselessPhraseDB.cpp -│   ├── ParselessPhraseDB.h -│   ├── ParselessPhraseDBTest.cpp -│   ├── PhraseReplacementMap.cpp -│   ├── PhraseReplacementMap.h -│   ├── PhraseReplacementMapTest.cpp -│   ├── UserOverrideModel.cpp -│   ├── UserOverrideModel.h -│   ├── UserPhrasesLM.cpp -│   ├── UserPhrasesLM.h -│   └── UserPhrasesLMTest.cpp -├── Images -│   ├── Bopomofo.tiff -│   ├── Bopomofo@2x.tiff -│   ├── Images.xcassets -│   │   ├── AlertIcon.imageset -│   │   │   ├── 128X128.png -│   │   │   ├── 192x192.png -│   │   │   ├── 64X64.png -│   │   │   └── Contents.json -│   │   ├── AppIcon.appiconset -│   │   │   ├── 1024X1024.png -│   │   │   ├── 128X128.png -│   │   │   ├── 16X16.png -│   │   │   ├── 256X256.png -│   │   │   ├── 32X32.png -│   │   │   ├── 512X512.png -│   │   │   ├── 64X64.png -│   │   │   └── Contents.json -│   │   └── Contents.json -│   ├── PlainBopomofo.tiff -│   └── PlainBopomofo@2x.tiff -├── InputMethodController.swift -├── InputState.swift -├── Installer -│   ├── AppDelegate.swift -│   ├── ArchiveUtil.swift -│   ├── Base.lproj -│   │   └── MainMenu.xib -│   ├── BundleTranslocate.h -│   ├── BundleTranslocate.m -│   ├── Installer-Info.plist -│   ├── Installer-Prefix.pch -│   ├── McBopomofoInstaller-Bridging-Header.h -│   ├── NotarizedArchives -│   │   └── README.md -│   ├── en.lproj -│   │   ├── InfoPlist.strings -│   │   ├── License.rtf -│   │   └── Localizable.strings -│   └── zh-Hant.lproj -│   ├── InfoPlist.strings -│   ├── License.rtf -│   ├── Localizable.strings -│   └── MainMenu.xib -├── KeyHandler.h -├── KeyHandler.mm -├── KeyHandlerInput.swift -├── LanguageModelManager+Privates.h -├── LanguageModelManager.h -├── LanguageModelManager.mm -├── McBopomofo-Bridging-Header.h -├── McBopomofo-Info.plist -├── McBopomofo-Prefix.pch -├── NonModalAlertWindowController.swift -├── NonModalAlertWindowController.xib -├── Preferences.swift -├── PreferencesWindowController.swift -├── README -├── Tools -│   ├── genRTF.py -│   └── tistool.m -├── en.lproj -│   ├── Credits.rtf -│   ├── InfoPlist.strings -│   └── Localizable.strings -├── main.swift -└── zh-Hant.lproj - ├── Credits.rtf - ├── InfoPlist.strings - ├── Localizable.strings - ├── MainMenu.xib - ├── preferences.xib - ├── template-data.txt - ├── template-exclude-phrases-plain-bpmf.txt - ├── template-exclude-phrases.txt - └── template-phrases-replacement.txt - -22 directories, 157 files diff --git a/Source/Resources/Base.lproj/Localizable.strings b/Source/Resources/Base.lproj/Localizable.strings index 9f854dac..fac28d72 100644 --- a/Source/Resources/Base.lproj/Localizable.strings +++ b/Source/Resources/Base.lproj/Localizable.strings @@ -24,7 +24,7 @@ "\"%@\" length must ≥ 2 for a user phrase." = "\"%@\" length must ≥ 2 for a user phrase."; "\"%@\" length should ≤ %d for a user phrase." = "\"%@\" length should ≤ %d for a user phrase."; "\"%@\" selected. ENTER to add user phrase." = "\"%@\" selected. ENTER to add user phrase."; -"\"%@\" already exists." = "\"%@\" already exists."; +"\"%@\" already exists, ENTER to boost its priority." = "\"%@\" already exists, ENTER to boost its priority."; "Edit Phrase Replacement Table…" = "Edit Phrase Replacement Table…"; "Use Phrase Replacement" = "Use Phrase Replacement"; "Candidates keys cannot be empty." = "Candidates keys cannot be empty."; diff --git a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/zh.lproj/InfoPlist.strings b/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/zh.lproj/InfoPlist.strings deleted file mode 100644 index 08c98689..00000000 Binary files a/Source/Resources/KeyLayouts/vChewingKeyLayout.bundle/Contents/Resources/zh.lproj/InfoPlist.strings and /dev/null differ diff --git a/Source/Resources/en.lproj/Localizable.strings b/Source/Resources/en.lproj/Localizable.strings index 9f854dac..fac28d72 100644 --- a/Source/Resources/en.lproj/Localizable.strings +++ b/Source/Resources/en.lproj/Localizable.strings @@ -24,7 +24,7 @@ "\"%@\" length must ≥ 2 for a user phrase." = "\"%@\" length must ≥ 2 for a user phrase."; "\"%@\" length should ≤ %d for a user phrase." = "\"%@\" length should ≤ %d for a user phrase."; "\"%@\" selected. ENTER to add user phrase." = "\"%@\" selected. ENTER to add user phrase."; -"\"%@\" already exists." = "\"%@\" already exists."; +"\"%@\" already exists, ENTER to boost its priority." = "\"%@\" already exists, ENTER to boost its priority."; "Edit Phrase Replacement Table…" = "Edit Phrase Replacement Table…"; "Use Phrase Replacement" = "Use Phrase Replacement"; "Candidates keys cannot be empty." = "Candidates keys cannot be empty."; diff --git a/Source/Resources/ja.lproj/Localizable.strings b/Source/Resources/ja.lproj/Localizable.strings index df40d67c..00026872 100644 --- a/Source/Resources/ja.lproj/Localizable.strings +++ b/Source/Resources/ja.lproj/Localizable.strings @@ -24,7 +24,7 @@ "\"%@\" length must ≥ 2 for a user phrase." = "「%@」もう1つ文字のお選びを。"; "\"%@\" length should ≤ %d for a user phrase." = "「%@」文字数過剰で登録不可、%d 文字以内にして下さい。"; "\"%@\" selected. ENTER to add user phrase." = "「%@」を ENTER で辞書に登録。"; -"\"%@\" already exists." = "「%@」は既存語彙である。"; +"\"%@\" already exists, ENTER to boost its priority." = "「%@」は既存語彙であり、ENTER で最優先にする。"; "Edit Phrase Replacement Table…" = "言葉置換表を編集…"; "Use Phrase Replacement" = "言葉置換機能"; "Candidates keys cannot be empty." = "言選り用キー陣列に何かキーをご登録ください。"; diff --git a/Source/Resources/zh-Hans.lproj/Localizable.strings b/Source/Resources/zh-Hans.lproj/Localizable.strings index 12bb250c..bee4cf8e 100644 --- a/Source/Resources/zh-Hans.lproj/Localizable.strings +++ b/Source/Resources/zh-Hans.lproj/Localizable.strings @@ -24,7 +24,7 @@ "\"%@\" length must ≥ 2 for a user phrase." = "「%@」字数不足以自订语汇。"; "\"%@\" length should ≤ %d for a user phrase." = "「%@」字数超过 %d、无法自订。"; "\"%@\" selected. ENTER to add user phrase." = "「%@」敲 Enter 添入自订语汇。"; -"\"%@\" already exists." = "「%@」已存在。"; +"\"%@\" already exists, ENTER to boost its priority." = "「%@」已存在,敲 ENTER 以提升其权重。"; "Edit Phrase Replacement Table…" = "编辑语汇置换表…"; "Use Phrase Replacement" = "使用语汇置换"; "Candidates keys cannot be empty." = "您必须指定选字键。"; diff --git a/Source/Resources/zh-Hant.lproj/Localizable.strings b/Source/Resources/zh-Hant.lproj/Localizable.strings index 783fa8dd..3a1b9998 100644 --- a/Source/Resources/zh-Hant.lproj/Localizable.strings +++ b/Source/Resources/zh-Hant.lproj/Localizable.strings @@ -24,7 +24,7 @@ "\"%@\" length must ≥ 2 for a user phrase." = "「%@」字數不足以自訂語彙。"; "\"%@\" length should ≤ %d for a user phrase." = "「%@」字數超過 %d、無法自訂。"; "\"%@\" selected. ENTER to add user phrase." = "「%@」敲 Enter 添入自訂語彙。"; -"\"%@\" already exists." = "「%@」已存在。"; +"\"%@\" already exists, ENTER to boost its priority." = "「%@」已存在,敲 ENTER 以提升其權重。"; "Edit Phrase Replacement Table…" = "編輯語彙置換表…"; "Use Phrase Replacement" = "使用語彙置換"; "Candidates keys cannot be empty." = "您必須指定選字鍵。"; diff --git a/Source/WindowControllers/ctlPrefWindow.swift b/Source/WindowControllers/ctlPrefWindow.swift index ebdd9695..b2b11896 100644 --- a/Source/WindowControllers/ctlPrefWindow.swift +++ b/Source/WindowControllers/ctlPrefWindow.swift @@ -86,7 +86,7 @@ extension RangeReplaceableCollection where Element: Hashable { let menuItem_vChewingDachen = NSMenuItem() menuItem_vChewingDachen.title = String(format: NSLocalizedString("vChewing Dachen (Not Finished Yet)", comment: "")) - menuItem_vChewingDachen.representedObject = String("org.atelierInmu.keyboardlayout.vChewingKeyLayout.zhuyindachen") + menuItem_vChewingDachen.representedObject = String("org.atelierInmu.keyboardlayout.vChewingKeyLayout.vChewingDachen") basisKeyboardLayoutButton.menu?.addItem(menuItem_vChewingDachen) let basisKeyboardLayoutID = Preferences.basisKeyboardLayout diff --git a/Update-Info.plist b/Update-Info.plist index 4fc78e67..dc3e903d 100644 --- a/Update-Info.plist +++ b/Update-Info.plist @@ -7,8 +7,8 @@ UpdateInfoSite https://gitee.com/vchewing/vChewing-macOS CFBundleVersion - 1922 + 1923 CFBundleShortVersionString - 1.3.3 + 1.3.4 diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index f7e2c7d7..916c2a5b 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ 5B11328927B94CFB00E58451 /* AppleKeyboardConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B11328827B94CFB00E58451 /* AppleKeyboardConverter.swift */; }; 5B2DB16F27AF6891006D874E /* data-chs.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5B2DB16D27AF6891006D874E /* data-chs.txt */; }; 5B2DB17027AF6891006D874E /* data-cht.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5B2DB16E27AF6891006D874E /* data-cht.txt */; }; - 5B30F11327BA568800484E24 /* vChewingKeyLayout.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */; }; 5B62A31727AE73A700A19448 /* unzip.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A30927AE73A700A19448 /* unzip.m */; }; 5B62A31827AE73A700A19448 /* zip.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A30A27AE73A700A19448 /* zip.m */; }; 5B62A31927AE73A700A19448 /* ioapi.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A30B27AE73A700A19448 /* ioapi.m */; }; @@ -50,6 +49,12 @@ 5BD05C6827B2BBEF004C4F1D /* Content.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD05C6327B2BBEF004C4F1D /* Content.swift */; }; 5BD05C6927B2BBEF004C4F1D /* WindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD05C6427B2BBEF004C4F1D /* WindowController.swift */; }; 5BD05C6A27B2BBEF004C4F1D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD05C6527B2BBEF004C4F1D /* ViewController.swift */; }; + 5BDC5CAB27C2873D00E1CCE2 /* Grid.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5BDC5CAA27C2873D00E1CCE2 /* Grid.mm */; }; + 5BDC5CB327C28E8B00E1CCE2 /* icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 5BDC5CB227C28E8B00E1CCE2 /* icon.icns */; }; + 5BDC5CB527C28E8B00E1CCE2 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDC5CB427C28E8B00E1CCE2 /* ShareViewController.swift */; }; + 5BDC5CB827C28E8B00E1CCE2 /* ShareViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BDC5CB627C28E8B00E1CCE2 /* ShareViewController.xib */; }; + 5BDC5CBD27C28E8B00E1CCE2 /* KeyboardExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5BDC5CB027C28E8B00E1CCE2 /* KeyboardExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 5BDC5CC227C2941F00E1CCE2 /* vChewingKeyLayout.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */; }; 5BDCBB2E27B4E67A00D0CC59 /* vChewingPhraseEditor.app in Resources */ = {isa = PBXBuildFile; fileRef = 5BD05BB827B2A429004C4F1D /* vChewingPhraseEditor.app */; }; 5BE78BD927B3775B005EA1BE /* ctlAboutWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BE78BD827B37750005EA1BE /* ctlAboutWindow.swift */; }; 5BE78BDD27B3776D005EA1BE /* frmAboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BE78BDA27B37764005EA1BE /* frmAboutWindow.xib */; }; @@ -68,7 +73,7 @@ 6ACC3D442793701600F1B140 /* ParselessPhraseDB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6ACC3D402793701600F1B140 /* ParselessPhraseDB.cpp */; }; 6ACC3D452793701600F1B140 /* ParselessLM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6ACC3D422793701600F1B140 /* ParselessLM.cpp */; }; D41355D8278D74B5005E5CBD /* mgrLangModel.mm in Sources */ = {isa = PBXBuildFile; fileRef = D41355D7278D7409005E5CBD /* mgrLangModel.mm */; }; - D41355DB278E6D17005E5CBD /* vChewingLM.mm in Sources */ = {isa = PBXBuildFile; fileRef = D41355D9278E6D17005E5CBD /* vChewingLM.mm */; }; + D41355DB278E6D17005E5CBD /* LMInstantiator.mm in Sources */ = {isa = PBXBuildFile; fileRef = D41355D9278E6D17005E5CBD /* LMInstantiator.mm */; }; D41355DE278EA3ED005E5CBD /* UserPhrasesLM.mm in Sources */ = {isa = PBXBuildFile; fileRef = D41355DC278EA3ED005E5CBD /* UserPhrasesLM.mm */; }; D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427F76B278CA1BA004A2160 /* AppDelegate.swift */; }; D44FB74D2792189A003C80A6 /* PhraseReplacementMap.mm in Sources */ = {isa = PBXBuildFile; fileRef = D44FB74B2792189A003C80A6 /* PhraseReplacementMap.mm */; }; @@ -96,6 +101,13 @@ remoteGlobalIDString = 5BD05BB727B2A429004C4F1D; remoteInfo = vChewingPhraseEditor; }; + 5BDC5CBB27C28E8B00E1CCE2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6A0D4E9415FC0CFA00ABF4B3 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5BDC5CAF27C28E8B00E1CCE2; + remoteInfo = KeyboardExtension; + }; 6A38BC2515FC131100A8A51F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 6A0D4E9415FC0CFA00ABF4B3 /* Project object */; @@ -112,6 +124,20 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 5BDC5CBE27C28E8B00E1CCE2 /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 5BDC5CBD27C28E8B00E1CCE2 /* KeyboardExtension.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 5B04305327B529D800CB65BC /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; 5B04305427B529D800CB65BC /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; @@ -195,6 +221,13 @@ 5BD05C6327B2BBEF004C4F1D /* Content.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Content.swift; sourceTree = ""; }; 5BD05C6427B2BBEF004C4F1D /* WindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WindowController.swift; sourceTree = ""; }; 5BD05C6527B2BBEF004C4F1D /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 5BDC5CAA27C2873D00E1CCE2 /* Grid.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Grid.mm; sourceTree = ""; }; + 5BDC5CB027C28E8B00E1CCE2 /* KeyboardExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = KeyboardExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 5BDC5CB227C28E8B00E1CCE2 /* icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = icon.icns; sourceTree = ""; }; + 5BDC5CB427C28E8B00E1CCE2 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; + 5BDC5CB727C28E8B00E1CCE2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ShareViewController.xib; sourceTree = ""; }; + 5BDC5CB927C28E8B00E1CCE2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5BDC5CBA27C28E8B00E1CCE2 /* KeyboardExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = KeyboardExtension.entitlements; sourceTree = ""; }; 5BDCBB4227B4F6C600D0CC59 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/MainMenu.strings"; sourceTree = ""; }; 5BDCBB4327B4F6C600D0CC59 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/frmAboutWindow.strings"; sourceTree = ""; }; 5BDCBB4527B4F6C600D0CC59 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings"; sourceTree = ""; }; @@ -243,8 +276,8 @@ 6ACC3D432793701600F1B140 /* ParselessLM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParselessLM.h; sourceTree = ""; }; D41355D6278D7409005E5CBD /* mgrLangModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mgrLangModel.h; sourceTree = ""; }; D41355D7278D7409005E5CBD /* mgrLangModel.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = mgrLangModel.mm; sourceTree = ""; }; - D41355D9278E6D17005E5CBD /* vChewingLM.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = vChewingLM.mm; sourceTree = ""; }; - D41355DA278E6D17005E5CBD /* vChewingLM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vChewingLM.h; sourceTree = ""; }; + D41355D9278E6D17005E5CBD /* LMInstantiator.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LMInstantiator.mm; sourceTree = ""; }; + D41355DA278E6D17005E5CBD /* LMInstantiator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LMInstantiator.h; sourceTree = ""; }; D41355DC278EA3ED005E5CBD /* UserPhrasesLM.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = UserPhrasesLM.mm; sourceTree = ""; }; D41355DD278EA3ED005E5CBD /* UserPhrasesLM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UserPhrasesLM.h; sourceTree = ""; }; D427A9BF25ED28CC005D43E0 /* vChewing-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "vChewing-Bridging-Header.h"; sourceTree = ""; }; @@ -280,6 +313,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5BDC5CAD27C28E8B00E1CCE2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 6A0D4E9F15FC0D2D00ABF4B3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -297,14 +337,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 5B30F10727BA501900484E24 /* KeyLayouts */ = { - isa = PBXGroup; - children = ( - 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */, - ); - path = KeyLayouts; - sourceTree = ""; - }; 5B62A30127AE732800A19448 /* 3rdParty */ = { isa = PBXGroup; children = ( @@ -423,12 +455,12 @@ 5B62A32427AE757300A19448 /* LangModelRelated */ = { isa = PBXGroup; children = ( + D41355D9278E6D17005E5CBD /* LMInstantiator.mm */, + D41355DA278E6D17005E5CBD /* LMInstantiator.h */, D41355D6278D7409005E5CBD /* mgrLangModel.h */, D495583A27A5C6C4006ADE1C /* mgrLangModel_Privates.h */, D41355D7278D7409005E5CBD /* mgrLangModel.mm */, 5B62A32527AE758000A19448 /* SubLanguageModels */, - D41355D9278E6D17005E5CBD /* vChewingLM.mm */, - D41355DA278E6D17005E5CBD /* vChewingLM.h */, ); path = LangModelRelated; sourceTree = ""; @@ -459,7 +491,6 @@ 5B62A33027AE78E500A19448 /* Resources */ = { isa = PBXGroup; children = ( - 5B30F10727BA501900484E24 /* KeyLayouts */, 6A0D4EEE15FC0DA600ABF4B3 /* Images */, 5BBBB76E27AED70B0023B93A /* MenuIcons */, 5BBBB75C27AED54C0023B93A /* SoundFiles */, @@ -596,6 +627,19 @@ path = Resources; sourceTree = ""; }; + 5BDC5CB127C28E8B00E1CCE2 /* KeyboardExtension */ = { + isa = PBXGroup; + children = ( + 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */, + 5BDC5CB227C28E8B00E1CCE2 /* icon.icns */, + 5BDC5CB427C28E8B00E1CCE2 /* ShareViewController.swift */, + 5BDC5CB627C28E8B00E1CCE2 /* ShareViewController.xib */, + 5BDC5CB927C28E8B00E1CCE2 /* Info.plist */, + 5BDC5CBA27C28E8B00E1CCE2 /* KeyboardExtension.entitlements */, + ); + path = KeyboardExtension; + sourceTree = ""; + }; 6A0D4E9215FC0CFA00ABF4B3 = { isa = PBXGroup; children = ( @@ -603,6 +647,7 @@ 6ACA41E715FC1D9000935EF6 /* Installer */, 6A0D4EC215FC0D3C00ABF4B3 /* Source */, 5BD05BB927B2A429004C4F1D /* UserPhraseEditor */, + 5BDC5CB127C28E8B00E1CCE2 /* KeyboardExtension */, 6A0D4EA315FC0D2D00ABF4B3 /* Products */, D47D73C127A7200500255A50 /* Frameworks */, ); @@ -614,6 +659,7 @@ 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */, 6ACA41CB15FC1D7500935EF6 /* vChewingInstaller.app */, 5BD05BB827B2A429004C4F1D /* vChewingPhraseEditor.app */, + 5BDC5CB027C28E8B00E1CCE2 /* KeyboardExtension.appex */, ); name = Products; sourceTree = ""; @@ -663,6 +709,7 @@ 6A0D4F1515FC0EB100ABF4B3 /* BlockReadingBuilder.h */, 6A0D4F1615FC0EB100ABF4B3 /* Gramambular.h */, 6A0D4F1715FC0EB100ABF4B3 /* Grid.h */, + 5BDC5CAA27C2873D00E1CCE2 /* Grid.mm */, 6A0D4F1815FC0EB100ABF4B3 /* KeyValuePair.h */, 6A0D4F1915FC0EB100ABF4B3 /* LanguageModel.h */, 6A0D4F1A15FC0EB100ABF4B3 /* Node.h */, @@ -734,6 +781,23 @@ productReference = 5BD05BB827B2A429004C4F1D /* vChewingPhraseEditor.app */; productType = "com.apple.product-type.application"; }; + 5BDC5CAF27C28E8B00E1CCE2 /* KeyboardExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5BDC5CC127C28E8B00E1CCE2 /* Build configuration list for PBXNativeTarget "KeyboardExtension" */; + buildPhases = ( + 5BDC5CAC27C28E8B00E1CCE2 /* Sources */, + 5BDC5CAD27C28E8B00E1CCE2 /* Frameworks */, + 5BDC5CAE27C28E8B00E1CCE2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = KeyboardExtension; + productName = KeyboardExtension; + productReference = 5BDC5CB027C28E8B00E1CCE2 /* KeyboardExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; 6A0D4EA115FC0D2D00ABF4B3 /* vChewing */ = { isa = PBXNativeTarget; buildConfigurationList = 6A0D4EC015FC0D2E00ABF4B3 /* Build configuration list for PBXNativeTarget "vChewing" */; @@ -741,12 +805,14 @@ 6A0D4E9E15FC0D2D00ABF4B3 /* Sources */, 6A0D4E9F15FC0D2D00ABF4B3 /* Frameworks */, 6A0D4EA015FC0D2D00ABF4B3 /* Resources */, + 5BDC5CBE27C28E8B00E1CCE2 /* Embed App Extensions */, ); buildRules = ( ); dependencies = ( 5B0AF8B327B2C4E20096FE54 /* PBXTargetDependency */, 6A38BC2615FC131100A8A51F /* PBXTargetDependency */, + 5BDC5CBC27C28E8B00E1CCE2 /* PBXTargetDependency */, ); name = vChewing; packageProductDependencies = ( @@ -790,6 +856,10 @@ LastSwiftMigration = 1320; ProvisioningStyle = Automatic; }; + 5BDC5CAF27C28E8B00E1CCE2 = { + CreatedOnToolsVersion = 13.2; + ProvisioningStyle = Automatic; + }; 6A0D4EA115FC0D2D00ABF4B3 = { LastSwiftMigration = 1240; ProvisioningStyle = Automatic; @@ -821,6 +891,7 @@ 6A0D4EA115FC0D2D00ABF4B3 /* vChewing */, 6ACA41CA15FC1D7500935EF6 /* vChewingInstaller */, 5BD05BB727B2A429004C4F1D /* vChewingPhraseEditor */, + 5BDC5CAF27C28E8B00E1CCE2 /* KeyboardExtension */, 6A38BC2115FC12FD00A8A51F /* Data */, ); }; @@ -838,6 +909,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5BDC5CAE27C28E8B00E1CCE2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5BDC5CB827C28E8B00E1CCE2 /* ShareViewController.xib in Resources */, + 5BDC5CC227C2941F00E1CCE2 /* vChewingKeyLayout.bundle in Resources */, + 5BDC5CB327C28E8B00E1CCE2 /* icon.icns in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 6A0D4EA015FC0D2D00ABF4B3 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -858,7 +939,6 @@ 5BBBB77627AED70B0023B93A /* MenuIcon-TCVIM.png in Resources */, 6A187E2616004C5900466B2E /* MainMenu.xib in Resources */, 5BBBB75F27AED54C0023B93A /* Beep.m4a in Resources */, - 5B30F11327BA568800484E24 /* vChewingKeyLayout.bundle in Resources */, 5B2DB16F27AF6891006D874E /* data-chs.txt in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -913,6 +993,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5BDC5CAC27C28E8B00E1CCE2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5BDC5CB527C28E8B00E1CCE2 /* ShareViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 6A0D4E9E15FC0D2D00ABF4B3 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -937,12 +1025,13 @@ 5B11328927B94CFB00E58451 /* AppleKeyboardConverter.swift in Sources */, 5B62A31827AE73A700A19448 /* zip.m in Sources */, 5B62A32E27AE78B000A19448 /* CNSLM.mm in Sources */, - D41355DB278E6D17005E5CBD /* vChewingLM.mm in Sources */, + D41355DB278E6D17005E5CBD /* LMInstantiator.mm in Sources */, 5B62A31A27AE73A700A19448 /* mztools.m in Sources */, 5B62A32927AE77D100A19448 /* FSEventStreamHelper.swift in Sources */, D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */, 5B62A33627AE795800A19448 /* PreferencesModule.swift in Sources */, 5B62A33827AE79CD00A19448 /* NSStringUtils.swift in Sources */, + 5BDC5CAB27C2873D00E1CCE2 /* Grid.mm in Sources */, 5B62A33227AE792F00A19448 /* InputSourceHelper.swift in Sources */, 5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */, 6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */, @@ -979,6 +1068,11 @@ target = 5BD05BB727B2A429004C4F1D /* vChewingPhraseEditor */; targetProxy = 5B0AF8B227B2C4E20096FE54 /* PBXContainerItemProxy */; }; + 5BDC5CBC27C28E8B00E1CCE2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5BDC5CAF27C28E8B00E1CCE2 /* KeyboardExtension */; + targetProxy = 5BDC5CBB27C28E8B00E1CCE2 /* PBXContainerItemProxy */; + }; 6A38BC2615FC131100A8A51F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 6A38BC2115FC12FD00A8A51F /* Data */; @@ -1046,6 +1140,14 @@ name = Main.storyboard; sourceTree = ""; }; + 5BDC5CB627C28E8B00E1CCE2 /* ShareViewController.xib */ = { + isa = PBXVariantGroup; + children = ( + 5BDC5CB727C28E8B00E1CCE2 /* Base */, + ); + name = ShareViewController.xib; + sourceTree = ""; + }; 5BE78BDA27B37764005EA1BE /* frmAboutWindow.xib */ = { isa = PBXVariantGroup; children = ( @@ -1147,7 +1249,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1922; + CURRENT_PROJECT_VERSION = 1923; DEBUG_INFORMATION_FORMAT = dwarf; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; @@ -1166,7 +1268,7 @@ INFOPLIST_KEY_NSPrincipalClass = NSApplication; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.3.3; + MARKETING_VERSION = 1.3.4; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor; @@ -1199,7 +1301,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1922; + CURRENT_PROJECT_VERSION = 1923; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1213,7 +1315,7 @@ INFOPLIST_KEY_NSPrincipalClass = NSApplication; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.3.3; + MARKETING_VERSION = 1.3.4; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor; @@ -1225,6 +1327,102 @@ }; name = Release; }; + 5BDC5CBF27C28E8B00E1CCE2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = KeyboardExtension/KeyboardExtension.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1923; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_ASSET_PATHS = KeyboardExtension/vChewingKeyLayout.bundle; + DEVELOPMENT_TEAM = ""; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = KeyboardExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = KeyboardExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 12.1; + MARKETING_VERSION = 1.3.4; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing.KeyboardExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5BDC5CC027C28E8B00E1CCE2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = KeyboardExtension/KeyboardExtension.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1923; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_ASSET_PATHS = KeyboardExtension/vChewingKeyLayout.bundle; + DEVELOPMENT_TEAM = ""; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = KeyboardExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = KeyboardExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 12.1; + MARKETING_VERSION = 1.3.4; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing.KeyboardExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; 6A0D4E9915FC0CFA00ABF4B3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1311,6 +1509,7 @@ 6A0D4EBE15FC0D2E00ABF4B3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_CXX_LANGUAGE_STANDARD = "c++17"; @@ -1327,8 +1526,8 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1922; - DEVELOPMENT_ASSET_PATHS = Source/Resources/KeyLayouts/vChewingKeyLayout.bundle; + CURRENT_PROJECT_VERSION = 1923; + DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; @@ -1359,7 +1558,7 @@ INFOPLIST_FILE = "Source/Resources/IME-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.3.3; + MARKETING_VERSION = 1.3.4; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1375,6 +1574,7 @@ 6A0D4EBF15FC0D2E00ABF4B3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_CXX_LANGUAGE_STANDARD = "c++17"; @@ -1391,9 +1591,9 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1922; + CURRENT_PROJECT_VERSION = 1923; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_ASSET_PATHS = Source/Resources/KeyLayouts/vChewingKeyLayout.bundle; + DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; @@ -1417,7 +1617,7 @@ INFOPLIST_FILE = "Source/Resources/IME-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.3.3; + MARKETING_VERSION = 1.3.4; PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1500,7 +1700,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1922; + CURRENT_PROJECT_VERSION = 1923; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; @@ -1522,7 +1722,7 @@ INFOPLIST_FILE = "Installer/Installer-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.3.3; + MARKETING_VERSION = 1.3.4; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1550,7 +1750,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1922; + CURRENT_PROJECT_VERSION = 1923; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -1566,7 +1766,7 @@ INFOPLIST_FILE = "Installer/Installer-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11.5; - MARKETING_VERSION = 1.3.3; + MARKETING_VERSION = 1.3.4; PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1589,6 +1789,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 5BDC5CC127C28E8B00E1CCE2 /* Build configuration list for PBXNativeTarget "KeyboardExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5BDC5CBF27C28E8B00E1CCE2 /* Debug */, + 5BDC5CC027C28E8B00E1CCE2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 6A0D4E9715FC0CFA00ABF4B3 /* Build configuration list for PBXProject "vChewing" */ = { isa = XCConfigurationList; buildConfigurations = (