1010@interface SquirrelInputController (Private)
1111-(void )createSession ;
1212-(void )destroySession ;
13- -(void )rimeConsumeCommittedText ;
13+ -(BOOL )rimeConsumeCommittedText ;
1414-(void )rimeUpdate ;
1515-(void )updateAppOptions ;
1616@end
@@ -29,6 +29,10 @@ @implementation SquirrelInputController {
2929 NSString *_schemaId;
3030 BOOL _inlinePreedit;
3131 BOOL _inlineCandidate;
32+ // app-specific bug fix
33+ BOOL _inlinePlaceholder;
34+ BOOL _panellessCommitFix;
35+ int _inlineOffset;
3236 // for chord-typing
3337 int _chordKeyCodes[N_KEY_ROLL_OVER];
3438 int _chordModifiers[N_KEY_ROLL_OVER];
@@ -150,8 +154,20 @@ - (BOOL)handleEvent:(NSEvent*)event client:(id)sender
150154 modifiers & OSX_CAPITAL_MASK);
151155 if (rime_keycode) {
152156 int rime_modifiers = osx_modifiers_to_rime_modifiers (modifiers);
153- handled = [self processKey: rime_keycode modifiers: rime_modifiers];
154- [self rimeUpdate ];
157+ if ((handled = [self processKey: rime_keycode modifiers: rime_modifiers])) {
158+ [self rimeUpdate ];
159+ } else if (_panellessCommitFix && [_currentClient markedRange ].length > 0 ) {
160+ if (rime_keycode == XK_Delete || (rime_keycode >= XK_Home && rime_keycode <= XK_KP_Delete) ||
161+ (rime_keycode >= XK_BackSpace && rime_keycode <= XK_Escape)) {
162+ [self showPlaceholder: @" " ];
163+ } else if (!(modifiers & (NSEventModifierFlagControl | NSEventModifierFlagCommand)) &&
164+ event.characters .length > 0 ) {
165+ [self showPlaceholder: nil ];
166+ [_currentClient insertText: event.characters
167+ replacementRange: NSMakeRange (NSNotFound , NSNotFound )];
168+ return YES ;
169+ }
170+ }
155171 }
156172 } break ;
157173 default :
@@ -418,6 +434,17 @@ -(void)commitString:(NSString*)string
418434 [NSApp .squirrelAppDelegate.panel hide ];
419435}
420436
437+ -(void )showPlaceholder : (NSString *)placeholder
438+ {
439+ NSDictionary * attrs = [self markForStyle: kTSMHiliteSelectedRawText
440+ atRange: NSMakeRange (0 , placeholder ? placeholder.length : 1 )];
441+ NSAttributedString * attrString = [[NSAttributedString alloc ] initWithString: placeholder ? : @" █"
442+ attributes: attrs];
443+ [_currentClient setMarkedText: attrString
444+ selectionRange: NSMakeRange (0 , 0 )
445+ replacementRange: NSMakeRange (NSNotFound , NSNotFound )];
446+ }
447+
421448-(void )showPreeditString : (NSString *)preedit
422449 selRange : (NSRange )range
423450 caretPos : (NSUInteger )pos
@@ -464,6 +491,8 @@ -(void)showPanelWithPreedit:(NSString*)preedit
464491 _candidates = candidates;
465492 NSRect inputPos;
466493 [_currentClient attributesForCharacterIndex: 0 lineHeightRectangle: &inputPos];
494+ NSWidth (inputPos) > NSHeight (inputPos) ? (inputPos.origin .x += _inlineOffset)
495+ : (inputPos.origin .y += _inlineOffset);
467496 SquirrelPanel* panel = NSApp .squirrelAppDelegate .panel ;
468497 panel.position = inputPos;
469498 panel.inputController = self;
@@ -504,10 +533,16 @@ -(void)updateAppOptions
504533 SquirrelAppOptions* appOptions = [NSApp .squirrelAppDelegate.config getAppOptions: _currentApp];
505534 if (appOptions) {
506535 for (NSString * key in appOptions) {
507- BOOL value = appOptions[key].boolValue ;
508- NSLog (@" set app option: %@ = %d " , key, value);
509- rime_get_api ()->set_option (_session, key.UTF8String , value);
536+ NSNumber *number = appOptions[key];
537+ if (!strcmp (number.objCType , @encode (BOOL ))) {
538+ Bool value = number.intValue ;
539+ // NSLog(@"set app option: %@ = %d", key, value);
540+ rime_get_api ()->set_option (_session, key.UTF8String , value);
541+ }
510542 }
543+ _panellessCommitFix = appOptions[@" panelless_commit_fix" ].boolValue ;
544+ _inlinePlaceholder = appOptions[@" inline_placeholder" ].boolValue ;
545+ _inlineOffset = appOptions[@" inline_offset" ].intValue ;
511546 }
512547}
513548
@@ -521,14 +556,22 @@ -(void)destroySession
521556 [self clearChord ];
522557}
523558
524- -(void )rimeConsumeCommittedText
559+ -(BOOL )rimeConsumeCommittedText
525560{
526561 RIME_STRUCT (RimeCommit, commit);
527562 if (rime_get_api ()->get_commit (_session, &commit)) {
528563 NSString *commitText = @(commit.text );
529- [self commitString: commitText];
564+ if (_panellessCommitFix) {
565+ [self showPlaceholder: commitText];
566+ [self commitString: commitText];
567+ [self showPlaceholder: sizeof (commit.text) == 1 ? @" " : nil ];
568+ } else {
569+ [self commitString: commitText];
570+ }
530571 rime_get_api ()->free_commit (&commit);
572+ return YES ;
531573 }
574+ return NO ;
532575}
533576
534577NSString *substr (const char *str, int length) {
@@ -541,7 +584,7 @@ -(void)rimeConsumeCommittedText
541584-(void )rimeUpdate
542585{
543586 // NSLog(@"rimeUpdate");
544- [self rimeConsumeCommittedText ];
587+ BOOL committedText = [self rimeConsumeCommittedText ];
545588
546589 RIME_STRUCT (RimeStatus, status);
547590 if (rime_get_api ()->get_status (_session, &status)) {
@@ -570,32 +613,38 @@ -(void)rimeUpdate
570613 NSUInteger start = substr (preedit, ctx.composition .sel_start ).length ;
571614 NSUInteger end = substr (preedit, ctx.composition .sel_end ).length ;
572615 NSUInteger caretPos = substr (preedit, ctx.composition .cursor_pos ).length ;
616+ NSUInteger numCandidate = ctx.menu .num_candidates ;
573617 NSRange selRange = NSMakeRange (start, end - start);
574- if (_inlineCandidate) {
575- const char *candidatePreview = ctx.commit_text_preview ;
576- NSString *candidatePreviewText = candidatePreview ? @(candidatePreview) : @" " ;
577- if (_inlinePreedit) {
578- if ((caretPos >= NSMaxRange (selRange)) && (caretPos < preeditText.length )) {
579- candidatePreviewText = [candidatePreviewText stringByAppendingString: [preeditText substringWithRange: NSMakeRange (caretPos, preeditText.length-caretPos)]];
618+ if (!(_panellessCommitFix && committedText)) {
619+ if (_inlineCandidate) {
620+ const char *candidatePreview = ctx.commit_text_preview ;
621+ NSString *candidatePreviewText = candidatePreview ? @(candidatePreview) : @" " ;
622+ if (_inlinePreedit) {
623+ if ((caretPos >= NSMaxRange (selRange)) && (caretPos < preeditText.length )) {
624+ candidatePreviewText = [candidatePreviewText stringByAppendingString: [preeditText substringWithRange: NSMakeRange (caretPos, preeditText.length-caretPos)]];
625+ }
626+ [self showPreeditString: candidatePreviewText selRange: NSMakeRange (selRange.location, candidatePreviewText.length-selRange.location) caretPos: candidatePreviewText.length-(preeditText.length-caretPos)];
627+ } else {
628+ if ((NSMaxRange (selRange) < caretPos) && (caretPos > selRange.location )) {
629+ candidatePreviewText = [candidatePreviewText substringWithRange: NSMakeRange (0 , candidatePreviewText.length-(caretPos-NSMaxRange (selRange)))];
630+ } else if ((NSMaxRange (selRange) < preeditText.length ) && (caretPos <= selRange.location )) {
631+ candidatePreviewText = [candidatePreviewText substringWithRange: NSMakeRange (0 , candidatePreviewText.length-(preeditText.length-NSMaxRange (selRange)))];
632+ }
633+ [self showPreeditString: candidatePreviewText selRange: NSMakeRange (selRange.location, candidatePreviewText.length-selRange.location) caretPos: candidatePreviewText.length];
580634 }
581- [self showPreeditString: candidatePreviewText selRange: NSMakeRange (selRange.location, candidatePreviewText.length-selRange.location) caretPos: candidatePreviewText.length-(preeditText.length-caretPos)];
582635 } else {
583- if ((NSMaxRange (selRange) < caretPos) && (caretPos > selRange.location )) {
584- candidatePreviewText = [candidatePreviewText substringWithRange: NSMakeRange (0 , candidatePreviewText.length-(caretPos-NSMaxRange (selRange)))];
585- } else if ((NSMaxRange (selRange) < preeditText.length ) && (caretPos <= selRange.location )) {
586- candidatePreviewText = [candidatePreviewText substringWithRange: NSMakeRange (0 , candidatePreviewText.length-(preeditText.length-NSMaxRange (selRange)))];
636+ if (_inlinePreedit) {
637+ _inlinePlaceholder && preeditText.length == 0 && numCandidate > 0
638+ ? [self showPlaceholder: @" " ]
639+ : [self showPreeditString: preeditText selRange: selRange caretPos: caretPos];
640+ } else {
641+ NSRange empty = {0 , 0 };
642+ // TRICKY: display a non-empty string to prevent iTerm2 from echoing each character in preedit.
643+ // note this is a full-shape space U+3000; using half shape characters like "..." will result in
644+ // an unstable baseline when composing Chinese characters.
645+ _inlinePlaceholder && preedit ? [self showPlaceholder: @" " ]
646+ : [self showPreeditString: @" " selRange: empty caretPos: 0 ];
587647 }
588- [self showPreeditString: candidatePreviewText selRange: NSMakeRange (selRange.location, candidatePreviewText.length-selRange.location) caretPos: candidatePreviewText.length];
589- }
590- } else {
591- if (_inlinePreedit) {
592- [self showPreeditString: preeditText selRange: selRange caretPos: caretPos];
593- } else {
594- NSRange empty = {0 , 0 };
595- // TRICKY: display a non-empty string to prevent iTerm2 from echoing each character in preedit.
596- // note this is a full-shape space U+3000; using half shape characters like "..." will result in
597- // an unstable baseline when composing Chinese characters.
598- [self showPreeditString: (preedit ? @" " : @" " ) selRange: empty caretPos: 0 ];
599648 }
600649 }
601650 // update candidates
0 commit comments