diff --git a/crates/multi_buffer/src/anchor.rs b/crates/multi_buffer/src/anchor.rs index 4b23f344c9d27412daf6a630e04df9a2e67ff726..c68233b1fd3e6af626cc151cf19f8a41f63d0648 100644 --- a/crates/multi_buffer/src/anchor.rs +++ b/crates/multi_buffer/src/anchor.rs @@ -4,7 +4,7 @@ use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint}; use language::Point; use std::{ cmp::Ordering, - ops::{AddAssign, Range, Sub}, + ops::{Add, AddAssign, Range, Sub}, }; use sum_tree::Bias; @@ -185,7 +185,9 @@ impl Anchor { D: MultiBufferDimension + Ord + Sub - + AddAssign, + + Sub + + AddAssign + + Add, D::TextDimension: Sub + Ord, { snapshot.summary_for_anchor(self) diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 31fc72ad2bbd6e432f3ad016c2c0ba0f3fec4dd3..b92aad010c7cdf5dc83b5145554ce3648a988a14 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -41,7 +41,7 @@ use std::{ io, iter::{self, FromIterator}, mem, - ops::{self, AddAssign, ControlFlow, Range, RangeBounds, Sub, SubAssign}, + ops::{self, Add, AddAssign, ControlFlow, Range, RangeBounds, Sub, SubAssign}, rc::Rc, str, sync::{Arc, OnceLock}, @@ -380,6 +380,14 @@ impl ops::Add for MultiBufferOffsetUtf16 { } } +impl ops::Add for MultiBufferOffsetUtf16 { + type Output = Self; + + fn add(self, rhs: OffsetUtf16) -> Self::Output { + MultiBufferOffsetUtf16(self.0 + rhs) + } +} + impl AddAssign for MultiBufferOffsetUtf16 { fn add_assign(&mut self, rhs: OffsetUtf16) { self.0 += rhs; @@ -400,6 +408,14 @@ impl Sub for MultiBufferOffsetUtf16 { } } +impl Sub for MultiBufferOffsetUtf16 { + type Output = MultiBufferOffsetUtf16; + + fn sub(self, other: OffsetUtf16) -> Self::Output { + MultiBufferOffsetUtf16(self.0 - other) + } +} + #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] pub struct BufferOffsetUtf16(pub OffsetUtf16); @@ -831,6 +847,23 @@ impl From for MBTextSummary { } } } + +impl From for TextSummary { + fn from(summary: MBTextSummary) -> Self { + TextSummary { + len: summary.len.0, + chars: summary.chars, + len_utf16: summary.len_utf16, + lines: summary.lines, + first_line_chars: summary.first_line_chars, + last_line_chars: summary.last_line_chars, + last_line_len_utf16: summary.last_line_len_utf16, + longest_row: summary.longest_row, + longest_row_chars: summary.longest_row_chars, + } + } +} + impl From<&str> for MBTextSummary { fn from(text: &str) -> Self { MBTextSummary::from(TextSummary::from(text)) @@ -5063,10 +5096,100 @@ impl MultiBufferSnapshot { MBD: MultiBufferDimension + Ord + Sub - + AddAssign, + + Sub + + AddAssign + + Add, MBD::TextDimension: Sub + Ord, { - self.summaries_for_anchors([anchor])[0] + let excerpt_id = self.latest_excerpt_id(anchor.excerpt_id); + let locator = self.excerpt_locator_for_id(excerpt_id); + let (start, _, mut item) = self + .excerpts + .find::((), locator, Bias::Left); + let mut start = MBD::from_summary(&start.text); + if item.is_none() && excerpt_id == ExcerptId::max() { + item = self.excerpts.last(); + if let Some(last_summary) = self.excerpts.last_summary() { + start = start - ::from_text_summary(&last_summary.text.into()); + } + } + + if self.diff_transforms.is_empty() { + let excerpt_start_position = ExcerptDimension(start); + if let Some(excerpt) = item { + if excerpt.id != excerpt_id && excerpt_id != ExcerptId::max() { + return excerpt_start_position.0; + } + let excerpt_buffer_start = excerpt + .range + .context + .start + .summary::(&excerpt.buffer); + let excerpt_buffer_end = excerpt + .range + .context + .end + .summary::(&excerpt.buffer); + let buffer_summary = anchor + .text_anchor + .summary::(&excerpt.buffer); + let summary = cmp::min(excerpt_buffer_end, buffer_summary); + let mut position = excerpt_start_position; + if summary > excerpt_buffer_start { + position += summary - excerpt_buffer_start; + } + + position.0 + } else { + excerpt_start_position.0 + } + } else { + let mut diff_transforms_cursor = self + .diff_transforms + .cursor::, OutputDimension>>(()); + diff_transforms_cursor.next(); + + let excerpt_start_position = ExcerptDimension(start); + if let Some(excerpt) = item { + if excerpt.id != excerpt_id && excerpt_id != ExcerptId::max() { + return self.resolve_summary_for_anchor( + &Anchor::min(), + excerpt_start_position, + &mut diff_transforms_cursor, + ); + } + let excerpt_buffer_start = excerpt + .range + .context + .start + .summary::(&excerpt.buffer); + let excerpt_buffer_end = excerpt + .range + .context + .end + .summary::(&excerpt.buffer); + let buffer_summary = anchor + .text_anchor + .summary::(&excerpt.buffer); + let summary = cmp::min(excerpt_buffer_end, buffer_summary); + let mut position = excerpt_start_position; + if summary > excerpt_buffer_start { + position += summary - excerpt_buffer_start; + } + + if diff_transforms_cursor.start().0 < position { + diff_transforms_cursor.seek_forward(&position, Bias::Left); + } + self.resolve_summary_for_anchor(&anchor, position, &mut diff_transforms_cursor) + } else { + diff_transforms_cursor.seek_forward(&excerpt_start_position, Bias::Left); + self.resolve_summary_for_anchor( + &Anchor::max(), + excerpt_start_position, + &mut diff_transforms_cursor, + ) + } + } } fn resolve_summary_for_anchor( @@ -7439,7 +7562,13 @@ impl sum_tree::ContextLessSummary for ExcerptSummary { } fn add_summary(&mut self, summary: &Self) { - debug_assert!(summary.excerpt_locator > self.excerpt_locator); + debug_assert!( + summary.excerpt_locator > self.excerpt_locator + || self.excerpt_locator == Locator::min(), + "Excerpt locators must be in ascending order: {:?} > {:?}", + summary.excerpt_locator, + self.excerpt_locator + ); self.excerpt_locator = summary.excerpt_locator.clone(); self.text += summary.text; self.widest_line_number = cmp::max(self.widest_line_number, summary.widest_line_number); diff --git a/crates/sum_tree/src/sum_tree.rs b/crates/sum_tree/src/sum_tree.rs index 6992e0b0f36a7aa1a87a8ce9a31de1ff294e7322..fa83dd937489f0c52e6c02b83b52112b5ff52ec1 100644 --- a/crates/sum_tree/src/sum_tree.rs +++ b/crates/sum_tree/src/sum_tree.rs @@ -613,6 +613,10 @@ impl SumTree { self.rightmost_leaf().0.items().last() } + pub fn last_summary(&self) -> Option<&T::Summary> { + self.rightmost_leaf().0.child_summaries().last() + } + pub fn update_last( &mut self, f: impl FnOnce(&mut T),