@@ -351,11 +351,10 @@ void FcitxCskkContext::updateUI() {
351351 }
352352
353353 // Preedit
354- auto preedit = skk_context_get_preedit (context_);
355- Text preeditText;
356- // FIXME: Pretty text format someday.
357- preeditText.append (std::string (preedit));
358- preeditText.setCursor (static_cast <int >(strlen (preedit)));
354+ uint32_t stateStackLen;
355+ auto preeditDetail = skk_context_get_preedit_detail (context_, &stateStackLen);
356+ auto [mainPreedit, supplementPreedit] =
357+ FcitxCskkContext::formatPreedit (preeditDetail, stateStackLen);
359358
360359 // CandidateList
361360 int currentCursorPosition =
@@ -383,10 +382,11 @@ void FcitxCskkContext::updateUI() {
383382 }
384383
385384 if (ic_->capabilityFlags ().test (CapabilityFlag::Preedit)) {
386- inputPanel.setClientPreedit (preeditText);
385+ inputPanel.setClientPreedit (mainPreedit);
386+ inputPanel.setPreedit (supplementPreedit);
387387 ic_->updatePreedit ();
388388 } else {
389- inputPanel.setPreedit (preeditText );
389+ inputPanel.setPreedit (mainPreedit );
390390 }
391391
392392 // StatusArea for status icon
@@ -432,6 +432,133 @@ int FcitxCskkContext::getInputMode() {
432432 }
433433 return skk_context_get_input_mode (context_);
434434}
435+ /* *
436+ * format preedit state into Text.
437+ * Returns tuple of <Main content Text, Supplement content Text>
438+ * Main content is something you always want to show, supplement content is
439+ * something you may show when you have space.
440+ */
441+ std::tuple<Text, Text>
442+ FcitxCskkContext::formatPreedit (CskkStateInfoFfi *cskkStateInfoArray,
443+ uint32_t stateLen) {
444+ std::string precomposition_marker = " ▽" ;
445+ std::string selection_marker = " ▼" ;
446+ Text mainContent = Text (" " ), supplementContent = Text (" " );
447+ size_t mainCursorIdx = 0 ;
448+ for (uint32_t i = 0 ; i < stateLen; i++) {
449+ auto cskkStateInfo = cskkStateInfoArray[i];
450+ switch (cskkStateInfo.tag ) {
451+ case DirectStateInfo: {
452+ auto directStateInfo = cskkStateInfo.direct_state_info ;
453+ if (directStateInfo.confirmed ) {
454+ mainCursorIdx += strlen (directStateInfo.confirmed );
455+ mainContent.append (directStateInfo.confirmed , TextFormatFlag::NoFlag);
456+ }
457+ if (directStateInfo.unconverted ) {
458+ mainCursorIdx += strlen (directStateInfo.unconverted );
459+ mainContent.append (directStateInfo.unconverted ,
460+ TextFormatFlag::Underline);
461+ }
462+ } break ;
463+ case PreCompositionStateInfo: {
464+ auto precompositionStateInfo = cskkStateInfo.pre_composition_state_info ;
465+ mainCursorIdx += precomposition_marker.length ();
466+ mainContent.append (precomposition_marker, TextFormatFlag::DontCommit);
467+ if (precompositionStateInfo.confirmed ) {
468+ mainCursorIdx += strlen (precompositionStateInfo.confirmed );
469+ mainContent.append (precompositionStateInfo.confirmed ,
470+ TextFormatFlag::NoFlag);
471+ }
472+ if (precompositionStateInfo.kana_to_composite ) {
473+ mainCursorIdx += strlen (precompositionStateInfo.kana_to_composite );
474+ mainContent.append (precompositionStateInfo.kana_to_composite ,
475+ TextFormatFlag::Underline);
476+ }
477+ if (precompositionStateInfo.unconverted ) {
478+ mainCursorIdx += strlen (precompositionStateInfo.unconverted );
479+ mainContent.append (precompositionStateInfo.unconverted ,
480+ TextFormatFlag::Underline);
481+ }
482+ } break ;
483+ case PreCompositionOkuriganaStateInfo: {
484+ auto precompositionOkuriganaStateInfo =
485+ cskkStateInfo.pre_composition_okurigana_state_info ;
486+ mainContent.append (precomposition_marker, TextFormatFlag::DontCommit);
487+ mainCursorIdx += precomposition_marker.length ();
488+ if (precompositionOkuriganaStateInfo.confirmed ) {
489+ mainCursorIdx += strlen (precompositionOkuriganaStateInfo.confirmed );
490+ mainContent.append (precompositionOkuriganaStateInfo.confirmed ,
491+ TextFormatFlag::NoFlag);
492+ }
493+ if (precompositionOkuriganaStateInfo.kana_to_composite ) {
494+ mainCursorIdx +=
495+ strlen (precompositionOkuriganaStateInfo.kana_to_composite );
496+ mainContent.append (precompositionOkuriganaStateInfo.kana_to_composite ,
497+ TextFormatFlag::Underline);
498+ }
499+ if (precompositionOkuriganaStateInfo.unconverted ) {
500+ mainContent.append (" *" , TextFormatFlags{TextFormatFlag::Underline,
501+ TextFormatFlag::DontCommit});
502+ mainCursorIdx +=
503+ strlen (precompositionOkuriganaStateInfo.unconverted ) + 1 ;
504+ mainContent.append (precompositionOkuriganaStateInfo.unconverted ,
505+ TextFormatFlag::Underline);
506+ }
507+ } break ;
508+ case CompositionSelectionStateInfo: {
509+ auto compositionSelectionStateInfo =
510+ cskkStateInfo.composition_selection_state_info ;
511+ mainContent.append (selection_marker, TextFormatFlag::DontCommit);
512+ mainCursorIdx += selection_marker.length ();
513+ std::string tmpContentString;
514+ if (compositionSelectionStateInfo.composited ) {
515+ mainCursorIdx += strlen (compositionSelectionStateInfo.composited );
516+ tmpContentString.append (compositionSelectionStateInfo.composited );
517+ }
518+ if (compositionSelectionStateInfo.okuri ) {
519+ mainCursorIdx += strlen (compositionSelectionStateInfo.okuri );
520+ tmpContentString.append (compositionSelectionStateInfo.okuri );
521+ }
522+ mainContent.append (tmpContentString, TextFormatFlag::Underline);
523+
524+ if (compositionSelectionStateInfo.annotation ) {
525+ supplementContent.clear ();
526+ supplementContent.append (compositionSelectionStateInfo.annotation ,
527+ TextFormatFlag::DontCommit);
528+ }
529+ } break ;
530+ case RegisterStateInfo: {
531+ auto registerStateInfo = cskkStateInfo.register_state_info ;
532+ mainContent.append (selection_marker, TextFormatFlag::DontCommit);
533+ mainCursorIdx += selection_marker.length ();
534+ if (registerStateInfo.confirmed ) {
535+ mainCursorIdx += strlen (registerStateInfo.confirmed );
536+ mainContent.append (registerStateInfo.confirmed ,
537+ TextFormatFlag::DontCommit);
538+ }
539+ if (registerStateInfo.kana_to_composite ) {
540+ mainCursorIdx += strlen (registerStateInfo.kana_to_composite );
541+ mainContent.append (registerStateInfo.kana_to_composite ,
542+ TextFormatFlag::DontCommit);
543+ }
544+ if (registerStateInfo.okuri ) {
545+ mainCursorIdx += strlen (registerStateInfo.okuri );
546+ mainContent.append (registerStateInfo.okuri , TextFormatFlag::DontCommit);
547+ }
548+ mainCursorIdx += strlen (" 【" );
549+ mainContent.append (" 【" , TextFormatFlag::DontCommit);
550+ } break ;
551+ }
552+ }
553+ // FIXME: Silently assuming length is less than int_max here. May fail when
554+ // length is over UINT_MAX. very unlikely, not high priority.
555+ mainContent.setCursor ((int )mainCursorIdx);
556+ for (uint32_t i = 1 ; i < stateLen; i++) {
557+ mainContent.append (" 】" , TextFormatFlag::DontCommit);
558+ }
559+
560+ return {mainContent, supplementContent};
561+ }
435562
436563/* ******************************************************************************
437564 * FcitxCskkFactory
0 commit comments