From 6137702644e36b05ef74116157338b64710ae25b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=85=E6=88=8E=E6=B0=8F?= Date: Thu, 17 Jul 2025 00:23:55 +0800 Subject: [PATCH] fix crash when enabled inline_candidate the complex logic handles the happy path, but the indices can be wrong eg. when the preedit is a complex structure containing prompt text. code that removes remaining code from the candidate preview is particularly dangerous. the current fix is not perfect and can produce wrong selection range. let's improve it by adding librime APIs that provide segmented and detailed data of the composition. --- sources/SquirrelInputController.swift | 51 +++++++++++++++++++-------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/sources/SquirrelInputController.swift b/sources/SquirrelInputController.swift index d8c9e7352..bad53d9f1 100644 --- a/sources/SquirrelInputController.swift +++ b/sources/SquirrelInputController.swift @@ -457,27 +457,48 @@ private extension SquirrelInputController { if inlineCandidate { var candidatePreview = ctx.commit_text_preview.map { String(cString: $0) } ?? "" + let endOfCandidatePreview = candidatePreview.endIndex if inlinePreedit { + // 左移光標後的情形: + // preedit: ^已選某些字[xiang zuo yi dong]|guangbiao$ + // commit_text_preview: ^已選某些字向左移動$ + // candidate_preview: ^已選某些字[向左移動]|guangbiao$ + // 繼續翻頁至指定更短字詞的情形: + // preedit: ^已選某些字[xiang zuo]yidong|guangbiao$ + // commit_text_preview: ^已選某些字向左yidong$ + // candidate_preview: ^已選某些字[向左]yidong|guangbiao$ + // 光標移至當前段落最左端的情形: + // preedit: ^已選某些字|[xiang zuo yi dong guang biao]$ + // commit_text_preview: ^已選某些字向左移動光標$ + // candidate_preview: ^已選某些字|[向左移動光標]$ + // 討論: + // preedit 與 commit_text_preview 中“已選某些字”部分一致 + // 因此,選中範圍即正在翻譯的碼段“向左移動”中,兩者的 start 值一致 + // 光標位置的範圍是 start ..= endOfCandidatePreview if caretPos >= end && caretPos < preedit.endIndex { + // 從 preedit 截取光標後未翻譯的編碼“guangbiao” candidatePreview += preedit[caretPos...] } - show(preedit: candidatePreview, - selRange: NSRange(location: start.utf16Offset(in: candidatePreview), length: candidatePreview.utf16.distance(from: start, to: candidatePreview.endIndex)), - caretPos: candidatePreview.utf16.count - max(0, preedit.utf16.distance(from: caretPos, to: preedit.endIndex))) } else { - if end < caretPos && start < caretPos { - candidatePreview = String(candidatePreview[..