Fix hints kitten breaking multi-byte UTF-8 characters when overlaying hint labels

In highlight_mark(), mark_text was sliced using byte-based indexing
(mark_text[:len(hint)] and mark_text[len(hint):]). Since len(hint)
equals the rune count (hint is always ASCII), but len(mark_text) is a
byte count, this could slice in the middle of a multi-byte UTF-8
sequence (e.g. CJK characters), producing an invalid byte sequence
rendered as the Unicode replacement character (�).

Fix by converting mark_text to []rune first, then slicing at rune
boundaries. The hint is ASCII so len(hint) == rune count, requiring
no conversion on the hint side.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gogongxt
2026-05-13 17:09:42 +08:00
parent 8b17088b58
commit 56f276580f

View File

@@ -200,10 +200,12 @@ func main(_ *cli.Command, o *Options, args []string) (rc int, err error) {
if hint == "" {
hint = " "
}
if len(mark_text) <= len(hint) {
hint_runes := len(hint)
runes := []rune(mark_text)
if len(runes) <= hint_runes {
mark_text = ""
} else {
replaced_text := mark_text[:len(hint)]
replaced_text := string(runes[:hint_runes])
replaced_text = strings.ReplaceAll(replaced_text, "\r", "\n")
if strings.Contains(replaced_text, "\n") {
buf := strings.Builder{}
@@ -224,7 +226,7 @@ func main(_ *cli.Command, o *Options, args []string) (rc int, err error) {
}
hint = buf.String()
}
mark_text = mark_text[len(hint):]
mark_text = string(runes[hint_runes:])
}
ans := hint_style(hint) + text_style(mark_text)
return fmt.Sprintf("\x1b]8;;mark:%d\a%s\x1b]8;;\a", m.Index, ans)