Detailed changes
@@ -2364,7 +2364,7 @@ impl Project {
(range_from_lsp(edit.range), edit.new_text.clone())
}
None => (
- this.common_prefix_at_position(position, &lsp_completion.label),
+ this.common_prefix_at(position, &lsp_completion.label),
lsp_completion.label.clone(),
),
Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
@@ -7,6 +7,7 @@ use std::{
iter::Iterator,
time::{Duration, Instant},
};
+use util::test::marked_text_ranges;
#[cfg(test)]
#[ctor::ctor]
@@ -166,10 +167,13 @@ fn test_line_len() {
#[test]
fn test_common_prefix_at_positionn() {
- let buffer = Buffer::new(0, 0, History::new("a = (bcd)".into()));
+ let (text, ranges) = marked_text_ranges("a = [bcd]");
+ let buffer = Buffer::new(0, 0, History::new(text.into()));
+ let snapshot = &buffer.snapshot();
+ let expected_range = ranges[0].to_offset(&snapshot);
assert_eq!(
- buffer.common_prefix_at_position(Point::new(0, 8), "bcdef"),
- Point::new(0, 5)..Point::new(0, 8)
+ buffer.common_prefix_at(expected_range.end, "bcdef"),
+ expected_range
)
}
@@ -1508,11 +1508,34 @@ impl BufferSnapshot {
.eq(needle.bytes())
}
- pub fn common_prefix_at_position<T>(&self, position: T, needle: &str) -> Range<T>
+ pub fn common_prefix_at<T>(&self, position: T, needle: &str) -> Range<T>
where
- T: TextDimension + ToOffset,
+ T: Clone + ToOffset + FromAnchor,
{
- todo!()
+ let position_offset = position.to_offset(self);
+ // Get byte indices and char counts for every character in needle in reverse order
+ let char_indices = needle
+ .char_indices()
+ .map(|(index, _)| index)
+ .chain(std::iter::once(needle.len()))
+ .enumerate()
+ // Don't test any prefixes that are bigger than the requested position
+ .take_while(|(_, prefix_length)| *prefix_length <= position_offset);
+
+ let start = char_indices
+ // Compute the prefix string and prefix start location
+ .map(move |(byte_position, char_length)| {
+ (position_offset - char_length, &needle[..byte_position])
+ })
+ // Only take strings when the prefix is contained at the expected prefix position
+ .filter(|(prefix_offset, prefix)| self.contains_str_at(prefix_offset, prefix))
+ // Convert offset to T
+ .map(|(prefix_offset, _)| T::from_anchor(&self.anchor_before(prefix_offset), self))
+ .last()
+ // If no prefix matches, return the passed in position to create an empty range
+ .unwrap_or(position.clone());
+
+ start..position
}
pub fn text(&self) -> String {