@@ -44,6 +44,15 @@ public final class SegmentsManager {
4444 private var replaceSuggestions : [ Candidate ] = [ ]
4545 private var suggestSelectionIndex : Int ?
4646
47+ public struct PredictionCandidate : Sendable {
48+ public var displayText : String
49+ public var appendText : String
50+ }
51+
52+ private func candidateReading( _ candidate: Candidate ) -> String {
53+ candidate. data. map ( \. ruby) . joined ( )
54+ }
55+
4756 private lazy var zenzaiPersonalizationMode : ConvertRequestOptions . ZenzaiMode . PersonalizationMode ? = self . getZenzaiPersonalizationMode ( )
4857
4958 private func getZenzaiPersonalizationMode( ) -> ConvertRequestOptions . ZenzaiMode . PersonalizationMode ? {
@@ -121,10 +130,15 @@ public final class SegmentsManager {
121130 }
122131 }
123132
124- private func options( leftSideContext: String ? = nil , requestRichCandidates: Bool = false ) -> ConvertRequestOptions {
133+ private func options(
134+ leftSideContext: String ? ,
135+ requestRichCandidates: Bool ,
136+ requireJapanesePrediction: ConvertRequestOptions . PredictionMode ,
137+ requireEnglishPrediction: ConvertRequestOptions . PredictionMode
138+ ) -> ConvertRequestOptions {
125139 . init(
126- requireJapanesePrediction: false ,
127- requireEnglishPrediction: false ,
140+ requireJapanesePrediction: requireJapanesePrediction ,
141+ requireEnglishPrediction: requireEnglishPrediction ,
128142 keyboardLanguage: . ja_JP,
129143 englishCandidateInRoman2KanaInput: false ,
130144 fullWidthRomanCandidate: true ,
@@ -361,7 +375,15 @@ public final class SegmentsManager {
361375
362376 let prefixComposingText = self . composingText. prefixToCursorPosition ( )
363377 let leftSideContext = forcedLeftSideContext ?? self . getCleanLeftSideContext ( maxCount: 30 )
364- let result = self . kanaKanjiConverter. requestCandidates ( prefixComposingText, options: options ( leftSideContext: leftSideContext, requestRichCandidates: requestRichCandidates) )
378+ let result = self . kanaKanjiConverter. requestCandidates (
379+ prefixComposingText,
380+ options: options (
381+ leftSideContext: leftSideContext,
382+ requestRichCandidates: requestRichCandidates,
383+ requireJapanesePrediction: Config . DebugPredictiveTyping ( ) . value ? . manualMix : . disabled,
384+ requireEnglishPrediction: Config . DebugPredictiveTyping ( ) . value ? . manualMix : . disabled
385+ )
386+ )
365387 self . rawCandidates = result
366388 }
367389
@@ -556,6 +578,52 @@ public final class SegmentsManager {
556578 suggestSelectionIndex = nil
557579 }
558580
581+ public func requestPredictionCandidates( ) -> [ PredictionCandidate ] {
582+ guard Config . DebugPredictiveTyping ( ) . value else {
583+ return [ ]
584+ }
585+
586+ let target = self . composingText. convertTarget
587+ guard !target. isEmpty else {
588+ return [ ]
589+ }
590+
591+ var matchTarget = target
592+ if let last = matchTarget. last,
593+ last. unicodeScalars. allSatisfy ( { $0. isASCII && CharacterSet . letters. contains ( $0) } ) {
594+ matchTarget. removeLast ( )
595+ }
596+ guard matchTarget. count >= 2 else {
597+ return [ ]
598+ }
599+ matchTarget = matchTarget. toHiragana ( )
600+
601+ guard let rawCandidates else {
602+ return [ ]
603+ }
604+
605+ for candidate in rawCandidates. predictionResults {
606+ let reading = candidateReading ( candidate)
607+ guard !reading. isEmpty else {
608+ continue
609+ }
610+ let readingHiragana = reading. toHiragana ( )
611+ guard readingHiragana. hasPrefix ( matchTarget) else {
612+ continue
613+ }
614+ guard matchTarget. count < readingHiragana. count else {
615+ continue
616+ }
617+ let appendText = String ( readingHiragana. dropFirst ( matchTarget. count) )
618+ guard !appendText. isEmpty else {
619+ continue
620+ }
621+ return [ . init( displayText: candidate. text, appendText: appendText) ]
622+ }
623+
624+ return [ ]
625+ }
626+
559627 // swiftlint:disable:next cyclomatic_complexity
560628 public func getCurrentMarkedText( inputState: InputState ) -> MarkedText {
561629 switch inputState {
0 commit comments