From 548e4f337306f4032a30b3d1f21b7bfeb1f89cc1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Dec 2025 14:42:40 +0000 Subject: Add `translate_by_grapheme: bool` field --- core/text/edit/text_edit.odin | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/core/text/edit/text_edit.odin b/core/text/edit/text_edit.odin index 8713f6eff..58e184309 100644 --- a/core/text/edit/text_edit.odin +++ b/core/text/edit/text_edit.odin @@ -24,6 +24,7 @@ State :: struct { up_index, down_index: int, // multi-lines + translate_by_grapheme: bool, // translates by codepoint by default // undo undo: [dynamic]^Undo_State, @@ -302,14 +303,32 @@ translate_position :: proc(s: ^State, t: Translation) -> int { case .End: pos = len(buf) case .Left: - pos -= 1 - for pos >= 0 && is_continuation_byte(buf[pos]) { + if s.translate_by_grapheme { + // TODO(bill): determine if there is a faster way to determine the last grapheme + // rather than iterate across the entire string (which may be very slow) + it := utf8.decode_grapheme_iterator_make(string(buf[:pos])) + g: utf8.Grapheme + for { + _, g = utf8.decode_grapheme_iterate(&it) or_break + } + pos -= max(g.width, 1) + } else { pos -= 1 + for pos >= 0 && is_continuation_byte(buf[pos]) { + pos -= 1 + } } case .Right: - pos += 1 - for pos < len(buf) && is_continuation_byte(buf[pos]) { + if s.translate_by_grapheme { + it := utf8.decode_grapheme_iterator_make(string(buf[pos:])) + + _, g, _ := utf8.decode_grapheme_iterate(&it) + pos += max(g.width, 1) + } else { pos += 1 + for pos < len(buf) && is_continuation_byte(buf[pos]) { + pos += 1 + } } case .Up: pos = s.up_index -- cgit v1.2.3