Fix sticky header in last buffer of a multibuffer (#26944)

This also simplifies our code to stop generating a last excerpt boundary
that we always ignore.

Closes #ISSUE

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin 2025-03-17 12:39:57 -06:00 committed by GitHub
parent 94b63808e0
commit 25772b8777
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 138 additions and 236 deletions

View file

@ -346,17 +346,16 @@ impl std::fmt::Debug for ExcerptInfo {
#[derive(Debug)]
pub struct ExcerptBoundary {
pub prev: Option<ExcerptInfo>,
pub next: Option<ExcerptInfo>,
pub next: ExcerptInfo,
/// The row in the `MultiBuffer` where the boundary is located
pub row: MultiBufferRow,
}
impl ExcerptBoundary {
pub fn starts_new_buffer(&self) -> bool {
match (self.prev.as_ref(), self.next.as_ref()) {
match (self.prev.as_ref(), &self.next) {
(None, _) => true,
(Some(_), None) => false,
(Some(prev), Some(next)) => prev.buffer_id != next.buffer_id,
(Some(prev), next) => prev.buffer_id != next.buffer_id,
}
}
}
@ -5200,27 +5199,19 @@ impl MultiBufferSnapshot {
cursor.next_excerpt();
let mut visited_end = false;
iter::from_fn(move || loop {
if self.singleton {
return None;
}
let next_region = cursor.region();
let next_region = cursor.region()?;
cursor.next_excerpt();
if !bounds.contains(&next_region.range.start.key) {
prev_region = Some(next_region);
continue;
}
let next_region_start = if let Some(region) = &next_region {
if !bounds.contains(&region.range.start.key) {
prev_region = next_region;
continue;
}
region.range.start.value.unwrap()
} else {
if !bounds.contains(&self.len()) {
return None;
}
self.max_point()
};
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()
} else {
@ -5235,29 +5226,21 @@ impl MultiBufferSnapshot {
end_row: MultiBufferRow(next_region_start.row),
});
let next = next_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(),
end_row: if region.excerpt.has_trailing_newline {
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 {
MultiBufferRow(next_region_end.row - 1)
} else {
MultiBufferRow(next_region_end.row)
},
});
if next.is_none() {
if visited_end {
return None;
} else {
visited_end = true;
}
}
};
let row = MultiBufferRow(next_region_start.row);
prev_region = next_region;
prev_region = Some(next_region);
return Some(ExcerptBoundary { row, prev, next });
})

View file

@ -341,17 +341,17 @@ fn test_excerpt_boundaries_and_clipping(cx: &mut App) {
) -> Vec<(MultiBufferRow, String, bool)> {
snapshot
.excerpt_boundaries_in_range(range)
.filter_map(|boundary| {
.map(|boundary| {
let starts_new_buffer = boundary.starts_new_buffer();
boundary.next.map(|next| {
(
boundary.row,
next.buffer
.text_for_range(next.range.context)
.collect::<String>(),
starts_new_buffer,
)
})
(
boundary.row,
boundary
.next
.buffer
.text_for_range(boundary.next.range.context)
.collect::<String>(),
starts_new_buffer,
)
})
.collect::<Vec<_>>()
}
@ -2695,7 +2695,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
let actual_text = snapshot.text();
let actual_boundary_rows = snapshot
.excerpt_boundaries_in_range(0..)
.filter_map(|b| if b.next.is_some() { Some(b.row) } else { None })
.map(|b| b.row)
.collect::<HashSet<_>>();
let actual_row_infos = snapshot.row_infos(MultiBufferRow(0)).collect::<Vec<_>>();