From 72a72a2bc21a06502fd177baa44c4daafbca3f96 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sun, 23 Feb 2025 19:00:50 +0100 Subject: [PATCH] app: [macOS] don't discard IME session for consistent snippets An IME session must be discarded when its text content no longer matches the underlying text component content. However, the check for matching was too pessimistic; the IME session would be discarded if the new snippet from the text component was not equal to the snippet reported to the IME. This change implements a refined check that only discards a session if the content of the overlap between the new and old snippets don't match. Fixes an IME issue reported by Zhang Zj. Signed-off-by: Elias Naur --- app/ime.go | 26 ++++++++++++++++++++++++++ app/os_macos.go | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/app/ime.go b/app/ime.go index df944da8..b60c9a21 100644 --- a/app/ime.go +++ b/app/ime.go @@ -5,6 +5,7 @@ package app import ( "unicode" "unicode/utf16" + "unicode/utf8" "gioui.org/io/input" "gioui.org/io/key" @@ -117,3 +118,28 @@ func (e *editorState) RunesIndex(chars int) int { // Assume runes after snippets are one UTF-16 character each. return runes + chars } + +// areSnippetsConsistent reports whether the content of the old snippet is +// consistent with the content of the new. +func areSnippetsConsistent(old, new key.Snippet) bool { + // Compute the overlapping range. + r := old.Range + r.Start = max(r.Start, new.Start) + r.End = max(r.End, r.Start) + r.End = min(r.End, new.End) + return snippetSubstring(old, r) == snippetSubstring(new, r) +} + +func snippetSubstring(s key.Snippet, r key.Range) string { + for r.Start > s.Start && r.Start < s.End { + _, n := utf8.DecodeRuneInString(s.Text) + s.Text = s.Text[n:] + s.Start++ + } + for r.End < s.End && r.End > s.Start { + _, n := utf8.DecodeLastRuneInString(s.Text) + s.Text = s.Text[:len(s.Text)-n] + s.End-- + } + return s.Text +} diff --git a/app/os_macos.go b/app/os_macos.go index 375ddb81..3a01ef25 100644 --- a/app/os_macos.go +++ b/app/os_macos.go @@ -534,7 +534,7 @@ func (w *window) SetCursor(cursor pointer.Cursor) { } func (w *window) EditorStateChanged(old, new editorState) { - if old.Selection.Range != new.Selection.Range || old.Snippet != new.Snippet { + if old.Selection.Range != new.Selection.Range || !areSnippetsConsistent(old.Snippet, new.Snippet) { C.discardMarkedText(w.view) w.w.SetComposingRegion(key.Range{Start: -1, End: -1}) }