From 55dc9ff7ca77009d0c342ae6377b0d1d7413e32c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 22 Sep 2025 13:45:23 +0200 Subject: [PATCH] text: Implement `Rope::clip_offset` in terms of the new utf8 boundary methods (#38630) Release Notes: - N/A --- .../src/assistant_context.rs | 2 +- crates/language/src/buffer.rs | 4 ++-- crates/project/src/git_store/conflict_set.rs | 4 ++-- crates/rope/src/rope.rs | 24 ++++--------------- crates/text/src/text.rs | 4 +++- 5 files changed, 12 insertions(+), 26 deletions(-) diff --git a/crates/assistant_context/src/assistant_context.rs b/crates/assistant_context/src/assistant_context.rs index 12eda0954a2e1cca9ddc7df9816b8f5a37d0ce10..23aeabbc8929e6a3874c2fbbf74b8f9729860481 100644 --- a/crates/assistant_context/src/assistant_context.rs +++ b/crates/assistant_context/src/assistant_context.rs @@ -2445,7 +2445,7 @@ impl AssistantContext { .message_anchors .get(next_message_ix) .map_or(buffer.len(), |message| { - buffer.clip_offset(message.start.to_offset(buffer) - 1, Bias::Left) + buffer.clip_offset(message.start.to_previous_offset(buffer), Bias::Left) }); Some(self.insert_message_at_offset(offset, role, status, cx)) } else { diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 1f5c35f8df9288182b294b8e52a9cd7bdb531124..311ef4d55b947888cd7fbc6706a9bd581f2dd27d 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -4198,8 +4198,8 @@ impl BufferSnapshot { range: Range, options: TreeSitterOptions, ) -> impl Iterator, TextObject)> + '_ { - let range = range.start.to_offset(self).saturating_sub(1) - ..self.len().min(range.end.to_offset(self) + 1); + let range = + range.start.to_previous_offset(self)..self.len().min(range.end.to_next_offset(self)); let mut matches = self.syntax diff --git a/crates/project/src/git_store/conflict_set.rs b/crates/project/src/git_store/conflict_set.rs index 2bcfc75b32da3c5a4860cc72f3266bff38f022e3..067af17820e58264006d0227cfb0f3c13069fcf9 100644 --- a/crates/project/src/git_store/conflict_set.rs +++ b/crates/project/src/git_store/conflict_set.rs @@ -344,8 +344,8 @@ mod tests { assert_eq!(conflicts_in_range.len(), 1); // Test with a range that doesn't include any conflicts - let range = buffer.anchor_after(first_conflict_end.to_offset(&buffer) + 1) - ..buffer.anchor_before(second_conflict_start.to_offset(&buffer) - 1); + let range = buffer.anchor_after(first_conflict_end.to_next_offset(&buffer)) + ..buffer.anchor_before(second_conflict_start.to_previous_offset(&buffer)); let conflicts_in_range = conflict_snapshot.conflicts_in_range(range, &snapshot); assert_eq!(conflicts_in_range.len(), 0); } diff --git a/crates/rope/src/rope.rs b/crates/rope/src/rope.rs index d802f972168348b15f003e1fd2fa567c1f9d75bb..cb2e103f76fa636571526c71afcbb3358542b083 100644 --- a/crates/rope/src/rope.rs +++ b/crates/rope/src/rope.rs @@ -459,26 +459,10 @@ impl Rope { }) } - pub fn clip_offset(&self, mut offset: usize, bias: Bias) -> usize { - let mut cursor = self.chunks.cursor::(&()); - cursor.seek(&offset, Bias::Left); - if let Some(chunk) = cursor.item() { - let mut ix = offset - cursor.start(); - while !chunk.text.is_char_boundary(ix) { - match bias { - Bias::Left => { - ix -= 1; - offset -= 1; - } - Bias::Right => { - ix += 1; - offset += 1; - } - } - } - offset - } else { - self.summary().len + pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize { + match bias { + Bias::Left => self.floor_char_boundary(offset), + Bias::Right => self.ceil_char_boundary(offset), } } diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index bbf9e2e3812238eebbdf92c63bd3b23819a9dac0..a38693ed934855acd0e0c6ff726c7835a1aa057e 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -2128,7 +2128,7 @@ impl BufferSnapshot { let row_end_offset = if row >= self.max_point().row { self.len() } else { - Point::new(row + 1, 0).to_offset(self) - 1 + Point::new(row + 1, 0).to_previous_offset(self) }; (row_end_offset - row_start_offset) as u32 } @@ -3076,11 +3076,13 @@ impl operation_queue::Operation for Operation { pub trait ToOffset { fn to_offset(&self, snapshot: &BufferSnapshot) -> usize; + /// Turns this point into the next offset in the buffer that comes after this, respecting utf8 boundaries. fn to_next_offset(&self, snapshot: &BufferSnapshot) -> usize { snapshot .visible_text .ceil_char_boundary(self.to_offset(snapshot) + 1) } + /// Turns this point into the previous offset in the buffer that comes before this, respecting utf8 boundaries. fn to_previous_offset(&self, snapshot: &BufferSnapshot) -> usize { snapshot .visible_text