diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 440a5d53469f119c007cdf32e8b6a148121daaa5..a9a95280d829cd4a4f2486c55f34da2271e18006 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -9801,55 +9801,49 @@ mod tests { #[gpui::test] fn test_editing_overlapping_excerpts(cx: &mut gpui::MutableAppContext) { cx.set_global(Settings::test(cx)); - let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx)); + let (initial_text, excerpt_ranges) = marked_text_ranges(indoc! {" + [aaaa + (bbbb] + cccc)"}); + let buffer = cx.add_model(|cx| Buffer::new(0, initial_text, cx)); let multibuffer = cx.add_model(|cx| { let mut multibuffer = MultiBuffer::new(0); - multibuffer.push_excerpts( - buffer, - [ - Point::new(0, 0)..Point::new(1, 4), - Point::new(1, 0)..Point::new(2, 4), - ], - cx, - ); + multibuffer.push_excerpts(buffer, excerpt_ranges, cx); multibuffer }); - assert_eq!( - multibuffer.read(cx).read(cx).text(), - "aaaa\nbbbb\nbbbb\ncccc" - ); - let (_, view) = cx.add_window(Default::default(), |cx| build_editor(multibuffer, cx)); view.update(cx, |view, cx| { - view.select_ranges( - [ - Point::new(1, 1)..Point::new(1, 1), - Point::new(2, 3)..Point::new(2, 3), - ], - None, - cx, - ); + let (expected_text, selection_ranges) = marked_text_ranges(indoc! {" + aaaa + b|bbb + b|bb|b + cccc"}); + assert_eq!(view.text(cx), expected_text); + view.select_ranges(selection_ranges, None, cx); view.handle_input(&Input("X".to_string()), cx); - assert_eq!(view.text(cx), "aaaa\nbXbbXb\nbXbbXb\ncccc"); - assert_eq!( - view.selected_ranges(cx), - [ - Point::new(1, 2)..Point::new(1, 2), - Point::new(2, 5)..Point::new(2, 5), - ] - ); + + let (expected_text, expected_selections) = marked_text_ranges(indoc! {" + aaaa + bX|bbXb + bX|bbX|b + cccc"}); + assert_eq!(view.text(cx), expected_text); + assert_eq!(view.selected_ranges(cx), expected_selections); view.newline(&Newline, cx); - assert_eq!(view.text(cx), "aaaa\nbX\nbbX\nb\nbX\nbbX\nb\ncccc"); - assert_eq!( - view.selected_ranges(cx), - [ - Point::new(2, 0)..Point::new(2, 0), - Point::new(6, 0)..Point::new(6, 0), - ] - ); + let (expected_text, expected_selections) = marked_text_ranges(indoc! {" + aaaa + bX + |bbX + b + bX + |bbX + |b + cccc"}); + assert_eq!(view.text(cx), expected_text); + assert_eq!(view.selected_ranges(cx), expected_selections); }); } diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 7ba9f248065f6b951eb531477452a8415993e683..2f41ce09a01f52d41a4628ed5a9b7d1d00b4738d 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -378,13 +378,11 @@ impl MultiBuffer { let mut insertions = Vec::new(); let mut deletions = Vec::new(); let empty_str: Arc = "".into(); - while let Some((mut range, mut new_text, mut is_insertion)) = edits.next() { - while let Some((next_range, next_new_text, next_is_insertion)) = - edits.peek() - { + while let Some((mut range, new_text, mut is_insertion)) = edits.next() { + while let Some((next_range, _, next_is_insertion)) = edits.peek() { if range.end >= next_range.start { range.end = cmp::max(next_range.end, range.end); - new_text = format!("{new_text}{next_new_text}").into(); + is_insertion |= *next_is_insertion; edits.next(); } else { @@ -395,7 +393,7 @@ impl MultiBuffer { if is_insertion { insertions.push(( buffer.anchor_before(range.start)..buffer.anchor_before(range.end), - new_text, + new_text.clone(), )); } else if !range.is_empty() { deletions.push(( diff --git a/crates/util/src/test/marked_text.rs b/crates/util/src/test/marked_text.rs index e0f549b7df6361e51c92d8b6c96900668b884201..23aa2d5806ad60b78d72b047f45a36d895a55ae1 100644 --- a/crates/util/src/test/marked_text.rs +++ b/crates/util/src/test/marked_text.rs @@ -55,10 +55,18 @@ pub fn marked_text_ranges_by( (unmarked_text, range_lookup) } -pub fn marked_text_ranges(marked_text: &str) -> (String, Vec>) { - let (unmarked_text, mut ranges) = marked_text_ranges_by(marked_text, vec![('[', ']')]); +// Returns ranges delimited by (), [], and <> ranges. Ranges using the same markers +// must not be overlapping. May also include | for empty ranges +pub fn marked_text_ranges(full_marked_text: &str) -> (String, Vec>) { + let (range_marked_text, empty_offsets) = marked_text(full_marked_text); + let (unmarked, range_lookup) = + marked_text_ranges_by(&range_marked_text, vec![('[', ']'), ('(', ')'), ('<', '>')]); ( - unmarked_text, - ranges.remove(&('[', ']')).unwrap_or_else(Vec::new), + unmarked, + range_lookup + .into_values() + .flatten() + .chain(empty_offsets.into_iter().map(|offset| offset..offset)) + .collect(), ) }