rope: Fix `point_utf16_to_offset` returning relative offset instead of absolute (#48862)

Jordi Villar created

`ChunkSlice::point_utf16_to_offset` returned `line.len()` (a relative
line byte length) instead of `row_offset_range.end` (the absolute byte
offset within the chunk) when clipping an out-of-range UTF-16 column on
a non-first row.

This caused incorrect position calculations in LSP coordinate
conversions whenever a UTF-16 point had a column beyond the line's
extent on any row after the first in a chunk.

Added a regression test covering clipping on both row 0 and row 1. Not
sure if it's the best place for a test like this one though.

Release Notes:

- N/A

Change summary

crates/rope/src/chunk.rs | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)

Detailed changes

crates/rope/src/chunk.rs 🔗

@@ -501,7 +501,7 @@ impl<'a> ChunkSlice<'a> {
                     self.text
                 );
             }
-            return line.len();
+            return row_offset_range.end;
         }
 
         let mut offset = row_offset_range.start;
@@ -1176,4 +1176,19 @@ mod tests {
         assert_eq!((max_row, max_chars as u32), (longest_row, longest_chars));
         assert_eq!(chunk.tabs().collect::<Vec<_>>(), expected_tab_positions);
     }
+
+    #[gpui::test]
+    fn test_point_utf16_to_offset_clips_to_correct_absolute_offset() {
+        let text = "abc\nde";
+        let chunk = Chunk::new(text);
+        let slice = chunk.as_slice();
+
+        // Clipping on row 0 (row_offset_range.start == 0, so relative == absolute)
+        assert_eq!(slice.point_utf16_to_offset(PointUtf16::new(0, 99), true), 3,);
+
+        // Clipping on row 1 — this is the case that was buggy.
+        // Row 1 starts at byte offset 4 ("de" is bytes 4..6), so the
+        // clipped result must be 6, not 2.
+        assert_eq!(slice.point_utf16_to_offset(PointUtf16::new(1, 99), true), 6,);
+    }
 }