From 9385690b988cacfadf28e55ecbcc799170ca8131 Mon Sep 17 00:00:00 2001 From: Keith Simmons Date: Thu, 31 Mar 2022 00:55:55 -0700 Subject: [PATCH] Add test for common_prefix_at and rewrite it to be more readable and pass the new test cases --- crates/project/src/project.rs | 2 +- crates/text/src/tests.rs | 10 +++++++--- crates/text/src/text.rs | 29 ++++++++++++++++++++++++++--- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 77dfc741c1..df84aec0c5 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -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(_)) => { diff --git a/crates/text/src/tests.rs b/crates/text/src/tests.rs index 0faf8e19de..54e802b521 100644 --- a/crates/text/src/tests.rs +++ b/crates/text/src/tests.rs @@ -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 ) } diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index 0e742f8a8b..ea0af9d21f 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -1508,11 +1508,34 @@ impl BufferSnapshot { .eq(needle.bytes()) } - pub fn common_prefix_at_position(&self, position: T, needle: &str) -> Range + pub fn common_prefix_at(&self, position: T, needle: &str) -> Range 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 {