From 5f579a4287625a109cfa855f97bdd6fccbe1a7da Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 31 Mar 2023 18:03:38 +0200 Subject: [PATCH] Fix prefix/suffix calculation when determining copilot suggestion Co-Authored-By: Nathan Sobo Co-Authored-By: Mikayla Maki --- crates/editor/src/editor.rs | 38 +++++++++++++++---------------- crates/editor/src/multi_buffer.rs | 4 ++++ crates/text/src/text.rs | 8 +++++++ 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 62efad288d..0b6d19e34a 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1041,29 +1041,26 @@ impl CopilotState { cursor: Anchor, buffer: &MultiBufferSnapshot, ) -> Option<&str> { + use language::ToOffset as _; + let completion = self.completions.get(self.active_completion_index)?; let excerpt_id = self.excerpt_id?; - let completion_buffer_id = buffer.buffer_id_for_excerpt(excerpt_id); - let completion_start = Anchor { - excerpt_id, - buffer_id: completion_buffer_id, - text_anchor: completion.range.start, - }; - let completion_end = Anchor { - excerpt_id, - buffer_id: completion_buffer_id, - text_anchor: completion.range.end, - }; - let prefix_len = common_prefix(buffer.chars_at(completion_start), completion.text.chars()); - let suffix_len = common_prefix( - buffer.reversed_chars_at(completion_end), - completion.text.chars().rev(), - ); + let completion_buffer = buffer.buffer_for_excerpt(excerpt_id)?; - let prefix_end_offset = completion_start.to_offset(&buffer) + prefix_len; - let suffix_start_offset = completion_end.to_offset(&buffer) - suffix_len; - if prefix_end_offset == suffix_start_offset - && prefix_end_offset == cursor.to_offset(&buffer) + let mut completion_range = completion.range.to_offset(&completion_buffer); + let prefix_len = common_prefix( + completion_buffer.chars_for_range(completion_range.clone()), + completion.text.chars(), + ); + completion_range.start += prefix_len; + let suffix_len = common_prefix( + completion_buffer.reversed_chars_for_range(completion_range.clone()), + completion.text[prefix_len..].chars().rev(), + ); + completion_range.end = completion_range.end.saturating_sub(suffix_len); + + if completion_range.is_empty() + && completion_range.start == cursor.text_anchor.to_offset(&completion_buffer) { Some(&completion.text[prefix_len..completion.text.len() - suffix_len]) } else { @@ -6492,6 +6489,7 @@ impl Editor { multi_buffer::Event::Edited => { self.refresh_active_diagnostics(cx); self.refresh_code_actions(cx); + self.refresh_copilot_suggestions(cx); cx.emit(Event::BufferEdited); } multi_buffer::Event::ExcerptsAdded { diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 0b85f94f08..ed4d297c51 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -2933,6 +2933,10 @@ impl MultiBufferSnapshot { Some(self.excerpt(excerpt_id)?.buffer_id) } + pub fn buffer_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<&BufferSnapshot> { + Some(&self.excerpt(excerpt_id)?.buffer) + } + fn excerpt<'a>(&'a self, excerpt_id: ExcerptId) -> Option<&'a Excerpt> { let mut cursor = self.excerpts.cursor::>(); let locator = self.excerpt_locator_for_id(excerpt_id); diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index c7d36e29de..11d451eab0 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -1579,6 +1579,14 @@ impl BufferSnapshot { self.text_for_range(range).flat_map(str::chars) } + pub fn reversed_chars_for_range( + &self, + range: Range, + ) -> impl Iterator + '_ { + self.reversed_chunks_in_range(range) + .flat_map(|chunk| chunk.chars().rev()) + } + pub fn contains_str_at(&self, position: T, needle: &str) -> bool where T: ToOffset,