Implement MultiBuffer::buffer_rows

This commit is contained in:
Max Brunsfeld 2021-12-16 12:17:47 -08:00
parent a293e9c0c5
commit db33e4935a

View file

@ -111,6 +111,12 @@ struct ExcerptSummary {
text: TextSummary, text: TextSummary,
} }
pub struct MultiBufferRows<'a> {
header_height: u32,
buffer_row_range: Range<u32>,
excerpts: Cursor<'a, Excerpt, Point>,
}
pub struct MultiBufferChunks<'a> { pub struct MultiBufferChunks<'a> {
range: Range<usize>, range: Range<usize>,
excerpts: Cursor<'a, Excerpt, usize>, excerpts: Cursor<'a, Excerpt, usize>,
@ -1052,6 +1058,32 @@ impl MultiBufferSnapshot {
} }
} }
pub fn buffer_rows<'a>(&'a self, start_row: u32) -> MultiBufferRows<'a> {
let mut excerpts = self.excerpts.cursor::<Point>();
excerpts.seek(&Point::new(start_row, 0), Bias::Right, &());
if excerpts.item().is_none() {
excerpts.prev(&());
}
let mut header_height = 0;
let mut buffer_row_range = 0..0;
if let Some(excerpt) = excerpts.item() {
let overshoot = start_row - excerpts.start().row;
let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer).row;
let excerpt_header_height = excerpt.header_height as u32;
header_height = excerpt_header_height.saturating_sub(overshoot);
buffer_row_range.start =
excerpt_start + overshoot.saturating_sub(excerpt_header_height);
buffer_row_range.end =
excerpt_start + excerpt.text_summary.lines.row + 1 - excerpt_header_height;
}
MultiBufferRows {
header_height,
buffer_row_range,
excerpts,
}
}
pub fn chunks<'a, T: ToOffset>( pub fn chunks<'a, T: ToOffset>(
&'a self, &'a self,
range: Range<T>, range: Range<T>,
@ -1821,6 +1853,34 @@ impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
} }
} }
impl<'a> Iterator for MultiBufferRows<'a> {
type Item = Option<u32>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.header_height > 0 {
self.header_height -= 1;
return Some(None);
}
if !self.buffer_row_range.is_empty() {
let row = Some(self.buffer_row_range.start);
self.buffer_row_range.start += 1;
return Some(row);
}
self.excerpts.next(&());
if let Some(excerpt) = self.excerpts.item() {
self.header_height = excerpt.header_height as u32;
self.buffer_row_range.start = excerpt.range.start.to_point(&excerpt.buffer).row;
self.buffer_row_range.end =
self.buffer_row_range.start + excerpt.text_summary.lines.row + 1
- self.header_height;
} else {
return None;
}
}
}
}
impl<'a> MultiBufferChunks<'a> { impl<'a> MultiBufferChunks<'a> {
pub fn offset(&self) -> usize { pub fn offset(&self) -> usize {
self.range.start self.range.start
@ -2009,15 +2069,26 @@ mod tests {
fn test_singleton_multibuffer(cx: &mut MutableAppContext) { fn test_singleton_multibuffer(cx: &mut MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx)); let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx)); let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
let snapshot = multibuffer.read(cx).snapshot(cx);
assert_eq!(snapshot.text(), buffer.read(cx).text());
assert_eq!( assert_eq!(
multibuffer.read(cx).snapshot(cx).text(), snapshot.buffer_rows(0).collect::<Vec<_>>(),
buffer.read(cx).text() (0..buffer.read(cx).row_count())
.map(Some)
.collect::<Vec<_>>()
); );
buffer.update(cx, |buffer, cx| buffer.edit([1..3], "XXX", cx)); buffer.update(cx, |buffer, cx| buffer.edit([1..3], "XXX\n", cx));
let snapshot = multibuffer.read(cx).snapshot(cx);
assert_eq!(snapshot.text(), buffer.read(cx).text());
assert_eq!( assert_eq!(
multibuffer.read(cx).snapshot(cx).text(), snapshot.buffer_rows(0).collect::<Vec<_>>(),
buffer.read(cx).text() (0..buffer.read(cx).row_count())
.map(Some)
.collect::<Vec<_>>()
); );
} }
@ -2075,8 +2146,9 @@ mod tests {
subscription subscription
}); });
let snapshot = multibuffer.read(cx).snapshot(cx);
assert_eq!( assert_eq!(
multibuffer.read(cx).snapshot(cx).text(), snapshot.text(),
concat!( concat!(
"\n", // Preserve newlines "\n", // Preserve newlines
"\n", // "\n", //
@ -2091,6 +2163,22 @@ mod tests {
"jj" // "jj" //
) )
); );
assert_eq!(
snapshot.buffer_rows(0).collect::<Vec<_>>(),
&[
None,
None,
Some(1),
Some(2),
None,
Some(3),
Some(4),
None,
None,
None,
Some(3)
]
);
{ {
let snapshot = multibuffer.read(cx).read(cx); let snapshot = multibuffer.read(cx).read(cx);
@ -2342,17 +2430,25 @@ mod tests {
let mut excerpt_starts = Vec::new(); let mut excerpt_starts = Vec::new();
let mut expected_text = String::new(); let mut expected_text = String::new();
let mut expected_buffer_rows = Vec::new();
for (buffer, range, header_height) in &expected_excerpts { for (buffer, range, header_height) in &expected_excerpts {
let buffer = buffer.read(cx); let buffer = buffer.read(cx);
let buffer_range = range.to_offset(buffer); let buffer_range = range.to_offset(buffer);
for _ in 0..*header_height { for _ in 0..*header_height {
expected_text.push('\n'); expected_text.push('\n');
expected_buffer_rows.push(None);
} }
excerpt_starts.push(TextSummary::from(expected_text.as_str())); excerpt_starts.push(TextSummary::from(expected_text.as_str()));
expected_text.extend(buffer.text_for_range(buffer_range.clone())); expected_text.extend(buffer.text_for_range(buffer_range.clone()));
expected_text.push('\n'); expected_text.push('\n');
let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
..=buffer.offset_to_point(buffer_range.end).row;
for row in buffer_row_range {
expected_buffer_rows.push(Some(row));
}
} }
// Remove final trailing newline. // Remove final trailing newline.
if !expected_excerpts.is_empty() { if !expected_excerpts.is_empty() {
@ -2362,6 +2458,21 @@ mod tests {
assert_eq!(snapshot.text(), expected_text); assert_eq!(snapshot.text(), expected_text);
log::info!("MultiBuffer text: {:?}", expected_text); log::info!("MultiBuffer text: {:?}", expected_text);
assert_eq!(
snapshot.buffer_rows(0).collect::<Vec<_>>(),
expected_buffer_rows,
);
for _ in 0..5 {
let start_row = rng.gen_range(0..=expected_buffer_rows.len());
assert_eq!(
snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
&expected_buffer_rows[start_row..],
"buffer_rows({})",
start_row
);
}
let mut excerpt_starts = excerpt_starts.into_iter(); let mut excerpt_starts = excerpt_starts.into_iter();
for (buffer, range, _) in &expected_excerpts { for (buffer, range, _) in &expected_excerpts {
let buffer_id = buffer.id(); let buffer_id = buffer.id();