Skip to content

Commit e6a4551

Browse files
committed
Respect UTF-16 positions in LSP word lookup
1 parent df941fa commit e6a4551

2 files changed

Lines changed: 31 additions & 1 deletion

File tree

cmd/vibes/lsp.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,13 +364,15 @@ func wordAtPosition(source string, line, character int) string {
364364
return ""
365365
}
366366

367-
runes := []rune(lines[line])
367+
lineText := lines[line]
368+
runes := []rune(lineText)
368369
if len(runes) == 0 {
369370
return ""
370371
}
371372
if character < 0 {
372373
character = 0
373374
}
375+
character = utf16OffsetToRuneIndex(lineText, character)
374376
if character > len(runes) {
375377
character = len(runes)
376378
}
@@ -401,6 +403,26 @@ func wordAtPosition(source string, line, character int) string {
401403
return string(runes[start:end])
402404
}
403405

406+
func utf16OffsetToRuneIndex(text string, utf16Offset int) int {
407+
if utf16Offset <= 0 {
408+
return 0
409+
}
410+
runeIndex := 0
411+
consumed := 0
412+
for _, r := range text {
413+
if consumed >= utf16Offset {
414+
break
415+
}
416+
if r > 0xFFFF {
417+
consumed += 2
418+
} else {
419+
consumed++
420+
}
421+
runeIndex++
422+
}
423+
return runeIndex
424+
}
425+
404426
func isWordRune(r rune) bool {
405427
return unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' || r == '?' || r == '!'
406428
}

cmd/vibes/lsp_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,14 @@ func TestWordAtPosition(t *testing.T) {
186186
}
187187
}
188188

189+
func TestWordAtPositionUsesUTF16CharacterOffsets(t *testing.T) {
190+
source := "😀😀x y\n"
191+
word := wordAtPosition(source, 0, 4)
192+
if word != "x" {
193+
t.Fatalf("expected x, got %q", word)
194+
}
195+
}
196+
189197
func rawID(value string) *json.RawMessage {
190198
raw := json.RawMessage(value)
191199
return &raw

0 commit comments

Comments
 (0)