Skip to content

Commit bad03fb

Browse files
Fixing a bug where UTF-8 encodings resulted in incorrect char offset
calculations. Co-authored-by: Vinicius Stock <vinistock@users.noreply.github.com> Co-authored-by: Vinicius Stock <vinistock@users.noreply.github.com>
1 parent 19e925d commit bad03fb

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

lib/ruby_lsp/document.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ class Scanner
176176
def initialize(source, encoding)
177177
@current_line = 0 #: Integer
178178
@pos = 0 #: Integer
179-
@source = source.codepoints #: Array[Integer]
179+
@source = encoding == Encoding::UTF_8 ? source.bytes : source.codepoints #: Array[Integer]
180+
@text = source
180181
@encoding = encoding
181182
end
182183

@@ -200,7 +201,14 @@ def find_char_position(position)
200201

201202
# The final position is the beginning of the line plus the requested column. If the encoding is UTF-16, we also
202203
# need to adjust for surrogate pairs
203-
requested_position = @pos + position[:character]
204+
requested_position = if @encoding == Encoding::UTF_8
205+
character_offset = @text.byteslice(@pos, position[:character]) #: as !nil
206+
.length
207+
@pos + character_offset
208+
209+
else
210+
@pos + position[:character]
211+
end
204212

205213
if @encoding == Encoding::UTF_16LE
206214
requested_position -= utf_16_character_position_correction(@pos, requested_position)

test/ruby_document_test.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,20 @@ def foo
5959
RUBY
6060
end
6161

62+
def test_multibyte_character_offsets_are_bytes_in_utf8
63+
document = RubyLsp::RubyDocument.new(source: +<<~RUBY, version: 1, uri: @uri, global_state: @global_state)
64+
65+
RUBY
66+
67+
document.push_edits(
68+
[{ range: { start: { line: 0, character: 3 }, end: { line: 0, character: 3 } }, text: "r" }], version: 2
69+
)
70+
71+
assert_equal(<<~RUBY, document.source)
72+
bár
73+
RUBY
74+
end
75+
6276
def test_deletion_full_node
6377
document = RubyLsp::RubyDocument.new(source: +<<~RUBY, version: 1, uri: @uri, global_state: @global_state)
6478
def foo

0 commit comments

Comments
 (0)