From 49a60c54c7c4ac0c77169a6ec873560dc78afb2c Mon Sep 17 00:00:00 2001 From: groverlynn Date: Mon, 14 Aug 2023 09:38:19 +0200 Subject: [PATCH] inline placeholder --- SquirrelInputController.m | 126 ++++++++++++++++++++++++-------------- data/squirrel.yaml | 7 +++ 2 files changed, 88 insertions(+), 45 deletions(-) diff --git a/SquirrelInputController.m b/SquirrelInputController.m index 87bfbb654..cbc7922bb 100644 --- a/SquirrelInputController.m +++ b/SquirrelInputController.m @@ -10,7 +10,7 @@ @interface SquirrelInputController(Private) -(void)createSession; -(void)destroySession; --(void)rimeConsumeCommittedText; +-(BOOL)rimeConsumeCommittedText; -(void)rimeUpdate; -(void)updateAppOptions; @end @@ -18,8 +18,9 @@ -(void)updateAppOptions; const int N_KEY_ROLL_OVER = 50; @implementation SquirrelInputController { - id _currentClient; - NSString *_preeditString; + NSMutableAttributedString *_preeditString; + NSAttributedString *_originalString; + NSString *_composedString; NSRange _selRange; NSUInteger _caretPos; NSArray *_candidates; @@ -29,6 +30,9 @@ @implementation SquirrelInputController { NSString *_schemaId; BOOL _inlinePreedit; BOOL _inlineCandidate; + // app-specific bug fix + BOOL _inlinePlaceHolder; + BOOL _panellessCommitFix; // for chord-typing int _chordKeyCodes[N_KEY_ROLL_OVER]; int _chordModifiers[N_KEY_ROLL_OVER]; @@ -49,9 +53,6 @@ - (BOOL)handleEvent:(NSEvent*)event client:(id)sender // Key processing will not continue in that case. In other words the // system will not deliver a key down event to the application. // Returning NO means the original key down will be passed on to the client. - - _currentClient = sender; - NSUInteger modifiers = event.modifierFlags; BOOL handled = NO; @@ -64,7 +65,7 @@ - (BOOL)handleEvent:(NSEvent*)event client:(id)sender } } - NSString* app = [_currentClient bundleIdentifier]; + NSString* app = [sender bundleIdentifier]; if (![_currentApp isEqualToString:app]) { _currentApp = [app copy]; @@ -319,14 +320,15 @@ -(void)activateServer:(id)sender if (keyboardLayout) { [sender overrideKeyboardWithKeyboardNamed:keyboardLayout]; } - _preeditString = @""; + _preeditString = nil; + _originalString = nil; + _composedString = nil; } -(instancetype)initWithServer:(IMKServer*)server delegate:(id)delegate client:(id)inputClient { //NSLog(@"initWithServer:delegate:client:"); if (self = [super initWithServer:server delegate:delegate client:inputClient]) { - _currentClient = inputClient; [self createSession]; } return self; @@ -335,7 +337,6 @@ -(instancetype)initWithServer:(IMKServer*)server delegate:(id)delegate client:(i -(void)deactivateServer:(id)sender { //NSLog(@"deactivateServer:"); - [NSApp.squirrelAppDelegate.panel hide]; [self commitComposition:sender]; } @@ -353,13 +354,9 @@ -(void)deactivateServer:(id)sender -(void)commitComposition:(id)sender { //NSLog(@"commitComposition:"); - // commit raw input if (_session) { - const char* raw_input = rime_get_api()->get_input(_session); - if (raw_input) { - [self commitString: @(raw_input)]; - rime_get_api()->clear_composition(_session); - } + [self commitString:[self composedString:sender]]; + rime_get_api()->clear_composition(_session); } } @@ -402,20 +399,49 @@ -(NSArray*)candidates:(id)sender return _candidates; } --(void)dealloc +- (void)hidePalettes +{ + [NSApp.squirrelAppDelegate.panel hide]; +} + +- (void)dealloc { [self destroySession]; } --(void)commitString:(NSString*)string +- (NSRange)selectionRange +{ + return NSMakeRange(_caretPos, 0); +} + +- (NSRange)replacementRange +{ + return self.client.selectedRange; +} + +- (void)commitString:(id)string { //NSLog(@"commitString:"); - [_currentClient insertText:string - replacementRange:NSMakeRange(NSNotFound, 0)]; + [self.client insertText:string + replacementRange:self.replacementRange]; + [self hidePalettes]; - _preeditString = @""; + _composedString = nil; + _originalString = nil; + _preeditString = nil; +} - [NSApp.squirrelAppDelegate.panel hide]; +- (void)cancelComposition +{ + [self commitString:[self originalString:self.client]]; + rime_get_api()->clear_composition(_session); +} + +- (void)updateComposition +{ + [self.client setMarkedText:_preeditString + selectionRange:self.selectionRange + replacementRange:self.replacementRange]; } -(void)showPreeditString:(NSString*)preedit @@ -423,33 +449,35 @@ -(void)showPreeditString:(NSString*)preedit caretPos:(NSUInteger)pos { //NSLog(@"showPreeditString: '%@'", preedit); - - if ([_preeditString isEqualToString:preedit] && - _caretPos == pos && _selRange.location == range.location && _selRange.length == range.length) + if ([preedit isEqualToString:_preeditString.string] && + NSEqualRanges(range, _selRange) && pos == _caretPos) { + if (_inlinePlaceHolder) { + [self updateComposition]; + } return; - - _preeditString = preedit; + } _selRange = range; _caretPos = pos; //NSLog(@"selRange.location = %ld, selRange.length = %ld; caretPos = %ld", // range.location, range.length, pos); - NSDictionary* attrs; - NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:preedit]; + NSDictionary *attrs; + _preeditString = [[NSMutableAttributedString alloc] initWithString:preedit]; if (range.location > 0) { NSRange convertedRange = NSMakeRange(0, range.location); attrs = [self markForStyle:kTSMHiliteConvertedText atRange:convertedRange]; - [attrString setAttributes:attrs range:convertedRange]; + [_preeditString addAttributes:attrs range:convertedRange]; } - { - NSRange remainingRange = NSMakeRange(range.location, preedit.length - range.location); - attrs = [self markForStyle:kTSMHiliteSelectedRawText atRange:remainingRange]; - [attrString setAttributes:attrs range:remainingRange]; + if (range.location < pos) { + attrs = [self markForStyle:kTSMHiliteSelectedConvertedText atRange:range]; + [_preeditString addAttributes:attrs range:range]; } - [_currentClient setMarkedText:attrString - selectionRange:NSMakeRange(pos, 0) - replacementRange:NSMakeRange(NSNotFound, 0)]; - + if (MIN(NSMaxRange(range), pos) < preedit.length) { + NSRange rawRange = NSMakeRange(MIN(NSMaxRange(range), pos), preedit.length - MIN(NSMaxRange(range), pos)); + attrs = [self markForStyle:kTSMHiliteSelectedRawText atRange:rawRange]; + [_preeditString addAttributes:attrs range:rawRange]; + } + [self updateComposition]; } -(void)showPanelWithPreedit:(NSString*)preedit @@ -463,7 +491,7 @@ -(void)showPanelWithPreedit:(NSString*)preedit //NSLog(@"showPanelWithPreedit:...:"); _candidates = candidates; NSRect inputPos; - [_currentClient attributesForCharacterIndex:0 lineHeightRectangle:&inputPos]; + [self.client attributesForCharacterIndex:0 lineHeightRectangle:&inputPos]; SquirrelPanel* panel = NSApp.squirrelAppDelegate.panel; panel.position = inputPos; panel.inputController = self; @@ -485,7 +513,7 @@ @implementation SquirrelInputController(Private) -(void)createSession { - NSString* app = [_currentClient bundleIdentifier]; + NSString* app = [self.client bundleIdentifier]; NSLog(@"createSession: %@", app); _currentApp = [app copy]; _session = rime_get_api()->create_session(); @@ -508,6 +536,8 @@ -(void)updateAppOptions NSLog(@"set app option: %@ = %d", key, value); rime_get_api()->set_option(_session, key.UTF8String, value); } + _panellessCommitFix = (appOptions[@"panelless_commit_fix"] ? : @(NO)).boolValue; + _inlinePlaceHolder = (appOptions[@"inline_placeholder"] ? : @(NO)).boolValue; } } @@ -521,15 +551,19 @@ -(void)destroySession [self clearChord]; } --(void)rimeConsumeCommittedText +-(BOOL)rimeConsumeCommittedText { RIME_STRUCT(RimeCommit, commit); if (rime_get_api()->get_commit(_session, &commit)) { NSString *commitText = @(commit.text); - [self showPreeditString:@" " selRange:NSMakeRange(0, 0) caretPos:0]; + if (_preeditString.length == 0 && _panellessCommitFix) { + [self showPreeditString:@" " selRange:NSMakeRange(0, 0) caretPos:0]; + } [self commitString:commitText]; rime_get_api()->free_commit(&commit); + return YES; } + return NO; } NSString *substr(const char *str, int length) { @@ -542,7 +576,9 @@ -(void)rimeConsumeCommittedText -(void)rimeUpdate { //NSLog(@"rimeUpdate"); - [self rimeConsumeCommittedText]; + if ([self rimeConsumeCommittedText]) { + return; + } RIME_STRUCT(RimeStatus, status); if (rime_get_api()->get_status(_session, &status)) { @@ -592,11 +628,11 @@ -(void)rimeUpdate if (_inlinePreedit) { [self showPreeditString:preeditText selRange:selRange caretPos:caretPos]; } else { - NSRange empty = {0, 0}; // TRICKY: display a non-empty string to prevent iTerm2 from echoing each character in preedit. // note this is a full-shape space U+3000; using half shape characters like "..." will result in // an unstable baseline when composing Chinese characters. - [self showPreeditString:(preedit ? @" " : @"") selRange:empty caretPos:0]; + [self showPreeditString:(preedit && _inlinePlaceHolder ? @" " : @"") + selRange:NSMakeRange(0, 0) caretPos:0]; } } // update candidates diff --git a/data/squirrel.yaml b/data/squirrel.yaml index a231691b4..71c4fb8df 100644 --- a/data/squirrel.yaml +++ b/data/squirrel.yaml @@ -341,6 +341,7 @@ app_options: com.apple.Terminal: ascii_mode: true no_inline: true + inline_placeholder: true com.googlecode.iterm2: ascii_mode: true no_inline: true @@ -350,6 +351,7 @@ app_options: vim_mode: true # 退出VIM插入模式自動切換輸入法狀態 com.apple.dt.Xcode: ascii_mode: true + no_inline: true com.barebones.textwrangler: ascii_mode: true com.macromates.TextMate.preview: @@ -367,9 +369,14 @@ app_options: no_inline: true co.zeit.hyper: ascii_mode: true + org.alacritty: + ascii_mode: true + vim_mode: true + panelless_commit_fix: true com.google.Chrome: # 規避 https://github.com/rime/squirrel/issues/435 inline: true + inline_placeholder: true ru.keepcoder.Telegram: # 規避 https://github.com/rime/squirrel/issues/475 inline: true