From a888620e5fc1175a83d00186c1f293658fa3f67f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 21 Dec 2021 15:25:57 -0800 Subject: [PATCH] Implement MultiBuffer::remove_excerpts We'll need this for updating project diagnostics --- crates/editor/src/multi_buffer.rs | 104 +++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 8 deletions(-) diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 6008f3623c..63c87d6606 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -641,6 +641,57 @@ impl MultiBuffer { id } + pub fn excerpt_ids_for_buffer(&self, buffer: &ModelHandle) -> Vec { + self.buffers + .borrow() + .get(&buffer.id()) + .map_or(Vec::new(), |state| state.excerpts.clone()) + } + + pub fn remove_excerpts<'a>( + &mut self, + excerpt_ids: impl IntoIterator, + cx: &mut ModelContext, + ) { + let mut buffers = self.buffers.borrow_mut(); + let mut snapshot = self.snapshot.borrow_mut(); + let mut new_excerpts = SumTree::new(); + let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>(); + let mut edits = Vec::new(); + for excerpt_id in excerpt_ids { + new_excerpts.push_tree(cursor.slice(&Some(excerpt_id), Bias::Left, &()), &()); + if let Some(excerpt) = cursor.item() { + if excerpt.id == *excerpt_id { + let mut old_start = cursor.start().1; + let old_end = cursor.end(&()).1; + cursor.next(&()); + + if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) { + buffer_state.excerpts.retain(|id| id != excerpt_id); + } + + // When removing the last excerpt, remove the trailing newline from + // the previous excerpt. + if cursor.item().is_none() && old_start > 0 { + old_start -= 1; + new_excerpts.update_last(|e| e.has_trailing_newline = false, &()); + } + + let new_start = new_excerpts.summary().text.bytes; + edits.push(Edit { + old: old_start..old_end, + new: new_start..new_start, + }); + } + } + } + new_excerpts.push_tree(cursor.suffix(&()), &()); + drop(cursor); + snapshot.excerpts = new_excerpts; + self.subscriptions.publish_mut(edits); + cx.notify(); + } + fn on_buffer_event( &mut self, _: ModelHandle, @@ -2063,8 +2114,9 @@ mod tests { ); }); + let snapshot = multibuffer.read(cx).snapshot(cx); assert_eq!( - multibuffer.read(cx).snapshot(cx).text(), + snapshot.text(), concat!( "bbbb\n", // Preserve newlines "c\n", // @@ -2083,27 +2135,44 @@ mod tests { }] ); - let multibuffer = multibuffer.read(cx).snapshot(cx); + let snapshot = multibuffer.read(cx).snapshot(cx); assert_eq!( - multibuffer.clip_point(Point::new(0, 5), Bias::Left), + snapshot.clip_point(Point::new(0, 5), Bias::Left), Point::new(0, 4) ); assert_eq!( - multibuffer.clip_point(Point::new(0, 5), Bias::Right), + snapshot.clip_point(Point::new(0, 5), Bias::Right), Point::new(0, 4) ); assert_eq!( - multibuffer.clip_point(Point::new(5, 1), Bias::Right), + snapshot.clip_point(Point::new(5, 1), Bias::Right), Point::new(5, 1) ); assert_eq!( - multibuffer.clip_point(Point::new(5, 2), Bias::Right), + snapshot.clip_point(Point::new(5, 2), Bias::Right), Point::new(5, 2) ); assert_eq!( - multibuffer.clip_point(Point::new(5, 3), Bias::Right), + snapshot.clip_point(Point::new(5, 3), Bias::Right), Point::new(5, 2) ); + + let snapshot = multibuffer.update(cx, |multibuffer, cx| { + let buffer_2_excerpt_id = multibuffer.excerpt_ids_for_buffer(&buffer_2)[0].clone(); + multibuffer.remove_excerpts(&[buffer_2_excerpt_id], cx); + multibuffer.snapshot(cx) + }); + + assert_eq!( + snapshot.text(), + concat!( + "bbbb\n", // Preserve newlines + "c\n", // + "cc\n", // + "ddd\n", // + "eeee", // + ) + ); } #[gpui::test] @@ -2201,7 +2270,7 @@ mod tests { let mut buffers: Vec> = Vec::new(); let list = cx.add_model(|_| MultiBuffer::new(0)); let mut excerpt_ids = Vec::new(); - let mut expected_excerpts = Vec::new(); + let mut expected_excerpts = Vec::<(ModelHandle, Range)>::new(); let mut old_versions = Vec::new(); for _ in 0..operations { @@ -2210,6 +2279,20 @@ mod tests { let buffer = buffers.choose(&mut rng).unwrap(); buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx)); } + 20..=29 if !expected_excerpts.is_empty() => { + let ix = rng.gen_range(0..expected_excerpts.len()); + let id = excerpt_ids.remove(ix); + let (buffer, range) = expected_excerpts.remove(ix); + let buffer = buffer.read(cx); + log::info!( + "Removing excerpt {}: {:?}", + ix, + buffer + .text_for_range(range.to_offset(&buffer)) + .collect::(), + ); + list.update(cx, |list, cx| list.remove_excerpts(&[id], cx)); + } _ => { let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) { let base_text = RandomCharIter::new(&mut rng).take(10).collect::(); @@ -2275,6 +2358,11 @@ mod tests { expected_text.pop(); } + // Always report one buffer row + if expected_buffer_rows.is_empty() { + expected_buffer_rows.push(Some(0)); + } + assert_eq!(snapshot.text(), expected_text); log::info!("MultiBuffer text: {:?}", expected_text);