Restructure git diff state management to allow viewing buffers with different diff bases (#21258)
This is a pure refactor of our Git diff state management. Buffers are no longer are associated with one single diff (the unstaged changes). Instead, there is an explicit project API for retrieving a buffer's unstaged changes, and the `Editor` view layer is responsible for choosing what diff to associate with a buffer. The reason for this change is that we'll soon want to add multiple "git diff views" to Zed, one of which will show the *uncommitted* changes for a buffer. But that view will need to co-exist with other views of the same buffer, which may want to show the unstaged changes. ### Todo * [x] Get git gutter and git hunks working with new structure * [x] Update editor tests to use new APIs * [x] Update buffer tests * [x] Restructure remoting/collab protocol * [x] Update assertions about staged text in `random_project_collaboration_tests` * [x] Move buffer tests for git diff management to a new spot, using the new APIs Release Notes: - N/A --------- Co-authored-by: Richard <richard@zed.dev> Co-authored-by: Cole <cole@zed.dev> Co-authored-by: Conrad <conrad@zed.dev>
This commit is contained in:
parent
31796171de
commit
a2115e7242
29 changed files with 1832 additions and 1651 deletions
|
@ -95,10 +95,7 @@ pub enum Event {
|
|||
},
|
||||
Reloaded,
|
||||
ReloadNeeded,
|
||||
DiffBaseChanged,
|
||||
DiffUpdated {
|
||||
buffer: Model<Buffer>,
|
||||
},
|
||||
|
||||
LanguageChanged(BufferId),
|
||||
CapabilityChanged,
|
||||
Reparsed(BufferId),
|
||||
|
@ -257,6 +254,7 @@ struct Excerpt {
|
|||
pub struct MultiBufferExcerpt<'a> {
|
||||
excerpt: &'a Excerpt,
|
||||
excerpt_offset: usize,
|
||||
excerpt_position: Point,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -1824,8 +1822,6 @@ impl MultiBuffer {
|
|||
language::BufferEvent::FileHandleChanged => Event::FileHandleChanged,
|
||||
language::BufferEvent::Reloaded => Event::Reloaded,
|
||||
language::BufferEvent::ReloadNeeded => Event::ReloadNeeded,
|
||||
language::BufferEvent::DiffBaseChanged => Event::DiffBaseChanged,
|
||||
language::BufferEvent::DiffUpdated => Event::DiffUpdated { buffer },
|
||||
language::BufferEvent::LanguageChanged => {
|
||||
Event::LanguageChanged(buffer.read(cx).remote_id())
|
||||
}
|
||||
|
@ -3424,47 +3420,86 @@ impl MultiBufferSnapshot {
|
|||
.map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone()))
|
||||
}
|
||||
|
||||
fn excerpts_for_range<T: ToOffset>(
|
||||
pub fn all_excerpts(&self) -> impl Iterator<Item = MultiBufferExcerpt> {
|
||||
let mut cursor = self.excerpts.cursor::<(usize, Point)>(&());
|
||||
cursor.next(&());
|
||||
std::iter::from_fn(move || {
|
||||
let excerpt = cursor.item()?;
|
||||
let excerpt = MultiBufferExcerpt::new(excerpt, *cursor.start());
|
||||
cursor.next(&());
|
||||
Some(excerpt)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn excerpts_for_range<T: ToOffset>(
|
||||
&self,
|
||||
range: Range<T>,
|
||||
) -> impl Iterator<Item = (&Excerpt, usize)> + '_ {
|
||||
) -> impl Iterator<Item = MultiBufferExcerpt> + '_ {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
|
||||
let mut cursor = self.excerpts.cursor::<usize>(&());
|
||||
let mut cursor = self.excerpts.cursor::<(usize, Point)>(&());
|
||||
cursor.seek(&range.start, Bias::Right, &());
|
||||
cursor.prev(&());
|
||||
|
||||
iter::from_fn(move || {
|
||||
cursor.next(&());
|
||||
if cursor.start() < &range.end {
|
||||
cursor.item().map(|item| (item, *cursor.start()))
|
||||
if cursor.start().0 < range.end {
|
||||
cursor
|
||||
.item()
|
||||
.map(|item| MultiBufferExcerpt::new(item, *cursor.start()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn excerpts_for_range_rev<T: ToOffset>(
|
||||
&self,
|
||||
range: Range<T>,
|
||||
) -> impl Iterator<Item = MultiBufferExcerpt> + '_ {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
|
||||
let mut cursor = self.excerpts.cursor::<(usize, Point)>(&());
|
||||
cursor.seek(&range.end, Bias::Left, &());
|
||||
if cursor.item().is_none() {
|
||||
cursor.prev(&());
|
||||
}
|
||||
|
||||
std::iter::from_fn(move || {
|
||||
let excerpt = cursor.item()?;
|
||||
let excerpt = MultiBufferExcerpt::new(excerpt, *cursor.start());
|
||||
cursor.prev(&());
|
||||
Some(excerpt)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn excerpt_before(&self, id: ExcerptId) -> Option<MultiBufferExcerpt<'_>> {
|
||||
let start_locator = self.excerpt_locator_for_id(id);
|
||||
let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
|
||||
cursor.seek(&Some(start_locator), Bias::Left, &());
|
||||
let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
|
||||
cursor.seek(start_locator, Bias::Left, &());
|
||||
cursor.prev(&());
|
||||
let excerpt = cursor.item()?;
|
||||
let excerpt_offset = cursor.start().text.len;
|
||||
let excerpt_position = cursor.start().text.lines;
|
||||
Some(MultiBufferExcerpt {
|
||||
excerpt,
|
||||
excerpt_offset: 0,
|
||||
excerpt_offset,
|
||||
excerpt_position,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn excerpt_after(&self, id: ExcerptId) -> Option<MultiBufferExcerpt<'_>> {
|
||||
let start_locator = self.excerpt_locator_for_id(id);
|
||||
let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
|
||||
cursor.seek(&Some(start_locator), Bias::Left, &());
|
||||
let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
|
||||
cursor.seek(start_locator, Bias::Left, &());
|
||||
cursor.next(&());
|
||||
let excerpt = cursor.item()?;
|
||||
let excerpt_offset = cursor.start().text.len;
|
||||
let excerpt_position = cursor.start().text.lines;
|
||||
Some(MultiBufferExcerpt {
|
||||
excerpt,
|
||||
excerpt_offset: 0,
|
||||
excerpt_offset,
|
||||
excerpt_position,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -3647,22 +3682,12 @@ impl MultiBufferSnapshot {
|
|||
) -> impl Iterator<Item = Range<usize>> + 'a {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
self.excerpts_for_range(range.clone())
|
||||
.filter(move |&(excerpt, _)| redaction_enabled(excerpt.buffer.file()))
|
||||
.flat_map(move |(excerpt, excerpt_offset)| {
|
||||
let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
|
||||
|
||||
.filter(move |excerpt| redaction_enabled(excerpt.buffer().file()))
|
||||
.flat_map(move |excerpt| {
|
||||
excerpt
|
||||
.buffer
|
||||
.redacted_ranges(excerpt.range.context.clone())
|
||||
.map(move |mut redacted_range| {
|
||||
// Re-base onto the excerpts coordinates in the multibuffer
|
||||
redacted_range.start = excerpt_offset
|
||||
+ redacted_range.start.saturating_sub(excerpt_buffer_start);
|
||||
redacted_range.end = excerpt_offset
|
||||
+ redacted_range.end.saturating_sub(excerpt_buffer_start);
|
||||
|
||||
redacted_range
|
||||
})
|
||||
.buffer()
|
||||
.redacted_ranges(excerpt.buffer_range().clone())
|
||||
.map(move |redacted_range| excerpt.map_range_from_buffer(redacted_range))
|
||||
.skip_while(move |redacted_range| redacted_range.end < range.start)
|
||||
.take_while(move |redacted_range| redacted_range.start < range.end)
|
||||
})
|
||||
|
@ -3674,12 +3699,13 @@ impl MultiBufferSnapshot {
|
|||
) -> impl Iterator<Item = language::RunnableRange> + '_ {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
self.excerpts_for_range(range.clone())
|
||||
.flat_map(move |(excerpt, excerpt_offset)| {
|
||||
let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
|
||||
.flat_map(move |excerpt| {
|
||||
let excerpt_buffer_start =
|
||||
excerpt.buffer_range().start.to_offset(&excerpt.buffer());
|
||||
|
||||
excerpt
|
||||
.buffer
|
||||
.runnable_ranges(excerpt.range.context.clone())
|
||||
.buffer()
|
||||
.runnable_ranges(excerpt.buffer_range())
|
||||
.filter_map(move |mut runnable| {
|
||||
// Re-base onto the excerpts coordinates in the multibuffer
|
||||
//
|
||||
|
@ -3688,15 +3714,14 @@ impl MultiBufferSnapshot {
|
|||
if runnable.run_range.start < excerpt_buffer_start {
|
||||
return None;
|
||||
}
|
||||
if language::ToPoint::to_point(&runnable.run_range.end, &excerpt.buffer).row
|
||||
> excerpt.max_buffer_row
|
||||
if language::ToPoint::to_point(&runnable.run_range.end, &excerpt.buffer())
|
||||
.row
|
||||
> excerpt.max_buffer_row()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
runnable.run_range.start =
|
||||
excerpt_offset + runnable.run_range.start - excerpt_buffer_start;
|
||||
runnable.run_range.end =
|
||||
excerpt_offset + runnable.run_range.end - excerpt_buffer_start;
|
||||
runnable.run_range = excerpt.map_range_from_buffer(runnable.run_range);
|
||||
|
||||
Some(runnable)
|
||||
})
|
||||
.skip_while(move |runnable| runnable.run_range.end < range.start)
|
||||
|
@ -3730,15 +3755,15 @@ impl MultiBufferSnapshot {
|
|||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
|
||||
self.excerpts_for_range(range.clone())
|
||||
.flat_map(move |(excerpt, excerpt_offset)| {
|
||||
.flat_map(move |excerpt| {
|
||||
let excerpt_buffer_start_row =
|
||||
excerpt.range.context.start.to_point(&excerpt.buffer).row;
|
||||
let excerpt_offset_row = crate::ToPoint::to_point(&excerpt_offset, self).row;
|
||||
excerpt.buffer_range().start.to_point(&excerpt.buffer()).row;
|
||||
let excerpt_offset_row = excerpt.start_point().row;
|
||||
|
||||
excerpt
|
||||
.buffer
|
||||
.buffer()
|
||||
.indent_guides_in_range(
|
||||
excerpt.range.context.clone(),
|
||||
excerpt.buffer_range(),
|
||||
ignore_disabled_for_language,
|
||||
cx,
|
||||
)
|
||||
|
@ -3856,151 +3881,6 @@ impl MultiBufferSnapshot {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn has_git_diffs(&self) -> bool {
|
||||
for excerpt in self.excerpts.iter() {
|
||||
if excerpt.buffer.has_git_diff() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn git_diff_hunks_in_range_rev(
|
||||
&self,
|
||||
row_range: Range<MultiBufferRow>,
|
||||
) -> impl Iterator<Item = MultiBufferDiffHunk> + '_ {
|
||||
let mut cursor = self.excerpts.cursor::<Point>(&());
|
||||
|
||||
cursor.seek(&Point::new(row_range.end.0, 0), Bias::Left, &());
|
||||
if cursor.item().is_none() {
|
||||
cursor.prev(&());
|
||||
}
|
||||
|
||||
std::iter::from_fn(move || {
|
||||
let excerpt = cursor.item()?;
|
||||
let multibuffer_start = *cursor.start();
|
||||
let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
|
||||
if multibuffer_start.row >= row_range.end.0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut buffer_start = excerpt.range.context.start;
|
||||
let mut buffer_end = excerpt.range.context.end;
|
||||
let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
|
||||
let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
|
||||
|
||||
if row_range.start.0 > multibuffer_start.row {
|
||||
let buffer_start_point =
|
||||
excerpt_start_point + Point::new(row_range.start.0 - multibuffer_start.row, 0);
|
||||
buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
|
||||
}
|
||||
|
||||
if row_range.end.0 < multibuffer_end.row {
|
||||
let buffer_end_point =
|
||||
excerpt_start_point + Point::new(row_range.end.0 - multibuffer_start.row, 0);
|
||||
buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
|
||||
}
|
||||
|
||||
let buffer_hunks = excerpt
|
||||
.buffer
|
||||
.git_diff_hunks_intersecting_range_rev(buffer_start..buffer_end)
|
||||
.map(move |hunk| {
|
||||
let start = multibuffer_start.row
|
||||
+ hunk.row_range.start.saturating_sub(excerpt_start_point.row);
|
||||
let end = multibuffer_start.row
|
||||
+ hunk
|
||||
.row_range
|
||||
.end
|
||||
.min(excerpt_end_point.row + 1)
|
||||
.saturating_sub(excerpt_start_point.row);
|
||||
|
||||
MultiBufferDiffHunk {
|
||||
row_range: MultiBufferRow(start)..MultiBufferRow(end),
|
||||
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
||||
buffer_range: hunk.buffer_range.clone(),
|
||||
buffer_id: excerpt.buffer_id,
|
||||
}
|
||||
});
|
||||
|
||||
cursor.prev(&());
|
||||
|
||||
Some(buffer_hunks)
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
pub fn git_diff_hunks_in_range(
|
||||
&self,
|
||||
row_range: Range<MultiBufferRow>,
|
||||
) -> impl Iterator<Item = MultiBufferDiffHunk> + '_ {
|
||||
let mut cursor = self.excerpts.cursor::<Point>(&());
|
||||
|
||||
cursor.seek(&Point::new(row_range.start.0, 0), Bias::Left, &());
|
||||
|
||||
std::iter::from_fn(move || {
|
||||
let excerpt = cursor.item()?;
|
||||
let multibuffer_start = *cursor.start();
|
||||
let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
|
||||
let mut buffer_start = excerpt.range.context.start;
|
||||
let mut buffer_end = excerpt.range.context.end;
|
||||
|
||||
let excerpt_rows = match multibuffer_start.row.cmp(&row_range.end.0) {
|
||||
cmp::Ordering::Less => {
|
||||
let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
|
||||
let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
|
||||
|
||||
if row_range.start.0 > multibuffer_start.row {
|
||||
let buffer_start_point = excerpt_start_point
|
||||
+ Point::new(row_range.start.0 - multibuffer_start.row, 0);
|
||||
buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
|
||||
}
|
||||
|
||||
if row_range.end.0 < multibuffer_end.row {
|
||||
let buffer_end_point = excerpt_start_point
|
||||
+ Point::new(row_range.end.0 - multibuffer_start.row, 0);
|
||||
buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
|
||||
}
|
||||
excerpt_start_point.row..excerpt_end_point.row
|
||||
}
|
||||
cmp::Ordering::Equal if row_range.end.0 == 0 => {
|
||||
buffer_end = buffer_start;
|
||||
0..0
|
||||
}
|
||||
cmp::Ordering::Greater | cmp::Ordering::Equal => return None,
|
||||
};
|
||||
|
||||
let buffer_hunks = excerpt
|
||||
.buffer
|
||||
.git_diff_hunks_intersecting_range(buffer_start..buffer_end)
|
||||
.map(move |hunk| {
|
||||
let buffer_range = if excerpt_rows.start == 0 && excerpt_rows.end == 0 {
|
||||
MultiBufferRow(0)..MultiBufferRow(1)
|
||||
} else {
|
||||
let start = multibuffer_start.row
|
||||
+ hunk.row_range.start.saturating_sub(excerpt_rows.start);
|
||||
let end = multibuffer_start.row
|
||||
+ hunk
|
||||
.row_range
|
||||
.end
|
||||
.min(excerpt_rows.end + 1)
|
||||
.saturating_sub(excerpt_rows.start);
|
||||
MultiBufferRow(start)..MultiBufferRow(end)
|
||||
};
|
||||
MultiBufferDiffHunk {
|
||||
row_range: buffer_range,
|
||||
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
||||
buffer_range: hunk.buffer_range.clone(),
|
||||
buffer_id: excerpt.buffer_id,
|
||||
}
|
||||
});
|
||||
|
||||
cursor.next(&());
|
||||
|
||||
Some(buffer_hunks)
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
let excerpt = self.excerpt_containing(range.clone())?;
|
||||
|
@ -4179,7 +4059,7 @@ impl MultiBufferSnapshot {
|
|||
pub fn excerpt_containing<T: ToOffset>(&self, range: Range<T>) -> Option<MultiBufferExcerpt> {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
|
||||
let mut cursor = self.excerpts.cursor::<usize>(&());
|
||||
let mut cursor = self.excerpts.cursor::<(usize, Point)>(&());
|
||||
cursor.seek(&range.start, Bias::Right, &());
|
||||
let start_excerpt = cursor.item()?;
|
||||
|
||||
|
@ -4204,12 +4084,12 @@ impl MultiBufferSnapshot {
|
|||
I: IntoIterator<Item = Range<Anchor>> + 'a,
|
||||
{
|
||||
let mut ranges = ranges.into_iter().map(|range| range.to_offset(self));
|
||||
let mut cursor = self.excerpts.cursor::<usize>(&());
|
||||
let mut cursor = self.excerpts.cursor::<(usize, Point)>(&());
|
||||
cursor.next(&());
|
||||
let mut current_range = ranges.next();
|
||||
iter::from_fn(move || {
|
||||
let range = current_range.clone()?;
|
||||
if range.start >= cursor.end(&()) {
|
||||
if range.start >= cursor.end(&()).0 {
|
||||
cursor.seek_forward(&range.start, Bias::Right, &());
|
||||
if range.start == self.len() {
|
||||
cursor.prev(&());
|
||||
|
@ -4217,11 +4097,11 @@ impl MultiBufferSnapshot {
|
|||
}
|
||||
|
||||
let excerpt = cursor.item()?;
|
||||
let range_start_in_excerpt = cmp::max(range.start, *cursor.start());
|
||||
let range_start_in_excerpt = cmp::max(range.start, cursor.start().0);
|
||||
let range_end_in_excerpt = if excerpt.has_trailing_newline {
|
||||
cmp::min(range.end, cursor.end(&()) - 1)
|
||||
cmp::min(range.end, cursor.end(&()).0 - 1)
|
||||
} else {
|
||||
cmp::min(range.end, cursor.end(&()))
|
||||
cmp::min(range.end, cursor.end(&()).0)
|
||||
};
|
||||
let buffer_range = MultiBufferExcerpt::new(excerpt, *cursor.start())
|
||||
.map_range_to_buffer(range_start_in_excerpt..range_end_in_excerpt);
|
||||
|
@ -4237,7 +4117,7 @@ impl MultiBufferSnapshot {
|
|||
text_anchor: excerpt.buffer.anchor_after(buffer_range.end),
|
||||
};
|
||||
|
||||
if range.end > cursor.end(&()) {
|
||||
if range.end > cursor.end(&()).0 {
|
||||
cursor.next(&());
|
||||
} else {
|
||||
current_range = ranges.next();
|
||||
|
@ -4256,12 +4136,12 @@ impl MultiBufferSnapshot {
|
|||
ranges: impl IntoIterator<Item = Range<Anchor>>,
|
||||
) -> impl Iterator<Item = (ExcerptId, &BufferSnapshot, Range<usize>)> {
|
||||
let mut ranges = ranges.into_iter().map(|range| range.to_offset(self));
|
||||
let mut cursor = self.excerpts.cursor::<usize>(&());
|
||||
let mut cursor = self.excerpts.cursor::<(usize, Point)>(&());
|
||||
cursor.next(&());
|
||||
let mut current_range = ranges.next();
|
||||
iter::from_fn(move || {
|
||||
let range = current_range.clone()?;
|
||||
if range.start >= cursor.end(&()) {
|
||||
if range.start >= cursor.end(&()).0 {
|
||||
cursor.seek_forward(&range.start, Bias::Right, &());
|
||||
if range.start == self.len() {
|
||||
cursor.prev(&());
|
||||
|
@ -4269,16 +4149,16 @@ impl MultiBufferSnapshot {
|
|||
}
|
||||
|
||||
let excerpt = cursor.item()?;
|
||||
let range_start_in_excerpt = cmp::max(range.start, *cursor.start());
|
||||
let range_start_in_excerpt = cmp::max(range.start, cursor.start().0);
|
||||
let range_end_in_excerpt = if excerpt.has_trailing_newline {
|
||||
cmp::min(range.end, cursor.end(&()) - 1)
|
||||
cmp::min(range.end, cursor.end(&()).0 - 1)
|
||||
} else {
|
||||
cmp::min(range.end, cursor.end(&()))
|
||||
cmp::min(range.end, cursor.end(&()).0)
|
||||
};
|
||||
let buffer_range = MultiBufferExcerpt::new(excerpt, *cursor.start())
|
||||
.map_range_to_buffer(range_start_in_excerpt..range_end_in_excerpt);
|
||||
|
||||
if range.end > cursor.end(&()) {
|
||||
if range.end > cursor.end(&()).0 {
|
||||
cursor.next(&());
|
||||
} else {
|
||||
current_range = ranges.next();
|
||||
|
@ -4702,6 +4582,11 @@ impl Excerpt {
|
|||
self.range.context.start.to_offset(&self.buffer)
|
||||
}
|
||||
|
||||
/// The [`Excerpt`]'s start point in its [`Buffer`]
|
||||
fn buffer_start_point(&self) -> Point {
|
||||
self.range.context.start.to_point(&self.buffer)
|
||||
}
|
||||
|
||||
/// The [`Excerpt`]'s end offset in its [`Buffer`]
|
||||
fn buffer_end_offset(&self) -> usize {
|
||||
self.buffer_start_offset() + self.text_summary.len
|
||||
|
@ -4709,10 +4594,11 @@ impl Excerpt {
|
|||
}
|
||||
|
||||
impl<'a> MultiBufferExcerpt<'a> {
|
||||
fn new(excerpt: &'a Excerpt, excerpt_offset: usize) -> Self {
|
||||
fn new(excerpt: &'a Excerpt, (excerpt_offset, excerpt_position): (usize, Point)) -> Self {
|
||||
MultiBufferExcerpt {
|
||||
excerpt,
|
||||
excerpt_offset,
|
||||
excerpt_position,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4740,9 +4626,32 @@ impl<'a> MultiBufferExcerpt<'a> {
|
|||
&self.excerpt.buffer
|
||||
}
|
||||
|
||||
pub fn buffer_range(&self) -> Range<text::Anchor> {
|
||||
self.excerpt.range.context.clone()
|
||||
}
|
||||
|
||||
pub fn start_offset(&self) -> usize {
|
||||
self.excerpt_offset
|
||||
}
|
||||
|
||||
pub fn start_point(&self) -> Point {
|
||||
self.excerpt_position
|
||||
}
|
||||
|
||||
/// Maps an offset within the [`MultiBuffer`] to an offset within the [`Buffer`]
|
||||
pub fn map_offset_to_buffer(&self, offset: usize) -> usize {
|
||||
self.excerpt.buffer_start_offset() + offset.saturating_sub(self.excerpt_offset)
|
||||
self.excerpt.buffer_start_offset()
|
||||
+ offset
|
||||
.saturating_sub(self.excerpt_offset)
|
||||
.min(self.excerpt.text_summary.len)
|
||||
}
|
||||
|
||||
/// Maps a point within the [`MultiBuffer`] to a point within the [`Buffer`]
|
||||
pub fn map_point_to_buffer(&self, point: Point) -> Point {
|
||||
self.excerpt.buffer_start_point()
|
||||
+ point
|
||||
.saturating_sub(self.excerpt_position)
|
||||
.min(self.excerpt.text_summary.lines)
|
||||
}
|
||||
|
||||
/// Maps a range within the [`MultiBuffer`] to a range within the [`Buffer`]
|
||||
|
@ -4752,14 +4661,20 @@ impl<'a> MultiBufferExcerpt<'a> {
|
|||
|
||||
/// Map an offset within the [`Buffer`] to an offset within the [`MultiBuffer`]
|
||||
pub fn map_offset_from_buffer(&self, buffer_offset: usize) -> usize {
|
||||
let mut buffer_offset_in_excerpt =
|
||||
buffer_offset.saturating_sub(self.excerpt.buffer_start_offset());
|
||||
buffer_offset_in_excerpt =
|
||||
cmp::min(buffer_offset_in_excerpt, self.excerpt.text_summary.len);
|
||||
|
||||
let buffer_offset_in_excerpt = buffer_offset
|
||||
.saturating_sub(self.excerpt.buffer_start_offset())
|
||||
.min(self.excerpt.text_summary.len);
|
||||
self.excerpt_offset + buffer_offset_in_excerpt
|
||||
}
|
||||
|
||||
/// Map a point within the [`Buffer`] to a point within the [`MultiBuffer`]
|
||||
pub fn map_point_from_buffer(&self, buffer_position: Point) -> Point {
|
||||
let position_in_excerpt = buffer_position.saturating_sub(self.excerpt.buffer_start_point());
|
||||
let position_in_excerpt =
|
||||
position_in_excerpt.min(self.excerpt.text_summary.lines + Point::new(1, 0));
|
||||
self.excerpt_position + position_in_excerpt
|
||||
}
|
||||
|
||||
/// Map a range within the [`Buffer`] to a range within the [`MultiBuffer`]
|
||||
pub fn map_range_from_buffer(&self, buffer_range: Range<usize>) -> Range<usize> {
|
||||
self.map_offset_from_buffer(buffer_range.start)
|
||||
|
@ -4771,6 +4686,10 @@ impl<'a> MultiBufferExcerpt<'a> {
|
|||
range.start >= self.excerpt.buffer_start_offset()
|
||||
&& range.end <= self.excerpt.buffer_end_offset()
|
||||
}
|
||||
|
||||
pub fn max_buffer_row(&self) -> u32 {
|
||||
self.excerpt.max_buffer_row
|
||||
}
|
||||
}
|
||||
|
||||
impl ExcerptId {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue