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;
2322 NSRange _selRange;
2423 NSUInteger _caretPos;
2524 NSArray *_candidates;
@@ -29,6 +28,9 @@ @implementation SquirrelInputController {
2928 NSString *_schemaId;
3029 BOOL _inlinePreedit;
3130 BOOL _inlineCandidate;
31+ // app-specific bug fix
32+ BOOL _inlinePlaceHolder;
33+ BOOL _panellessCommitFix;
3234 // for chord-typing
3335 int _chordKeyCodes[N_KEY_ROLL_OVER];
3436 int _chordModifiers[N_KEY_ROLL_OVER];
@@ -49,9 +51,6 @@ - (BOOL)handleEvent:(NSEvent*)event client:(id)sender
4951 // Key processing will not continue in that case. In other words the
5052 // system will not deliver a key down event to the application.
5153 // Returning NO means the original key down will be passed on to the client.
52-
53- _currentClient = sender;
54-
5554 NSUInteger modifiers = event.modifierFlags ;
5655
5756 BOOL handled = NO ;
@@ -64,7 +63,7 @@ - (BOOL)handleEvent:(NSEvent*)event client:(id)sender
6463 }
6564 }
6665
67- NSString * app = [_currentClient bundleIdentifier ];
66+ NSString * app = [sender bundleIdentifier ];
6867
6968 if (![_currentApp isEqualToString: app]) {
7069 _currentApp = [app copy ];
@@ -319,14 +318,13 @@ -(void)activateServer:(id)sender
319318 if (keyboardLayout) {
320319 [sender overrideKeyboardWithKeyboardNamed: keyboardLayout];
321320 }
322- _preeditString = @" " ;
321+ _preeditString = nil ;
323322}
324323
325324-(instancetype )initWithServer : (IMKServer*)server delegate : (id )delegate client : (id )inputClient
326325{
327326 // NSLog(@"initWithServer:delegate:client:");
328327 if (self = [super initWithServer: server delegate: delegate client: inputClient]) {
329- _currentClient = inputClient;
330328 [self createSession ];
331329 }
332330 return self;
@@ -335,7 +333,6 @@ -(instancetype)initWithServer:(IMKServer*)server delegate:(id)delegate client:(i
335333-(void )deactivateServer : (id )sender
336334{
337335 // NSLog(@"deactivateServer:");
338- [NSApp .squirrelAppDelegate.panel hide ];
339336 [self commitComposition: sender];
340337}
341338
@@ -402,54 +399,77 @@ -(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 NSMakeRange (NSNotFound , NSNotFound );
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+ _preeditString = nil ;
430+ }
417431
418- [NSApp .squirrelAppDelegate.panel hide ];
432+ - (void )updateComposition
433+ {
434+ [self .client setMarkedText: _preeditString
435+ selectionRange: self .selectionRange
436+ replacementRange: self .replacementRange];
419437}
420438
421439-(void )showPreeditString : (NSString *)preedit
422440 selRange : (NSRange )range
423441 caretPos : (NSUInteger )pos
424442{
425443 // NSLog(@"showPreeditString: '%@'", preedit);
426-
427- if ([_preeditString isEqualToString: preedit] &&
428- _caretPos == pos && _selRange.location == range.location && _selRange.length == range.length )
444+ if ([preedit isEqualToString: _preeditString.string] &&
445+ NSEqualRanges (range, _selRange) && pos == _caretPos) {
446+ if (_inlinePlaceHolder) {
447+ [self updateComposition ];
448+ }
429449 return ;
430-
431- _preeditString = preedit;
450+ }
432451 _selRange = range;
433452 _caretPos = pos;
434453
435454 // NSLog(@"selRange.location = %ld, selRange.length = %ld; caretPos = %ld",
436455 // range.location, range.length, pos);
437- NSDictionary * attrs;
438- NSMutableAttributedString * attrString = [[NSMutableAttributedString alloc ] initWithString: preedit];
456+ NSDictionary * attrs;
457+ _preeditString = [[NSMutableAttributedString alloc ] initWithString: preedit];
439458 if (range.location > 0 ) {
440459 NSRange convertedRange = NSMakeRange (0 , range.location );
441460 attrs = [self markForStyle: kTSMHiliteConvertedText atRange: convertedRange];
442- [attrString setAttributes : attrs range: convertedRange];
461+ [_preeditString addAttributes : attrs range: convertedRange];
443462 }
444- {
445- NSRange remainingRange = NSMakeRange (range.location , preedit.length - range.location );
446- attrs = [self markForStyle: kTSMHiliteSelectedRawText atRange: remainingRange];
447- [attrString setAttributes: attrs range: remainingRange];
463+ if (range.location < pos) {
464+ attrs = [self markForStyle: kTSMHiliteSelectedConvertedText atRange: range];
465+ [_preeditString addAttributes: attrs range: range];
448466 }
449- [_currentClient setMarkedText: attrString
450- selectionRange: NSMakeRange (pos, 0 )
451- replacementRange: NSMakeRange (NSNotFound , 0 )];
452-
467+ if (MIN (NSMaxRange (range), pos) < preedit.length ) {
468+ NSRange rawRange = NSMakeRange (MIN (NSMaxRange (range), pos), preedit.length - MIN (NSMaxRange (range), pos));
469+ attrs = [self markForStyle: kTSMHiliteSelectedRawText atRange: rawRange];
470+ [_preeditString addAttributes: attrs range: rawRange];
471+ }
472+ [self updateComposition ];
453473}
454474
455475-(void )showPanelWithPreedit : (NSString *)preedit
@@ -463,7 +483,7 @@ -(void)showPanelWithPreedit:(NSString*)preedit
463483 // NSLog(@"showPanelWithPreedit:...:");
464484 _candidates = candidates;
465485 NSRect inputPos;
466- [_currentClient attributesForCharacterIndex: 0 lineHeightRectangle: &inputPos];
486+ [self .client attributesForCharacterIndex: 0 lineHeightRectangle: &inputPos];
467487 SquirrelPanel* panel = NSApp .squirrelAppDelegate .panel ;
468488 panel.position = inputPos;
469489 panel.inputController = self;
@@ -485,7 +505,7 @@ @implementation SquirrelInputController(Private)
485505
486506-(void )createSession
487507{
488- NSString * app = [_currentClient bundleIdentifier ];
508+ NSString * app = [self .client bundleIdentifier ];
489509 NSLog (@" createSession: %@ " , app);
490510 _currentApp = [app copy ];
491511 _session = rime_get_api ()->create_session ();
@@ -508,6 +528,8 @@ -(void)updateAppOptions
508528 NSLog (@" set app option: %@ = %d " , key, value);
509529 rime_get_api ()->set_option (_session, key.UTF8String , value);
510530 }
531+ _panellessCommitFix = (appOptions[@" panelless_commit_fix" ] ? : @(NO )).boolValue ;
532+ _inlinePlaceHolder = (appOptions[@" inline_placeholder" ] ? : @(NO )).boolValue ;
511533 }
512534}
513535
@@ -521,15 +543,19 @@ -(void)destroySession
521543 [self clearChord ];
522544}
523545
524- -(void )rimeConsumeCommittedText
546+ -(BOOL )rimeConsumeCommittedText
525547{
526548 RIME_STRUCT (RimeCommit, commit);
527549 if (rime_get_api ()->get_commit (_session, &commit)) {
528550 NSString *commitText = @(commit.text );
529- [self showPreeditString: @" " selRange: NSMakeRange (0 , 0 ) caretPos: 0 ];
551+ if (_preeditString.length == 0 && _panellessCommitFix) {
552+ [self showPreeditString: @" " selRange: NSMakeRange (0 , 0 ) caretPos: 0 ];
553+ }
530554 [self commitString: commitText];
531555 rime_get_api ()->free_commit (&commit);
556+ return YES ;
532557 }
558+ return NO ;
533559}
534560
535561NSString *substr (const char *str, int length) {
@@ -542,7 +568,9 @@ -(void)rimeConsumeCommittedText
542568-(void )rimeUpdate
543569{
544570 // NSLog(@"rimeUpdate");
545- [self rimeConsumeCommittedText ];
571+ if ([self rimeConsumeCommittedText ]) {
572+ return ;
573+ }
546574
547575 RIME_STRUCT (RimeStatus, status);
548576 if (rime_get_api ()->get_status (_session, &status)) {
@@ -592,11 +620,11 @@ -(void)rimeUpdate
592620 if (_inlinePreedit) {
593621 [self showPreeditString: preeditText selRange: selRange caretPos: caretPos];
594622 } else {
595- NSRange empty = {0 , 0 };
596623 // TRICKY: display a non-empty string to prevent iTerm2 from echoing each character in preedit.
597624 // note this is a full-shape space U+3000; using half shape characters like "..." will result in
598625 // an unstable baseline when composing Chinese characters.
599- [self showPreeditString: (preedit ? @" " : @" " ) selRange: empty caretPos: 0 ];
626+ [self showPreeditString: (preedit && _inlinePlaceHolder ? @" " : @" " )
627+ selRange: NSMakeRange (0 , 0 ) caretPos: 0 ];
600628 }
601629 }
602630 // update candidates
0 commit comments