diff --git a/crates/agent/src/edit_agent/streaming_fuzzy_matcher.rs b/crates/agent/src/edit_agent/streaming_fuzzy_matcher.rs index 904ec05a8c7565d5052cd546fc0bf6d723ffa375..008a39aa6efaddb2974ae6b4d6537e408f8faeb7 100644 --- a/crates/agent/src/edit_agent/streaming_fuzzy_matcher.rs +++ b/crates/agent/src/edit_agent/streaming_fuzzy_matcher.rs @@ -320,7 +320,7 @@ mod tests { ); let snapshot = buffer.snapshot(); - let mut finder = StreamingFuzzyMatcher::new(snapshot); + let mut finder = StreamingFuzzyMatcher::new(snapshot.clone()); assert_eq!(push(&mut finder, ""), None); assert_eq!(finish(finder), None); } @@ -334,7 +334,7 @@ mod tests { ); let snapshot = buffer.snapshot(); - let mut finder = StreamingFuzzyMatcher::new(snapshot); + let mut finder = StreamingFuzzyMatcher::new(snapshot.clone()); // Push partial query assert_eq!(push(&mut finder, "This"), None); @@ -366,7 +366,7 @@ mod tests { ); let snapshot = buffer.snapshot(); - let mut finder = StreamingFuzzyMatcher::new(snapshot); + let mut finder = StreamingFuzzyMatcher::new(snapshot.clone()); // Push a fuzzy query that should match the first function assert_eq!( @@ -392,7 +392,7 @@ mod tests { ); let snapshot = buffer.snapshot(); - let mut finder = StreamingFuzzyMatcher::new(snapshot); + let mut finder = StreamingFuzzyMatcher::new(snapshot.clone()); // No match initially assert_eq!(push(&mut finder, "Lin"), None); @@ -421,7 +421,7 @@ mod tests { ); let snapshot = buffer.snapshot(); - let mut finder = StreamingFuzzyMatcher::new(snapshot); + let mut finder = StreamingFuzzyMatcher::new(snapshot.clone()); // Push text in small chunks across line boundaries assert_eq!(push(&mut finder, "jumps "), None); // No newline yet @@ -459,7 +459,7 @@ mod tests { ); let snapshot = buffer.snapshot(); - let mut finder = StreamingFuzzyMatcher::new(snapshot); + let mut finder = StreamingFuzzyMatcher::new(snapshot.clone()); assert_eq!( push(&mut finder, "impl Debug for User {\n"), @@ -716,7 +716,7 @@ mod tests { "Expected to match `second_function` based on the line hint" ); - let mut matcher = StreamingFuzzyMatcher::new(snapshot); + let mut matcher = StreamingFuzzyMatcher::new(snapshot.clone()); matcher.push(query, None); matcher.finish(); let best_match = matcher.select_best_match(); @@ -732,7 +732,7 @@ mod tests { let buffer = TextBuffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), text.clone()); let snapshot = buffer.snapshot(); - let mut matcher = StreamingFuzzyMatcher::new(snapshot); + let mut matcher = StreamingFuzzyMatcher::new(snapshot.clone()); // Split query into random chunks let chunks = to_random_chunks(rng, query); diff --git a/crates/buffer_diff/src/buffer_diff.rs b/crates/buffer_diff/src/buffer_diff.rs index 51e0a5be572e0ddc0e769dacde9cbb46a719b2a9..76db07f13d5139d432575db480d7b537bd6eee78 100644 --- a/crates/buffer_diff/src/buffer_diff.rs +++ b/crates/buffer_diff/src/buffer_diff.rs @@ -30,7 +30,7 @@ pub struct BufferDiff { #[derive(Clone)] pub struct BufferDiffSnapshot { inner: BufferDiffInner, - secondary_diff: Option>, + secondary_diff: Option>, } impl std::fmt::Debug for BufferDiffSnapshot { @@ -222,11 +222,11 @@ impl std::fmt::Debug for BufferDiffInner { impl BufferDiffSnapshot { #[cfg(test)] fn new_sync( - buffer: text::BufferSnapshot, + buffer: &text::BufferSnapshot, diff_base: String, cx: &mut gpui::TestAppContext, ) -> BufferDiffSnapshot { - let buffer_diff = cx.new(|cx| BufferDiff::new_with_base_text(&diff_base, &buffer, cx)); + let buffer_diff = cx.new(|cx| BufferDiff::new_with_base_text(&diff_base, buffer, cx)); buffer_diff.update(cx, |buffer_diff, cx| buffer_diff.snapshot(cx)) } @@ -950,10 +950,10 @@ fn build_diff_options( fn compute_hunks( diff_base: Option<(Arc, Rope)>, - buffer: text::BufferSnapshot, + buffer: &text::BufferSnapshot, diff_options: Option, ) -> SumTree { - let mut tree = SumTree::new(&buffer); + let mut tree = SumTree::new(buffer); if let Some((diff_base, diff_base_rope)) = diff_base { let buffer_text = buffer.as_rope().to_string(); @@ -980,7 +980,7 @@ fn compute_hunks( base_word_diffs: Vec::default(), buffer_word_diffs: Vec::default(), }, - &buffer, + buffer, ); return tree; } @@ -992,11 +992,11 @@ fn compute_hunks( &patch, hunk_index, &diff_base_rope, - &buffer, + buffer, &mut divergence, diff_options.as_ref(), ); - tree.push(hunk, &buffer); + tree.push(hunk, buffer); } } } else { @@ -1007,7 +1007,7 @@ fn compute_hunks( base_word_diffs: Vec::default(), buffer_word_diffs: Vec::default(), }, - &buffer, + buffer, ); } @@ -1544,7 +1544,7 @@ impl BufferDiff { base_text .clone() .map(|base_text| (base_text, base_text_rope.clone())), - buffer.clone(), + &buffer, diff_options, ); let base_text = base_text.unwrap_or_default(); @@ -1785,10 +1785,10 @@ impl BufferDiff { base_text_exists: self.inner.base_text_exists, buffer_snapshot: self.inner.buffer_snapshot.clone(), }, - secondary_diff: self - .secondary_diff - .as_ref() - .map(|diff| Box::new(diff.read(cx).snapshot(cx))), + secondary_diff: self.secondary_diff.as_ref().map(|diff| { + debug_assert!(diff.read(cx).secondary_diff.is_none()); + Arc::new(diff.read(cx).snapshot(cx)) + }), } } @@ -2018,7 +2018,7 @@ mod tests { .unindent(); let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text); - let mut diff = BufferDiffSnapshot::new_sync(buffer.clone(), diff_base.clone(), cx); + let mut diff = BufferDiffSnapshot::new_sync(&buffer, diff_base.clone(), cx); assert_hunks( diff.hunks_intersecting_range( Anchor::min_max_range_for_buffer(buffer.remote_id()), @@ -2030,7 +2030,7 @@ mod tests { ); buffer.edit([(0..0, "point five\n")]); - diff = BufferDiffSnapshot::new_sync(buffer.clone(), diff_base.clone(), cx); + diff = BufferDiffSnapshot::new_sync(&buffer, diff_base.clone(), cx); assert_hunks( diff.hunks_intersecting_range( Anchor::min_max_range_for_buffer(buffer.remote_id()), @@ -2101,10 +2101,9 @@ mod tests { .unindent(); let buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text); - let unstaged_diff = BufferDiffSnapshot::new_sync(buffer.clone(), index_text, cx); - let mut uncommitted_diff = - BufferDiffSnapshot::new_sync(buffer.clone(), head_text.clone(), cx); - uncommitted_diff.secondary_diff = Some(Box::new(unstaged_diff)); + let unstaged_diff = BufferDiffSnapshot::new_sync(&buffer, index_text, cx); + let mut uncommitted_diff = BufferDiffSnapshot::new_sync(&buffer, head_text.clone(), cx); + uncommitted_diff.secondary_diff = Some(Arc::new(unstaged_diff)); let expected_hunks = vec![ (2..3, "two\n", "TWO\n", DiffHunkStatus::modified_none()), @@ -2631,7 +2630,7 @@ mod tests { let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text_1); let empty_diff = cx.update(|cx| BufferDiff::new(&buffer, cx).snapshot(cx)); - let diff_1 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx); + let diff_1 = BufferDiffSnapshot::new_sync(&buffer, base_text.clone(), cx); let DiffChanged { changed_range, base_text_changed_range, @@ -2666,7 +2665,7 @@ mod tests { " .unindent(), ); - let diff_2 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx); + let diff_2 = BufferDiffSnapshot::new_sync(&buffer, base_text.clone(), cx); let DiffChanged { changed_range, base_text_changed_range, @@ -2704,7 +2703,7 @@ mod tests { " .unindent(), ); - let diff_3 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx); + let diff_3 = BufferDiffSnapshot::new_sync(&buffer, base_text.clone(), cx); let DiffChanged { changed_range, base_text_changed_range, @@ -2738,7 +2737,7 @@ mod tests { " .unindent(), ); - let diff_4 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx); + let diff_4 = BufferDiffSnapshot::new_sync(&buffer, base_text.clone(), cx); let DiffChanged { changed_range, base_text_changed_range, @@ -3172,11 +3171,11 @@ mod tests { .unindent(); let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text); - let old_buffer = buffer.snapshot(); - let diff_a = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx); + let old_buffer = buffer.snapshot().clone(); + let diff_a = BufferDiffSnapshot::new_sync(&buffer, base_text.clone(), cx); buffer.edit([(Point::new(1, 3)..Point::new(1, 3), "\n")]); - let diff_b = BufferDiffSnapshot::new_sync(buffer.clone(), base_text, cx); + let diff_b = BufferDiffSnapshot::new_sync(&buffer, base_text, cx); let DiffChanged { changed_range, @@ -3235,11 +3234,11 @@ mod tests { .unindent(); let mut buffer_2 = Buffer::new(ReplicaId::LOCAL, BufferId::new(2).unwrap(), buffer_text_2); - let old_buffer_2 = buffer_2.snapshot(); - let diff_2a = BufferDiffSnapshot::new_sync(buffer_2.clone(), base_text_2.clone(), cx); + let old_buffer_2 = buffer_2.snapshot().clone(); + let diff_2a = BufferDiffSnapshot::new_sync(&buffer_2, base_text_2.clone(), cx); buffer_2.edit([(Point::new(4, 0)..Point::new(4, 4), "FIVE_CHANGED")]); - let diff_2b = BufferDiffSnapshot::new_sync(buffer_2.clone(), base_text_2, cx); + let diff_2b = BufferDiffSnapshot::new_sync(&buffer_2, base_text_2, cx); let DiffChanged { changed_range, @@ -3293,7 +3292,7 @@ mod tests { buffer_text_1.to_string(), ); - let old_base_snapshot_1 = base_text_buffer.snapshot(); + let old_base_snapshot_1 = base_text_buffer.snapshot().clone(); let old_hunks_1 = compute_hunks( Some((Arc::from(initial_base), Rope::from(initial_base))), buffer.snapshot(), @@ -3352,7 +3351,7 @@ mod tests { buffer_text_2.to_string(), ); - let old_base_snapshot_2 = base_buf_2.snapshot(); + let old_base_snapshot_2 = base_buf_2.snapshot().clone(); let old_hunks_2 = compute_hunks( Some((Arc::from(simple_base), Rope::from(simple_base))), buffer_2.snapshot(), @@ -3419,7 +3418,7 @@ mod tests { buffer_text_3.to_string(), ); - let old_base_snapshot_3 = base_buf_3.snapshot(); + let old_base_snapshot_3 = base_buf_3.snapshot().clone(); let old_hunks_3 = compute_hunks( Some((Arc::from(base_3), Rope::from(base_3))), buffer_3.snapshot(), @@ -3485,8 +3484,8 @@ mod tests { buffer_text_4.to_string(), ); - let old_base_snapshot_4 = base_buf_4.snapshot(); - let old_buffer_snapshot_4 = buffer_4.snapshot(); + let old_base_snapshot_4 = base_buf_4.snapshot().clone(); + let old_buffer_snapshot_4 = buffer_4.snapshot().clone(); let old_hunks_4 = compute_hunks( Some((Arc::from(base_4), Rope::from(base_4))), buffer_4.snapshot(), diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index fb3d4921e2e8049cf34633119c384146b67005f4..f381d47d5955684d0519ab222300c91919e25340 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -441,6 +441,15 @@ impl DisplayMap { return; }; + // Second call to set_companion doesn't need to do anything + if companion_display_map + .update(cx, |companion_dm, _| companion_dm.companion.is_none()) + .unwrap_or(true) + { + self.companion = Some((companion_display_map, companion)); + return; + } + let rhs_display_map_id = companion.read(cx).rhs_display_map_id; if self.entity_id != rhs_display_map_id { let buffer_mapping = companion diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index b85f13e3a67bffb6cffb63abe792487045a1f770..ed7b2d87469ce38754c95f2d6e4173c3a83e8dc2 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -1110,20 +1110,32 @@ impl BlockMap { let mut companion_tab_point_cursor = companion_snapshot.tab_point_cursor(); let mut companion_wrap_point_cursor = companion_snapshot.wrap_point_cursor(); - let mut determine_spacer = |our_point: Point, their_point: Point, delta: i32| { - let our_wrap = our_wrap_point_cursor + let mut our_wrapper = |our_point: Point| { + our_wrap_point_cursor .map(our_tab_point_cursor.map( our_fold_point_cursor.map(our_inlay_point_cursor.map(our_point), Bias::Left), )) - .row(); - let companion_wrap = companion_wrap_point_cursor + .row() + }; + let mut companion_wrapper = |their_point: Point| { + companion_wrap_point_cursor .map( companion_tab_point_cursor.map( companion_fold_point_cursor .map(companion_inlay_point_cursor.map(their_point), Bias::Left), ), ) - .row(); + .row() + }; + fn determine_spacer( + our_wrapper: &mut impl FnMut(Point) -> WrapRow, + companion_wrapper: &mut impl FnMut(Point) -> WrapRow, + our_point: Point, + their_point: Point, + delta: i32, + ) -> (i32, Option<(WrapRow, u32)>) { + let our_wrap = our_wrapper(our_point); + let companion_wrap = companion_wrapper(their_point); let new_delta = companion_wrap.0 as i32 - our_wrap.0 as i32; let spacer = if new_delta > delta { @@ -1133,7 +1145,7 @@ impl BlockMap { None }; (new_delta, spacer) - }; + } let mut result = Vec::new(); @@ -1179,12 +1191,8 @@ impl BlockMap { // Case 3: We are at the start of the excerpt--no previous row to use as the baseline. (first_point, edit_for_first_point.new.start) }; - let our_baseline = wrap_snapshot - .make_wrap_point(our_baseline, Bias::Left) - .row(); - let their_baseline = companion_snapshot - .make_wrap_point(their_baseline, Bias::Left) - .row(); + let our_baseline = our_wrapper(our_baseline); + let their_baseline = companion_wrapper(their_baseline); let mut delta = their_baseline.0 as i32 - our_baseline.0 as i32; @@ -1201,8 +1209,13 @@ impl BlockMap { current_boundary = next_point; } - let (new_delta, spacer) = - determine_spacer(current_boundary, current_range.end, delta); + let (new_delta, spacer) = determine_spacer( + &mut our_wrapper, + &mut companion_wrapper, + current_boundary, + current_range.end, + delta, + ); delta = new_delta; if let Some((wrap_row, height)) = spacer { @@ -1229,8 +1242,13 @@ impl BlockMap { } // Align the two sides at the start of this group. - let (delta_at_start, mut spacer_at_start) = - determine_spacer(current_boundary, current_range.start, delta); + let (delta_at_start, mut spacer_at_start) = determine_spacer( + &mut our_wrapper, + &mut companion_wrapper, + current_boundary, + current_range.start, + delta, + ); delta = delta_at_start; while let Some(next_point) = source_points.peek().copied() { @@ -1260,8 +1278,13 @@ impl BlockMap { break; } - let (delta_at_end, spacer_at_end) = - determine_spacer(current_boundary, current_range.end, delta); + let (delta_at_end, spacer_at_end) = determine_spacer( + &mut our_wrapper, + &mut companion_wrapper, + current_boundary, + current_range.end, + delta, + ); delta = delta_at_end; if let Some((wrap_row, mut height)) = spacer_at_start { @@ -1289,8 +1312,13 @@ impl BlockMap { } if last_source_point == excerpt.source_excerpt_range.end { - let (_new_delta, spacer) = - determine_spacer(last_source_point, excerpt.target_excerpt_range.end, delta); + let (_new_delta, spacer) = determine_spacer( + &mut our_wrapper, + &mut companion_wrapper, + last_source_point, + excerpt.target_excerpt_range.end, + delta, + ); if let Some((wrap_row, height)) = spacer { result.push(( BlockPlacement::Below(wrap_row), diff --git a/crates/editor/src/split.rs b/crates/editor/src/split.rs index f4236a1ab15dc63f690b6b1026567f07d6614314..193dd64a77da4b2e8552d275e749c832d569d1bc 100644 --- a/crates/editor/src/split.rs +++ b/crates/editor/src/split.rs @@ -523,6 +523,7 @@ impl SplittableEditor { convert_lhs_rows_to_rhs, ); + // stream this for (path, diff) in path_diffs { for (lhs, rhs) in lhs.update_path_excerpts_from_rhs(path, &self.rhs_multibuffer, diff.clone(), cx) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 968e46eb3cdf97662d7fb77f2ee0e3afb517edf1..998bc23e8ee4deb8d5ef547f7992d79e6bc6d13a 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -151,16 +151,16 @@ pub struct TreeSitterData { const MAX_ROWS_IN_A_CHUNK: u32 = 50; impl TreeSitterData { - fn clear(&mut self, snapshot: text::BufferSnapshot) { - self.chunks = RowChunks::new(snapshot, MAX_ROWS_IN_A_CHUNK); + fn clear(&mut self, snapshot: &text::BufferSnapshot) { + self.chunks = RowChunks::new(&snapshot, MAX_ROWS_IN_A_CHUNK); self.brackets_by_chunks.get_mut().clear(); self.brackets_by_chunks .get_mut() .resize(self.chunks.len(), None); } - fn new(snapshot: text::BufferSnapshot) -> Self { - let chunks = RowChunks::new(snapshot, MAX_ROWS_IN_A_CHUNK); + fn new(snapshot: &text::BufferSnapshot) -> Self { + let chunks = RowChunks::new(&snapshot, MAX_ROWS_IN_A_CHUNK); Self { brackets_by_chunks: Mutex::new(vec![None; chunks.len()]), chunks, @@ -188,12 +188,12 @@ struct BufferBranchState { pub struct BufferSnapshot { pub text: text::BufferSnapshot, pub syntax: SyntaxSnapshot, - file: Option>, + tree_sitter_data: Arc, diagnostics: TreeMap, remote_selections: TreeMap, language: Option>, + file: Option>, non_text_state_update_count: usize, - tree_sitter_data: Arc, pub capability: Capability, } @@ -1168,14 +1168,14 @@ impl Buffer { let buffer_id = entity_id.as_non_zero_u64().into(); async move { let text = - TextBuffer::new_normalized(ReplicaId::LOCAL, buffer_id, Default::default(), text) - .snapshot(); + TextBuffer::new_normalized(ReplicaId::LOCAL, buffer_id, Default::default(), text); + let text = text.into_snapshot(); let mut syntax = SyntaxMap::new(&text).snapshot(); if let Some(language) = language.clone() { let language_registry = language_registry.clone(); syntax.reparse(&text, language_registry, language); } - let tree_sitter_data = TreeSitterData::new(text.clone()); + let tree_sitter_data = TreeSitterData::new(&text); BufferSnapshot { text, syntax, @@ -1198,10 +1198,10 @@ impl Buffer { buffer_id, Default::default(), Rope::new(), - ) - .snapshot(); + ); + let text = text.into_snapshot(); let syntax = SyntaxMap::new(&text).snapshot(); - let tree_sitter_data = TreeSitterData::new(text.clone()); + let tree_sitter_data = TreeSitterData::new(&text); BufferSnapshot { text, syntax, @@ -1226,12 +1226,12 @@ impl Buffer { let buffer_id = entity_id.as_non_zero_u64().into(); let text = TextBuffer::new_normalized(ReplicaId::LOCAL, buffer_id, Default::default(), text) - .snapshot(); + .into_snapshot(); let mut syntax = SyntaxMap::new(&text).snapshot(); if let Some(language) = language.clone() { syntax.reparse(&text, language_registry, language); } - let tree_sitter_data = TreeSitterData::new(text.clone()); + let tree_sitter_data = TreeSitterData::new(&text); BufferSnapshot { text, syntax, @@ -1249,18 +1249,21 @@ impl Buffer { /// cheap, and allows reading from the buffer on a background thread. pub fn snapshot(&self) -> BufferSnapshot { let text = self.text.snapshot(); - let mut syntax_map = self.syntax_map.lock(); - syntax_map.interpolate(&text); - let syntax = syntax_map.snapshot(); + + let syntax = { + let mut syntax_map = self.syntax_map.lock(); + syntax_map.interpolate(text); + syntax_map.snapshot() + }; let tree_sitter_data = if self.text.version() != *self.tree_sitter_data.version() { - Arc::new(TreeSitterData::new(text.clone())) + Arc::new(TreeSitterData::new(text)) } else { self.tree_sitter_data.clone() }; BufferSnapshot { - text, + text: text.clone(), syntax, tree_sitter_data, file: self.file.clone(), @@ -1304,7 +1307,7 @@ impl Buffer { ) -> Task { let registry = self.language_registry(); let language = self.language().cloned(); - let old_snapshot = self.text.snapshot(); + let old_snapshot = self.text.snapshot().clone(); let mut branch_buffer = self.text.branch(); let mut syntax_snapshot = self.syntax_map.lock().snapshot(); cx.background_spawn(async move { @@ -1323,7 +1326,7 @@ impl Buffer { } EditPreview { old_snapshot, - applied_edits_snapshot: branch_buffer.snapshot(), + applied_edits_snapshot: branch_buffer.into_snapshot(), syntax_snapshot, } }) @@ -1416,8 +1419,7 @@ impl Buffer { } } - #[cfg(test)] - pub(crate) fn as_text_snapshot(&self) -> &text::BufferSnapshot { + pub fn as_text_snapshot(&self) -> &text::BufferSnapshot { &self.text } @@ -1425,7 +1427,8 @@ impl Buffer { /// language-related state like the syntax tree or diagnostics. #[ztracing::instrument(skip_all)] pub fn text_snapshot(&self) -> text::BufferSnapshot { - self.text.snapshot() + // todo lw + self.text.snapshot().clone() } /// The file associated with the buffer, if any. @@ -1781,12 +1784,15 @@ impl Buffer { self.sync_parse_timeout = timeout; } - fn invalidate_tree_sitter_data(&mut self, snapshot: text::BufferSnapshot) { - match Arc::get_mut(&mut self.tree_sitter_data) { + fn invalidate_tree_sitter_data( + tree_sitter_data: &mut Arc, + snapshot: &text::BufferSnapshot, + ) { + match Arc::get_mut(tree_sitter_data) { Some(tree_sitter_data) => tree_sitter_data.clear(snapshot), None => { - let tree_sitter_data = TreeSitterData::new(snapshot); - self.tree_sitter_data = Arc::new(tree_sitter_data) + let new_tree_sitter_data = TreeSitterData::new(snapshot); + *tree_sitter_data = Arc::new(new_tree_sitter_data) } } } @@ -1817,7 +1823,7 @@ impl Buffer { #[ztracing::instrument(skip_all)] pub fn reparse(&mut self, cx: &mut Context, may_block: bool) { if self.text.version() != *self.tree_sitter_data.version() { - self.invalidate_tree_sitter_data(self.text.snapshot()); + Self::invalidate_tree_sitter_data(&mut self.tree_sitter_data, self.text.snapshot()); } if self.reparse.is_some() { return; @@ -1898,7 +1904,7 @@ impl Buffer { self.was_changed(); self.request_autoindent(cx, block_budget); self.parse_status.0.send(ParseStatus::Idle).unwrap(); - self.invalidate_tree_sitter_data(self.text.snapshot()); + Self::invalidate_tree_sitter_data(&mut self.tree_sitter_data, &self.text.snapshot()); cx.emit(BufferEvent::Reparsed); cx.notify(); } diff --git a/crates/language/src/buffer/row_chunk.rs b/crates/language/src/buffer/row_chunk.rs index 0f3c0b5afb1cc1a2d60a2a568fe00403733ef5c6..c0528544c15c108ffa8fe97d45f174a40da5b7ad 100644 --- a/crates/language/src/buffer/row_chunk.rs +++ b/crates/language/src/buffer/row_chunk.rs @@ -31,7 +31,7 @@ impl std::fmt::Debug for RowChunks { } impl RowChunks { - pub fn new(snapshot: text::BufferSnapshot, max_rows_per_chunk: u32) -> Self { + pub fn new(snapshot: &text::BufferSnapshot, max_rows_per_chunk: u32) -> Self { let buffer_point_range = (0..snapshot.len()).to_point(&snapshot); let last_row = buffer_point_range.end.row; let chunks = (buffer_point_range.start.row..=last_row) diff --git a/crates/language/src/syntax_map/syntax_map_tests.rs b/crates/language/src/syntax_map/syntax_map_tests.rs index f5197c9e25e94152e6447278cc71d910a5c4dd52..2ee37f19df022a8c3fe1a27924c1542424690b22 100644 --- a/crates/language/src/syntax_map/syntax_map_tests.rs +++ b/crates/language/src/syntax_map/syntax_map_tests.rs @@ -1047,7 +1047,7 @@ fn test_random_edits( log::info!("initial text:\n{}", buffer.text()); for _ in 0..operations { - let prev_buffer = buffer.snapshot(); + let prev_buffer = buffer.snapshot().clone(); let prev_syntax_map = syntax_map.snapshot(); buffer.randomly_edit(&mut rng, 3); diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 18831e2fc789ebcd1aea76f9fdbf5aa4b640b9f3..aa2a1da870e5ea7e7ea9b9841bea147a5db0df64 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -678,7 +678,7 @@ impl std::hash::Hash for DiffTransformHunkInfo { #[derive(Clone)] pub struct ExcerptInfo { pub id: ExcerptId, - pub buffer: BufferSnapshot, + pub buffer: Arc, pub buffer_id: BufferId, pub range: ExcerptRange, pub end_row: MultiBufferRow, @@ -739,7 +739,7 @@ struct Excerpt { /// The buffer being excerpted buffer_id: BufferId, /// A snapshot of the buffer being excerpted - buffer: BufferSnapshot, + buffer: Arc, /// The range of the buffer to be shown in the excerpt range: ExcerptRange, /// The last row in the excerpted slice of the buffer @@ -1849,6 +1849,7 @@ impl MultiBuffer { }; let mut excerpts = Vec::new(); + let buffer_snapshot = Arc::new(buffer_snapshot); while let Some((id, range)) = ranges.next() { let locator = Locator::between(&prev_locator, &next_locator); if let Err(ix) = buffer_state.excerpts.binary_search(&locator) { @@ -3013,6 +3014,21 @@ impl MultiBuffer { *has_deleted_file = false; *has_conflict = false; + if !diffs.is_empty() { + let mut diffs_to_add = Vec::new(); + for (id, diff) in diffs { + if diff.is_inverted || buffer_diff.get(id).is_none() { + if diffs_to_add.capacity() == 0 { + // we'd rather overallocate than reallocate as buffer diffs are quite big + // meaning re-allocations will be fairly expensive + diffs_to_add.reserve(diffs.len()); + } + diffs_to_add.push((*id, diff.snapshot(cx))); + } + } + buffer_diff.extend(diffs_to_add); + } + let mut excerpts_to_edit = Vec::new(); let mut non_text_state_updated = false; let mut edited = false; @@ -3052,19 +3068,7 @@ impl MultiBuffer { *non_text_state_update_count += 1; } - let diffs_to_add = diffs - .iter() - .filter_map(|(id, diff)| { - if diff.is_inverted || buffer_diff.get(id).is_none() { - Some((*id, diff.snapshot(cx))) - } else { - None - } - }) - .collect::>(); - buffer_diff.extend(diffs_to_add); - - excerpts_to_edit.sort_unstable_by_key(|(locator, _, _)| *locator); + excerpts_to_edit.sort_unstable_by_key(|&(locator, _, _)| locator); let mut edits = Vec::new(); let mut new_excerpts = SumTree::default(); @@ -3075,7 +3079,6 @@ impl MultiBuffer { let old_excerpt = cursor.item().unwrap(); let buffer = buffer.read(cx); let buffer_id = buffer.remote_id(); - let mut new_excerpt; if buffer_edited { edits.extend( @@ -3103,13 +3106,13 @@ impl MultiBuffer { old_excerpt.id, locator.clone(), buffer_id, - buffer.snapshot(), + Arc::new(buffer.snapshot()), old_excerpt.range.clone(), old_excerpt.has_trailing_newline, ); } else { new_excerpt = old_excerpt.clone(); - new_excerpt.buffer = buffer.snapshot(); + new_excerpt.buffer = Arc::new(buffer.snapshot()); } new_excerpts.push(new_excerpt, ()); @@ -3981,7 +3984,7 @@ impl MultiBufferSnapshot { return None; } let excerpt = region.excerpt; - cursor.next_excerpt(); + cursor.next_excerpt_forwards(); Some(excerpt) }) } @@ -4308,7 +4311,7 @@ impl MultiBufferSnapshot { { return None; } - cursor.next_excerpt(); + cursor.next_excerpt_forwards(); } } }) @@ -4477,7 +4480,7 @@ impl MultiBufferSnapshot { self.excerpts .iter() .next() - .map(|e| (&e.id, e.buffer_id, &e.buffer)) + .map(|e| (&e.id, e.buffer_id, &*e.buffer)) } else { None } @@ -5699,7 +5702,7 @@ impl MultiBufferSnapshot { ) -> impl Iterator)> { self.excerpts .iter() - .map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone())) + .map(|excerpt| (excerpt.id, &*excerpt.buffer, excerpt.range.clone())) } fn cursor<'a, MBD, BD>(&'a self) -> MultiBufferCursor<'a, MBD, BD> @@ -5778,16 +5781,18 @@ impl MultiBufferSnapshot { }); if cursor - .region() - .is_some_and(|region| bounds.contains(®ion.range.start.key)) + .fetch_excerpt_with_range() + .is_some_and(|(_, range)| bounds.contains(&range.start.key)) { cursor.prev_excerpt(); } else { cursor.seek_to_start_of_current_excerpt(); } - let mut prev_region = cursor.region().cloned(); + let mut prev_region = cursor + .fetch_excerpt_with_range() + .map(|(excerpt, _)| excerpt); - cursor.next_excerpt(); + cursor.next_excerpt_forwards(); iter::from_fn(move || { loop { @@ -5795,34 +5800,34 @@ impl MultiBufferSnapshot { return None; } - let next_region = cursor.region()?.clone(); - cursor.next_excerpt(); - if !bounds.contains(&next_region.range.start.key) { - prev_region = Some(next_region); + let (next_excerpt, next_range) = cursor.fetch_excerpt_with_range()?; + cursor.next_excerpt_forwards(); + if !bounds.contains(&next_range.start.key) { + prev_region = Some(next_excerpt); continue; } - let next_region_start = next_region.range.start.value.unwrap(); - let next_region_end = if let Some(region) = cursor.region() { - region.range.start.value.unwrap() + let next_region_start = next_range.start.value.unwrap(); + let next_region_end = if let Some((_, range)) = cursor.fetch_excerpt_with_range() { + range.start.value.unwrap() } else { self.max_point() }; let prev = prev_region.as_ref().map(|region| ExcerptInfo { - id: region.excerpt.id, - buffer: region.excerpt.buffer.clone(), - buffer_id: region.excerpt.buffer_id, - range: region.excerpt.range.clone(), + id: region.id, + buffer: region.buffer.clone(), + buffer_id: region.buffer_id, + range: region.range.clone(), end_row: MultiBufferRow(next_region_start.row), }); let next = ExcerptInfo { - id: next_region.excerpt.id, - buffer: next_region.excerpt.buffer.clone(), - buffer_id: next_region.excerpt.buffer_id, - range: next_region.excerpt.range.clone(), - end_row: if next_region.excerpt.has_trailing_newline { + id: next_excerpt.id, + buffer: next_excerpt.buffer.clone(), + buffer_id: next_excerpt.buffer_id, + range: next_excerpt.range.clone(), + end_row: if next_excerpt.has_trailing_newline { MultiBufferRow(next_region_end.row - 1) } else { MultiBufferRow(next_region_end.row) @@ -5831,7 +5836,7 @@ impl MultiBufferSnapshot { let row = MultiBufferRow(next_region_start.row); - prev_region = Some(next_region); + prev_region = Some(next_excerpt); return Some(ExcerptBoundary { row, prev, next }); } @@ -6048,7 +6053,7 @@ impl MultiBufferSnapshot { cursor.next(); Some(line_indents.map(move |(buffer_row, indent)| { let row = region_row + (buffer_row - region_buffer_row); - (MultiBufferRow(row), indent, region_buffer) + (MultiBufferRow(row), indent, region_buffer.as_ref()) })) }) .flatten() @@ -6092,7 +6097,7 @@ impl MultiBufferSnapshot { cursor.prev(); Some(line_indents.map(move |(buffer_row, indent)| { let row = region_row + (buffer_row - region_buffer_row); - (MultiBufferRow(row), indent, region_buffer) + (MultiBufferRow(row), indent, region_buffer.as_ref()) })) }) .flatten() @@ -7029,8 +7034,26 @@ where fn seek_to_start_of_current_excerpt(&mut self) { self.cached_region.take(); - self.diff_transforms.seek(self.excerpts.start(), Bias::Left); - if self.diff_transforms.end().excerpt_dimension == *self.excerpts.start() + + if self.diff_transforms.seek(self.excerpts.start(), Bias::Left) + && self.diff_transforms.start().excerpt_dimension < *self.excerpts.start() + && self.diff_transforms.next_item().is_some() + { + self.diff_transforms.next(); + } + } + + fn next_excerpt_forwards(&mut self) { + self.excerpts.next(); + self.seek_to_start_of_current_excerpt_forward(); + } + + fn seek_to_start_of_current_excerpt_forward(&mut self) { + self.cached_region.take(); + + if self + .diff_transforms + .seek_forward(self.excerpts.start(), Bias::Left) && self.diff_transforms.start().excerpt_dimension < *self.excerpts.start() && self.diff_transforms.next_item().is_some() { @@ -7191,10 +7214,10 @@ where let mut end; let mut buffer_end; let has_trailing_newline; - if self.diff_transforms.end().excerpt_dimension < self.excerpts.end() { - let overshoot = - self.diff_transforms.end().excerpt_dimension - *self.excerpts.start(); - end = self.diff_transforms.end().output_dimension.0; + let transform_end = self.diff_transforms.end(); + if transform_end.excerpt_dimension < self.excerpts.end() { + let overshoot = transform_end.excerpt_dimension - *self.excerpts.start(); + end = transform_end.output_dimension.0; buffer_end = buffer_context_start; buffer_end += overshoot; has_trailing_newline = false; @@ -7228,6 +7251,38 @@ where } } + fn fetch_excerpt_with_range(&self) -> Option<(&'a Excerpt, Range)> { + let excerpt = self.excerpts.item()?; + match self.diff_transforms.item()? { + &DiffTransform::DeletedHunk { .. } => { + let start = self.diff_transforms.start().output_dimension.0; + let end = self.diff_transforms.end().output_dimension.0; + Some((excerpt, start..end)) + } + DiffTransform::BufferContent { .. } => { + let mut start = self.diff_transforms.start().output_dimension.0; + if self.diff_transforms.start().excerpt_dimension < *self.excerpts.start() { + let overshoot = + *self.excerpts.start() - self.diff_transforms.start().excerpt_dimension; + start += overshoot; + } + + let mut end; + let transform_end = self.diff_transforms.end(); + if transform_end.excerpt_dimension < self.excerpts.end() { + end = transform_end.output_dimension.0; + } else { + let overshoot = + self.excerpts.end() - self.diff_transforms.start().excerpt_dimension; + end = self.diff_transforms.start().output_dimension.0; + end += overshoot; + }; + + Some((excerpt, start..end)) + } + } + } + fn excerpt(&self) -> Option<&'a Excerpt> { self.excerpts.item() } @@ -7238,7 +7293,7 @@ impl Excerpt { id: ExcerptId, locator: Locator, buffer_id: BufferId, - buffer: BufferSnapshot, + buffer: Arc, range: ExcerptRange, has_trailing_newline: bool, ) -> Self { diff --git a/crates/project/src/lsp_store/inlay_hint_cache.rs b/crates/project/src/lsp_store/inlay_hint_cache.rs index 0cd9698e74bbfa4c53ad58569ebf59db99b5decd..57d1c0509f55415cc7099cc0082bb55a45ddfe57 100644 --- a/crates/project/src/lsp_store/inlay_hint_cache.rs +++ b/crates/project/src/lsp_store/inlay_hint_cache.rs @@ -78,7 +78,7 @@ const MAX_ROWS_IN_A_CHUNK: u32 = 50; impl BufferInlayHints { pub fn new(buffer: &Entity, cx: &mut App) -> Self { - let chunks = RowChunks::new(buffer.read(cx).text_snapshot(), MAX_ROWS_IN_A_CHUNK); + let chunks = RowChunks::new(buffer.read(cx).as_text_snapshot(), MAX_ROWS_IN_A_CHUNK); Self { hints_by_chunks: vec![None; chunks.len()], diff --git a/crates/sum_tree/src/tree_map.rs b/crates/sum_tree/src/tree_map.rs index 9cdbb3c3e97208e4fc70230e1ccb797b301e1e0d..e58f7a65dd5d13ca67d4433bd25118ffb55d1169 100644 --- a/crates/sum_tree/src/tree_map.rs +++ b/crates/sum_tree/src/tree_map.rs @@ -83,9 +83,6 @@ impl TreeMap { .into_iter() .map(|(key, value)| Edit::Insert(MapEntry { key, value })) .collect(); - if edits.is_empty() { - return; - } self.0.edit(edits, ()); } diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index 7d5dcd654ed5399c16628eddc366516670f75ab9..506116e7df768bfecd1ab2866108e69147270eb6 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -104,16 +104,16 @@ impl From for u64 { #[derive(Clone)] pub struct BufferSnapshot { - replica_id: ReplicaId, - remote_id: BufferId, visible_text: Rope, deleted_text: Rope, - line_ending: LineEnding, - undo_map: UndoMap, fragments: SumTree, insertions: SumTree, insertion_slices: TreeSet, + undo_map: UndoMap, pub version: clock::Global, + remote_id: BufferId, + replica_id: ReplicaId, + line_ending: LineEnding, } #[derive(Clone, Debug)] @@ -780,8 +780,12 @@ impl Buffer { self.version.clone() } - pub fn snapshot(&self) -> BufferSnapshot { - self.snapshot.clone() + pub fn snapshot(&self) -> &BufferSnapshot { + &self.snapshot + } + + pub fn into_snapshot(self) -> BufferSnapshot { + self.snapshot } pub fn branch(&self) -> Self {