diff --git a/internal/ui/render.go b/internal/ui/render.go index 1eb2d56..7d53e82 100644 --- a/internal/ui/render.go +++ b/internal/ui/render.go @@ -24,6 +24,7 @@ import ( "gioui.org/unit" "gioui.org/widget" "golang.org/x/image/math/fixed" +"log" ) // maxInt32 is a large value used as MaxWidth for single-line text layout. @@ -330,7 +331,15 @@ func (r *Renderer) ApplyIMECommitToModel(gtx layout.Context, ev key.EditEvent) { r.imeHoldActive = true r.imeHoldEditSeq = uint64(r.lastEditSeq) r.imeHoldFrames = 0 - caret := ev.Range.End + utf8.RuneCountInString(ev.Text) + // The post-commit caret is at the END of the inserted text, which + // starts at Range.Start: for an insertion (Start == End) that is + // Range.End + len, but for a replacement (a swipe/autocorrect over a + // selection) it is Range.Start + len — Range.End + len would land + // (End-Start) runes past the inserted text and desynchronize the IME's + // caret from ours (observed on the phone: a 4-rune replacement left + // every subsequent commit 4 runes ahead of the caret). + caret := ev.Range.Start + utf8.RuneCountInString(ev.Text) + log.Printf("IME PUSH commit-range=[%d,%d) text=%q -> sel caret=%d", ev.Range.Start, ev.Range.End, ev.Text, caret) r.lastSelStart, r.lastSelCaret = -1, caret r.lastIMECaretPos = r.imeCaretPos gtx.Execute(key.SelectionCmd{ @@ -405,6 +414,7 @@ func (r *Renderer) FlushIME(gtx layout.Context, tf TextField) { // this runs — see ApplyIMECommitToModel — so a normal keystroke // never reaches this branch; it is the re-anchoring path: scroll, // tap, file switch, snapped commit, external edit.) + log.Printf("IME PUSH snippet=[%d,%d) len=%d (restart)", snippet.Range.Start, snippet.Range.End, utf8.RuneCountInString(snippet.Text)) r.lastSelStart, r.lastSelCaret = -1, -1 gtx.Execute(key.SnippetCmd{Tag: tf.id, Snippet: snippet}) } @@ -428,6 +438,7 @@ func (r *Renderer) FlushIME(gtx layout.Context, tf TextField) { r.lastSelStart = selStart r.lastSelCaret = selEnd r.lastIMECaretPos = r.imeCaretPos + log.Printf("IME PUSH sel=[%d,%d)", selStart, selEnd) rng := key.Range{Start: selStart, End: selEnd} if selStart < 0 { rng = key.Range{Start: selEnd, End: selEnd}