1010@interface SquirrelInputController (Private)
1111-(void )createSession ;
1212-(void )destroySession ;
13- -(void )rimeConsumeCommittedText ;
13+ -(BOOL )rimeConsumeCommittedText ;
1414-(void )rimeUpdate ;
1515-(void )updateAppOptions ;
1616@end
1717
1818const int N_KEY_ROLL_OVER = 50 ;
1919
2020@implementation SquirrelInputController {
21- id _currentClient;
22- NSString *_preeditString;
21+ NSMutableAttributedString *_preeditString;
22+ NSAttributedString *_originalString;
23+ NSString *_composedString;
2324 NSRange _selRange;
2425 NSUInteger _caretPos;
2526 NSArray *_candidates;
@@ -29,6 +30,9 @@ @implementation SquirrelInputController {
2930 NSString *_schemaId;
3031 BOOL _inlinePreedit;
3132 BOOL _inlineCandidate;
33+ // app-specific bug fix
34+ BOOL _inlinePlaceHolder;
35+ BOOL _panellessCommitFix;
3236 // for chord-typing
3337 int _chordKeyCodes[N_KEY_ROLL_OVER];
3438 int _chordModifiers[N_KEY_ROLL_OVER];
@@ -49,9 +53,6 @@ - (BOOL)handleEvent:(NSEvent*)event client:(id)sender
4953 // Key processing will not continue in that case. In other words the
5054 // system will not deliver a key down event to the application.
5155 // Returning NO means the original key down will be passed on to the client.
52-
53- _currentClient = sender;
54-
5556 NSUInteger modifiers = event.modifierFlags ;
5657
5758 BOOL handled = NO ;
@@ -64,7 +65,7 @@ - (BOOL)handleEvent:(NSEvent*)event client:(id)sender
6465 }
6566 }
6667
67- NSString * app = [_currentClient bundleIdentifier ];
68+ NSString * app = [sender bundleIdentifier ];
6869
6970 if (![_currentApp isEqualToString: app]) {
7071 _currentApp = [app copy ];
@@ -319,14 +320,15 @@ -(void)activateServer:(id)sender
319320 if (keyboardLayout) {
320321 [sender overrideKeyboardWithKeyboardNamed: keyboardLayout];
321322 }
322- _preeditString = @" " ;
323+ _preeditString = nil ;
324+ _originalString = nil ;
325+ _composedString = nil ;
323326}
324327
325328-(instancetype )initWithServer : (IMKServer*)server delegate : (id )delegate client : (id )inputClient
326329{
327330 // NSLog(@"initWithServer:delegate:client:");
328331 if (self = [super initWithServer: server delegate: delegate client: inputClient]) {
329- _currentClient = inputClient;
330332 [self createSession ];
331333 }
332334 return self;
@@ -335,7 +337,6 @@ -(instancetype)initWithServer:(IMKServer*)server delegate:(id)delegate client:(i
335337-(void )deactivateServer : (id )sender
336338{
337339 // NSLog(@"deactivateServer:");
338- [NSApp .squirrelAppDelegate.panel hide ];
339340 [self commitComposition: sender];
340341}
341342
@@ -353,13 +354,9 @@ -(void)deactivateServer:(id)sender
353354-(void )commitComposition : (id )sender
354355{
355356 // NSLog(@"commitComposition:");
356- // commit raw input
357357 if (_session) {
358- const char * raw_input = rime_get_api ()->get_input (_session);
359- if (raw_input) {
360- [self commitString: @(raw_input)];
361- rime_get_api ()->clear_composition (_session);
362- }
358+ [self commitString: [self composedString: sender]];
359+ rime_get_api ()->clear_composition (_session);
363360 }
364361}
365362
@@ -402,54 +399,85 @@ -(NSArray*)candidates:(id)sender
402399 return _candidates;
403400}
404401
405- -(void )dealloc
402+ - (void )hidePalettes
403+ {
404+ [NSApp .squirrelAppDelegate.panel hide ];
405+ }
406+
407+ - (void )dealloc
406408{
407409 [self destroySession ];
408410}
409411
410- -(void )commitString : (NSString *)string
412+ - (NSRange )selectionRange
413+ {
414+ return NSMakeRange (_caretPos, 0 );
415+ }
416+
417+ - (NSRange )replacementRange
418+ {
419+ return self.client .selectedRange ;
420+ }
421+
422+ - (void )commitString : (id )string
411423{
412424 // NSLog(@"commitString:");
413- [_currentClient insertText: string
414- replacementRange: NSMakeRange (NSNotFound , 0 )];
425+ [self .client insertText: string
426+ replacementRange: self .replacementRange];
427+ [self hidePalettes ];
415428
416- _preeditString = @" " ;
429+ _composedString = nil ;
430+ _originalString = nil ;
431+ _preeditString = nil ;
432+ }
417433
418- [NSApp .squirrelAppDelegate.panel hide ];
434+ - (void )cancelComposition
435+ {
436+ [self commitString: [self originalString: self .client]];
437+ rime_get_api ()->clear_composition (_session);
438+ }
439+
440+ - (void )updateComposition
441+ {
442+ [self .client setMarkedText: _preeditString
443+ selectionRange: self .selectionRange
444+ replacementRange: self .replacementRange];
419445}
420446
421447-(void )showPreeditString : (NSString *)preedit
422448 selRange : (NSRange )range
423449 caretPos : (NSUInteger )pos
424450{
425451 // NSLog(@"showPreeditString: '%@'", preedit);
426-
427- if ([_preeditString isEqualToString: preedit] &&
428- _caretPos == pos && _selRange.location == range.location && _selRange.length == range.length )
452+ if ([preedit isEqualToString: _preeditString.string] &&
453+ NSEqualRanges (range, _selRange) && pos == _caretPos) {
454+ if (_inlinePlaceHolder) {
455+ [self updateComposition ];
456+ }
429457 return ;
430-
431- _preeditString = preedit;
458+ }
432459 _selRange = range;
433460 _caretPos = pos;
434461
435462 // NSLog(@"selRange.location = %ld, selRange.length = %ld; caretPos = %ld",
436463 // range.location, range.length, pos);
437- NSDictionary * attrs;
438- NSMutableAttributedString * attrString = [[NSMutableAttributedString alloc ] initWithString: preedit];
464+ NSDictionary * attrs;
465+ _preeditString = [[NSMutableAttributedString alloc ] initWithString: preedit];
439466 if (range.location > 0 ) {
440467 NSRange convertedRange = NSMakeRange (0 , range.location );
441468 attrs = [self markForStyle: kTSMHiliteConvertedText atRange: convertedRange];
442- [attrString setAttributes : attrs range: convertedRange];
469+ [_preeditString addAttributes : attrs range: convertedRange];
443470 }
444- {
445- NSRange remainingRange = NSMakeRange (range.location , preedit.length - range.location );
446- attrs = [self markForStyle: kTSMHiliteSelectedRawText atRange: remainingRange];
447- [attrString setAttributes: attrs range: remainingRange];
471+ if (range.location < pos) {
472+ attrs = [self markForStyle: kTSMHiliteSelectedConvertedText atRange: range];
473+ [_preeditString addAttributes: attrs range: range];
448474 }
449- [_currentClient setMarkedText: attrString
450- selectionRange: NSMakeRange (pos, 0 )
451- replacementRange: NSMakeRange (NSNotFound , 0 )];
452-
475+ if (MIN (NSMaxRange (range), pos) < preedit.length ) {
476+ NSRange rawRange = NSMakeRange (MIN (NSMaxRange (range), pos), preedit.length - MIN (NSMaxRange (range), pos));
477+ attrs = [self markForStyle: kTSMHiliteSelectedRawText atRange: rawRange];
478+ [_preeditString addAttributes: attrs range: rawRange];
479+ }
480+ [self updateComposition ];
453481}
454482
455483-(void )showPanelWithPreedit : (NSString *)preedit
@@ -463,7 +491,7 @@ -(void)showPanelWithPreedit:(NSString*)preedit
463491 // NSLog(@"showPanelWithPreedit:...:");
464492 _candidates = candidates;
465493 NSRect inputPos;
466- [_currentClient attributesForCharacterIndex: 0 lineHeightRectangle: &inputPos];
494+ [self .client attributesForCharacterIndex: 0 lineHeightRectangle: &inputPos];
467495 SquirrelPanel* panel = NSApp .squirrelAppDelegate .panel ;
468496 panel.position = inputPos;
469497 panel.inputController = self;
@@ -485,7 +513,7 @@ @implementation SquirrelInputController(Private)
485513
486514-(void )createSession
487515{
488- NSString * app = [_currentClient bundleIdentifier ];
516+ NSString * app = [self .client bundleIdentifier ];
489517 NSLog (@" createSession: %@ " , app);
490518 _currentApp = [app copy ];
491519 _session = rime_get_api ()->create_session ();
@@ -508,6 +536,8 @@ -(void)updateAppOptions
508536 NSLog (@" set app option: %@ = %d " , key, value);
509537 rime_get_api ()->set_option (_session, key.UTF8String , value);
510538 }
539+ _panellessCommitFix = (appOptions[@" panelless_commit_fix" ] ? : @(NO )).boolValue ;
540+ _inlinePlaceHolder = (appOptions[@" inline_placeholder" ] ? : @(NO )).boolValue ;
511541 }
512542}
513543
@@ -521,15 +551,19 @@ -(void)destroySession
521551 [self clearChord ];
522552}
523553
524- -(void )rimeConsumeCommittedText
554+ -(BOOL )rimeConsumeCommittedText
525555{
526556 RIME_STRUCT (RimeCommit, commit);
527557 if (rime_get_api ()->get_commit (_session, &commit)) {
528558 NSString *commitText = @(commit.text );
529- [self showPreeditString: @" " selRange: NSMakeRange (0 , 0 ) caretPos: 0 ];
559+ if (_preeditString.length == 0 && _panellessCommitFix) {
560+ [self showPreeditString: @" " selRange: NSMakeRange (0 , 0 ) caretPos: 0 ];
561+ }
530562 [self commitString: commitText];
531563 rime_get_api ()->free_commit (&commit);
564+ return YES ;
532565 }
566+ return NO ;
533567}
534568
535569NSString *substr (const char *str, int length) {
@@ -542,7 +576,9 @@ -(void)rimeConsumeCommittedText
542576-(void )rimeUpdate
543577{
544578 // NSLog(@"rimeUpdate");
545- [self rimeConsumeCommittedText ];
579+ if ([self rimeConsumeCommittedText ]) {
580+ return ;
581+ }
546582
547583 RIME_STRUCT (RimeStatus, status);
548584 if (rime_get_api ()->get_status (_session, &status)) {
@@ -592,11 +628,11 @@ -(void)rimeUpdate
592628 if (_inlinePreedit) {
593629 [self showPreeditString: preeditText selRange: selRange caretPos: caretPos];
594630 } else {
595- NSRange empty = {0 , 0 };
596631 // TRICKY: display a non-empty string to prevent iTerm2 from echoing each character in preedit.
597632 // note this is a full-shape space U+3000; using half shape characters like "..." will result in
598633 // an unstable baseline when composing Chinese characters.
599- [self showPreeditString: (preedit ? @" " : @" " ) selRange: empty caretPos: 0 ];
634+ [self showPreeditString: (preedit && _inlinePlaceHolder ? @" " : @" " )
635+ selRange: NSMakeRange (0 , 0 ) caretPos: 0 ];
600636 }
601637 }
602638 // update candidates
0 commit comments