Don't insert headers in MultiBuffer

This lays the groundwork to insert headers in the block map instead.
This commit is contained in:
Antonio Scandurra 2021-12-21 16:38:18 +01:00
parent 99317bbd62
commit 8534a9cc41
4 changed files with 165 additions and 385 deletions

View file

@ -348,11 +348,12 @@ impl DisplaySnapshot {
&'a self, &'a self,
rows: Range<u32>, rows: Range<u32>,
) -> impl 'a + Iterator<Item = (Range<u32>, RenderHeaderFn)> { ) -> impl 'a + Iterator<Item = (Range<u32>, RenderHeaderFn)> {
todo!();
let start_row = DisplayPoint::new(rows.start, 0).to_point(self).row; let start_row = DisplayPoint::new(rows.start, 0).to_point(self).row;
let end_row = DisplayPoint::new(rows.end, 0).to_point(self).row; let end_row = DisplayPoint::new(rows.end, 0).to_point(self).row;
self.buffer_snapshot self.buffer_snapshot
.excerpt_headers_in_range(start_row..end_row) .excerpt_headers_in_range(start_row..end_row)
.map(move |(rows, render)| { .map(move |(row, header_height, render)| {
let start_row = Point::new(rows.start, 0).to_display_point(self).row(); let start_row = Point::new(rows.start, 0).to_display_point(self).row();
let end_row = Point::new(rows.end, 0).to_display_point(self).row(); let end_row = Point::new(rows.end, 0).to_display_point(self).row();
(start_row..end_row, render) (start_row..end_row, render)

View file

@ -114,7 +114,6 @@ struct ExcerptSummary {
} }
pub struct MultiBufferRows<'a> { pub struct MultiBufferRows<'a> {
header_height: u32,
buffer_row_range: Range<u32>, buffer_row_range: Range<u32>,
excerpts: Cursor<'a, Excerpt, Point>, excerpts: Cursor<'a, Excerpt, Point>,
} }
@ -134,13 +133,11 @@ pub struct MultiBufferBytes<'a> {
} }
struct ExcerptChunks<'a> { struct ExcerptChunks<'a> {
header_height: usize,
content_chunks: BufferChunks<'a>, content_chunks: BufferChunks<'a>,
footer_height: usize, footer_height: usize,
} }
struct ExcerptBytes<'a> { struct ExcerptBytes<'a> {
header_height: usize,
content_bytes: language::rope::Bytes<'a>, content_bytes: language::rope::Bytes<'a>,
footer_height: usize, footer_height: usize,
} }
@ -326,8 +323,7 @@ impl MultiBuffer {
cursor.prev(&()); cursor.prev(&());
} }
let start_excerpt = cursor.item().expect("start offset out of bounds"); let start_excerpt = cursor.item().expect("start offset out of bounds");
let start_overshoot = let start_overshoot = start - cursor.start();
(start - cursor.start()).saturating_sub(start_excerpt.header_height as usize);
let buffer_start = let buffer_start =
start_excerpt.range.start.to_offset(&start_excerpt.buffer) + start_overshoot; start_excerpt.range.start.to_offset(&start_excerpt.buffer) + start_overshoot;
@ -336,8 +332,7 @@ impl MultiBuffer {
cursor.prev(&()); cursor.prev(&());
} }
let end_excerpt = cursor.item().expect("end offset out of bounds"); let end_excerpt = cursor.item().expect("end offset out of bounds");
let end_overshoot = let end_overshoot = end - cursor.start();
(end - cursor.start()).saturating_sub(end_excerpt.header_height as usize);
let buffer_end = end_excerpt.range.start.to_offset(&end_excerpt.buffer) + end_overshoot; let buffer_end = end_excerpt.range.start.to_offset(&end_excerpt.buffer) + end_overshoot;
if start_excerpt.id == end_excerpt.id { if start_excerpt.id == end_excerpt.id {
@ -749,10 +744,8 @@ impl MultiBuffer {
old_excerpt.range.clone(), old_excerpt.range.clone(),
) )
.map(|mut edit| { .map(|mut edit| {
let excerpt_old_start = let excerpt_old_start = cursor.start().1;
cursor.start().1 + old_excerpt.header_height as usize; let excerpt_new_start = new_excerpts.summary().text.bytes;
let excerpt_new_start = new_excerpts.summary().text.bytes
+ old_excerpt.header_height as usize;
edit.old.start += excerpt_old_start; edit.old.start += excerpt_old_start;
edit.old.end += excerpt_old_start; edit.old.end += excerpt_old_start;
edit.new.start += excerpt_new_start; edit.new.start += excerpt_new_start;
@ -831,14 +824,12 @@ impl MultiBufferSnapshot {
pub fn excerpt_headers_in_range<'a>( pub fn excerpt_headers_in_range<'a>(
&'a self, &'a self,
range: Range<u32>, range: Range<u32>,
) -> impl 'a + Iterator<Item = (Range<u32>, RenderHeaderFn)> { ) -> impl 'a + Iterator<Item = (u32, u8, RenderHeaderFn)> {
let mut cursor = self.excerpts.cursor::<Point>(); let mut cursor = self.excerpts.cursor::<Point>();
cursor.seek(&Point::new(range.start, 0), Bias::Right, &()); cursor.seek(&Point::new(range.start, 0), Bias::Right, &());
if let Some(excerpt) = cursor.item() { if cursor.item().is_some() && range.start > cursor.start().row {
if range.start >= cursor.start().row + excerpt.header_height as u32 { cursor.next(&());
cursor.next(&());
}
} }
iter::from_fn(move || { iter::from_fn(move || {
@ -849,9 +840,8 @@ impl MultiBufferSnapshot {
if let Some(render) = excerpt.render_header.clone() { if let Some(render) = excerpt.render_header.clone() {
let start = cursor.start().row; let start = cursor.start().row;
let end = start + excerpt.header_height as u32;
cursor.next(&()); cursor.next(&());
return Some((start..end, render)); return Some((start, excerpt.header_height, render));
} else { } else {
cursor.next(&()); cursor.next(&());
} }
@ -868,12 +858,9 @@ impl MultiBufferSnapshot {
let mut cursor = self.excerpts.cursor::<usize>(); let mut cursor = self.excerpts.cursor::<usize>();
cursor.seek(&offset, Bias::Left, &()); cursor.seek(&offset, Bias::Left, &());
let mut excerpt_chunks = cursor.item().map(|excerpt| { let mut excerpt_chunks = cursor.item().map(|excerpt| {
let start_after_header = cursor.start() + excerpt.header_height as usize;
let end_before_footer = cursor.start() + excerpt.text_summary.bytes; let end_before_footer = cursor.start() + excerpt.text_summary.bytes;
let start = excerpt.range.start.to_offset(&excerpt.buffer); let start = excerpt.range.start.to_offset(&excerpt.buffer);
let end = let end = start + (cmp::min(offset, end_before_footer) - cursor.start());
start + (cmp::min(offset, end_before_footer).saturating_sub(start_after_header));
excerpt.buffer.reversed_chunks_in_range(start..end) excerpt.buffer.reversed_chunks_in_range(start..end)
}); });
iter::from_fn(move || { iter::from_fn(move || {
@ -888,11 +875,7 @@ impl MultiBufferSnapshot {
} }
let excerpt = cursor.item().unwrap(); let excerpt = cursor.item().unwrap();
if offset <= cursor.start() + excerpt.header_height as usize { if offset == cursor.end(&()) && excerpt.has_trailing_newline {
let header_height = offset - cursor.start();
offset -= header_height;
Some(unsafe { str::from_utf8_unchecked(&NEWLINES[..header_height]) })
} else if offset == cursor.end(&()) && excerpt.has_trailing_newline {
offset -= 1; offset -= 1;
Some("\n") Some("\n")
} else { } else {
@ -953,93 +936,48 @@ impl MultiBufferSnapshot {
pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize { pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
let mut cursor = self.excerpts.cursor::<usize>(); let mut cursor = self.excerpts.cursor::<usize>();
cursor.seek(&offset, Bias::Right, &()); cursor.seek(&offset, Bias::Right, &());
if let Some(excerpt) = cursor.item() { let overshoot = if let Some(excerpt) = cursor.item() {
let header_end = *cursor.start() + excerpt.header_height as usize; let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
if offset < header_end { let buffer_offset = excerpt
if bias == Bias::Left { .buffer
cursor.prev(&()); .clip_offset(excerpt_start + (offset - cursor.start()), bias);
if let Some(excerpt) = cursor.item() { buffer_offset.saturating_sub(excerpt_start)
return *cursor.start() + excerpt.text_summary.bytes;
}
}
header_end
} else {
let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
let buffer_offset = excerpt
.buffer
.clip_offset(excerpt_start + (offset - header_end), bias);
let offset_in_excerpt = if buffer_offset > excerpt_start {
buffer_offset - excerpt_start
} else {
0
};
header_end + offset_in_excerpt
}
} else { } else {
self.excerpts.summary().text.bytes 0
} };
cursor.start() + overshoot
} }
pub fn clip_point(&self, point: Point, bias: Bias) -> Point { pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
let mut cursor = self.excerpts.cursor::<Point>(); let mut cursor = self.excerpts.cursor::<Point>();
cursor.seek(&point, Bias::Right, &()); cursor.seek(&point, Bias::Right, &());
if let Some(excerpt) = cursor.item() { let overshoot = if let Some(excerpt) = cursor.item() {
let header_end = *cursor.start() + Point::new(excerpt.header_height as u32, 0); let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
if point < header_end { let buffer_point = excerpt
if bias == Bias::Left { .buffer
cursor.prev(&()); .clip_point(excerpt_start + (point - cursor.start()), bias);
if let Some(excerpt) = cursor.item() { buffer_point.saturating_sub(excerpt_start)
return *cursor.start() + excerpt.text_summary.lines;
}
}
header_end
} else {
let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
let buffer_point = excerpt
.buffer
.clip_point(excerpt_start + (point - header_end), bias);
let point_in_excerpt = if buffer_point > excerpt_start {
buffer_point - excerpt_start
} else {
Point::zero()
};
header_end + point_in_excerpt
}
} else { } else {
self.excerpts.summary().text.lines Point::zero()
} };
*cursor.start() + overshoot
} }
pub fn clip_point_utf16(&self, point: PointUtf16, bias: Bias) -> PointUtf16 { pub fn clip_point_utf16(&self, point: PointUtf16, bias: Bias) -> PointUtf16 {
let mut cursor = self.excerpts.cursor::<PointUtf16>(); let mut cursor = self.excerpts.cursor::<PointUtf16>();
cursor.seek(&point, Bias::Right, &()); cursor.seek(&point, Bias::Right, &());
if let Some(excerpt) = cursor.item() { let overshoot = if let Some(excerpt) = cursor.item() {
let header_end = *cursor.start() + PointUtf16::new(excerpt.header_height as u32, 0); let excerpt_start = excerpt
if point < header_end { .buffer
if bias == Bias::Left { .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
cursor.prev(&()); let buffer_point = excerpt
if let Some(excerpt) = cursor.item() { .buffer
return *cursor.start() + excerpt.text_summary.lines_utf16; .clip_point_utf16(excerpt_start + (point - cursor.start()), bias);
} buffer_point.saturating_sub(excerpt_start)
}
header_end
} else {
let excerpt_start = excerpt
.buffer
.offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
let buffer_point = excerpt
.buffer
.clip_point_utf16(excerpt_start + (point - header_end), bias);
let point_in_excerpt = if buffer_point > excerpt_start {
buffer_point - excerpt_start
} else {
PointUtf16::new(0, 0)
};
header_end + point_in_excerpt
}
} else { } else {
self.excerpts.summary().text.lines_utf16 PointUtf16::zero()
} };
*cursor.start() + overshoot
} }
pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> MultiBufferBytes<'a> { pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> MultiBufferBytes<'a> {
@ -1067,7 +1005,6 @@ impl MultiBufferSnapshot {
pub fn buffer_rows<'a>(&'a self, start_row: u32) -> MultiBufferRows<'a> { pub fn buffer_rows<'a>(&'a self, start_row: u32) -> MultiBufferRows<'a> {
let mut result = MultiBufferRows { let mut result = MultiBufferRows {
header_height: 0,
buffer_row_range: 0..0, buffer_row_range: 0..0,
excerpts: self.excerpts.cursor(), excerpts: self.excerpts.cursor(),
}; };
@ -1097,19 +1034,12 @@ impl MultiBufferSnapshot {
if let Some(excerpt) = cursor.item() { if let Some(excerpt) = cursor.item() {
let (start_offset, start_point) = cursor.start(); let (start_offset, start_point) = cursor.start();
let overshoot = offset - start_offset; let overshoot = offset - start_offset;
let header_height = excerpt.header_height as usize; let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
if overshoot < header_height { let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
*start_point + Point::new(overshoot as u32, 0) let buffer_point = excerpt
} else { .buffer
let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer); .offset_to_point(excerpt_start_offset + overshoot);
let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer); *start_point + (buffer_point - excerpt_start_point)
let buffer_point = excerpt
.buffer
.offset_to_point(excerpt_start_offset + (overshoot - header_height));
*start_point
+ Point::new(header_height as u32, 0)
+ (buffer_point - excerpt_start_point)
}
} else { } else {
self.excerpts.summary().text.lines self.excerpts.summary().text.lines
} }
@ -1121,18 +1051,12 @@ impl MultiBufferSnapshot {
if let Some(excerpt) = cursor.item() { if let Some(excerpt) = cursor.item() {
let (start_point, start_offset) = cursor.start(); let (start_point, start_offset) = cursor.start();
let overshoot = point - start_point; let overshoot = point - start_point;
let header_height = Point::new(excerpt.header_height as u32, 0); let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
if overshoot < header_height { let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
start_offset + overshoot.row as usize let buffer_offset = excerpt
} else { .buffer
let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer); .point_to_offset(excerpt_start_point + overshoot);
let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer); *start_offset + buffer_offset - excerpt_start_offset
let buffer_offset = excerpt
.buffer
.point_to_offset(excerpt_start_point + (overshoot - header_height));
*start_offset + excerpt.header_height as usize + buffer_offset
- excerpt_start_offset
}
} else { } else {
self.excerpts.summary().text.bytes self.excerpts.summary().text.bytes
} }
@ -1144,21 +1068,14 @@ impl MultiBufferSnapshot {
if let Some(excerpt) = cursor.item() { if let Some(excerpt) = cursor.item() {
let (start_point, start_offset) = cursor.start(); let (start_point, start_offset) = cursor.start();
let overshoot = point - start_point; let overshoot = point - start_point;
let header_height = PointUtf16::new(excerpt.header_height as u32, 0); let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
if overshoot < header_height { let excerpt_start_point = excerpt
start_offset + overshoot.row as usize .buffer
} else { .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer); let buffer_offset = excerpt
let excerpt_start_point = excerpt .buffer
.buffer .point_utf16_to_offset(excerpt_start_point + overshoot);
.offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer)); *start_offset + (buffer_offset - excerpt_start_offset)
let buffer_offset = excerpt
.buffer
.point_utf16_to_offset(excerpt_start_point + (overshoot - header_height));
*start_offset
+ excerpt.header_height as usize
+ (buffer_offset - excerpt_start_offset)
}
} else { } else {
self.excerpts.summary().text.bytes self.excerpts.summary().text.bytes
} }
@ -1188,18 +1105,15 @@ impl MultiBufferSnapshot {
cursor.seek(&Point::new(row, 0), Bias::Right, &()); cursor.seek(&Point::new(row, 0), Bias::Right, &());
if let Some(excerpt) = cursor.item() { if let Some(excerpt) = cursor.item() {
let overshoot = row - cursor.start().row; let overshoot = row - cursor.start().row;
let header_height = excerpt.header_height as u32; let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
if overshoot >= header_height { let excerpt_end = excerpt.range.end.to_point(&excerpt.buffer);
let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer); let buffer_row = excerpt_start.row + overshoot;
let excerpt_end = excerpt.range.end.to_point(&excerpt.buffer); let line_start = Point::new(buffer_row, 0);
let buffer_row = excerpt_start.row + overshoot - header_height; let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
let line_start = Point::new(buffer_row, 0); return Some((
let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row)); &excerpt.buffer,
return Some(( line_start.max(excerpt_start)..line_end.min(excerpt_end),
&excerpt.buffer, ));
line_start.max(excerpt_start)..line_end.min(excerpt_end),
));
}
} }
None None
} }
@ -1222,31 +1136,15 @@ impl MultiBufferSnapshot {
let mut cursor = self.excerpts.cursor::<usize>(); let mut cursor = self.excerpts.cursor::<usize>();
cursor.seek(&range.start, Bias::Right, &()); cursor.seek(&range.start, Bias::Right, &());
if let Some(excerpt) = cursor.item() { if let Some(excerpt) = cursor.item() {
let start_after_header = cursor.start() + excerpt.header_height as usize;
if range.start < start_after_header {
let header_len = cmp::min(range.end, start_after_header) - range.start;
summary.add_assign(&D::from_text_summary(&TextSummary {
bytes: header_len,
lines: Point::new(header_len as u32, 0),
lines_utf16: PointUtf16::new(header_len as u32, 0),
first_line_chars: 0,
last_line_chars: 0,
longest_row: 0,
longest_row_chars: 0,
}));
range.start = start_after_header;
range.end = cmp::max(range.start, range.end);
}
let mut end_before_newline = cursor.end(&()); let mut end_before_newline = cursor.end(&());
if excerpt.has_trailing_newline { if excerpt.has_trailing_newline {
end_before_newline -= 1; end_before_newline -= 1;
} }
let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer); let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
let start_in_excerpt = excerpt_start + (range.start - start_after_header); let start_in_excerpt = excerpt_start + (range.start - cursor.start());
let end_in_excerpt = let end_in_excerpt =
excerpt_start + (cmp::min(end_before_newline, range.end) - start_after_header); excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start());
summary.add_assign( summary.add_assign(
&excerpt &excerpt
.buffer .buffer
@ -1275,28 +1173,15 @@ impl MultiBufferSnapshot {
&(), &(),
))); )));
if let Some(excerpt) = cursor.item() { if let Some(excerpt) = cursor.item() {
let start_after_header = cursor.start() + excerpt.header_height as usize; range.end = cmp::max(*cursor.start(), range.end);
let header_len =
cmp::min(range.end - cursor.start(), excerpt.header_height as usize);
summary.add_assign(&D::from_text_summary(&TextSummary {
bytes: header_len,
lines: Point::new(header_len as u32, 0),
lines_utf16: PointUtf16::new(header_len as u32, 0),
first_line_chars: 0,
last_line_chars: 0,
longest_row: 0,
longest_row_chars: 0,
}));
range.end = cmp::max(start_after_header, range.end);
let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer); let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
let end_in_excerpt = excerpt_start + (range.end - start_after_header); let end_in_excerpt = excerpt_start + (range.end - cursor.start());
summary.add_assign( summary.add_assign(
&excerpt &excerpt
.buffer .buffer
.text_summary_for_range(excerpt_start..end_in_excerpt), .text_summary_for_range(excerpt_start..end_in_excerpt),
); );
cursor.next(&());
} }
} }
@ -1315,7 +1200,6 @@ impl MultiBufferSnapshot {
let mut position = D::from_text_summary(&cursor.start().text); let mut position = D::from_text_summary(&cursor.start().text);
if let Some(excerpt) = cursor.item() { if let Some(excerpt) = cursor.item() {
position.add_summary(&excerpt.header_summary(), &());
if excerpt.id == anchor.excerpt_id { if excerpt.id == anchor.excerpt_id {
let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer); let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
let buffer_position = anchor.text_anchor.summary::<D>(&excerpt.buffer); let buffer_position = anchor.text_anchor.summary::<D>(&excerpt.buffer);
@ -1351,9 +1235,8 @@ impl MultiBufferSnapshot {
cursor.next(&()); cursor.next(&());
} }
let mut position = D::from_text_summary(&cursor.start().text); let position = D::from_text_summary(&cursor.start().text);
if let Some(excerpt) = cursor.item() { if let Some(excerpt) = cursor.item() {
position.add_summary(&excerpt.header_summary(), &());
if excerpt.id == *excerpt_id { if excerpt.id == *excerpt_id {
let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer); let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
summaries.extend( summaries.extend(
@ -1395,8 +1278,7 @@ impl MultiBufferSnapshot {
cursor.prev(&()); cursor.prev(&());
} }
if let Some(excerpt) = cursor.item() { if let Some(excerpt) = cursor.item() {
let start_after_header = cursor.start().0 + excerpt.header_height as usize; let mut overshoot = offset.saturating_sub(cursor.start().0);
let mut overshoot = offset.saturating_sub(start_after_header);
if excerpt.has_trailing_newline && offset == cursor.end(&()).0 { if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
overshoot -= 1; overshoot -= 1;
bias = Bias::Right; bias = Bias::Right;
@ -1458,14 +1340,12 @@ impl MultiBufferSnapshot {
let excerpt_buffer_start = let excerpt_buffer_start =
start_excerpt.range.start.to_offset(&start_excerpt.buffer); start_excerpt.range.start.to_offset(&start_excerpt.buffer);
let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
- start_excerpt.header_height as usize;
let start_after_header = cursor.start() + start_excerpt.header_height as usize;
let start_in_buffer = let start_in_buffer =
excerpt_buffer_start + range.start.saturating_sub(start_after_header); excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
let end_in_buffer = let end_in_buffer =
excerpt_buffer_start + range.end.saturating_sub(start_after_header); excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
let (mut start_bracket_range, mut end_bracket_range) = start_excerpt let (mut start_bracket_range, mut end_bracket_range) = start_excerpt
.buffer .buffer
.enclosing_bracket_ranges(start_in_buffer..end_in_buffer)?; .enclosing_bracket_ranges(start_in_buffer..end_in_buffer)?;
@ -1474,13 +1354,13 @@ impl MultiBufferSnapshot {
&& end_bracket_range.end < excerpt_buffer_end && end_bracket_range.end < excerpt_buffer_end
{ {
start_bracket_range.start = start_bracket_range.start =
start_after_header + (start_bracket_range.start - excerpt_buffer_start); cursor.start() + (start_bracket_range.start - excerpt_buffer_start);
start_bracket_range.end = start_bracket_range.end =
start_after_header + (start_bracket_range.end - excerpt_buffer_start); cursor.start() + (start_bracket_range.end - excerpt_buffer_start);
end_bracket_range.start = end_bracket_range.start =
start_after_header + (end_bracket_range.start - excerpt_buffer_start); cursor.start() + (end_bracket_range.start - excerpt_buffer_start);
end_bracket_range.end = end_bracket_range.end =
start_after_header + (end_bracket_range.end - excerpt_buffer_start); cursor.start() + (end_bracket_range.end - excerpt_buffer_start);
Some((start_bracket_range, end_bracket_range)) Some((start_bracket_range, end_bracket_range))
} else { } else {
None None
@ -1551,14 +1431,12 @@ impl MultiBufferSnapshot {
let excerpt_buffer_start = let excerpt_buffer_start =
start_excerpt.range.start.to_offset(&start_excerpt.buffer); start_excerpt.range.start.to_offset(&start_excerpt.buffer);
let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
- start_excerpt.header_height as usize;
let start_after_header = cursor.start() + start_excerpt.header_height as usize;
let start_in_buffer = let start_in_buffer =
excerpt_buffer_start + range.start.saturating_sub(start_after_header); excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
let end_in_buffer = let end_in_buffer =
excerpt_buffer_start + range.end.saturating_sub(start_after_header); excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
let mut ancestor_buffer_range = start_excerpt let mut ancestor_buffer_range = start_excerpt
.buffer .buffer
.range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?; .range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?;
@ -1566,9 +1444,8 @@ impl MultiBufferSnapshot {
cmp::max(ancestor_buffer_range.start, excerpt_buffer_start); cmp::max(ancestor_buffer_range.start, excerpt_buffer_start);
ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end); ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end);
let start = let start = cursor.start() + (ancestor_buffer_range.start - excerpt_buffer_start);
start_after_header + (ancestor_buffer_range.start - excerpt_buffer_start); let end = cursor.start() + (ancestor_buffer_range.end - excerpt_buffer_start);
let end = start_after_header + (ancestor_buffer_range.end - excerpt_buffer_start);
Some(start..end) Some(start..end)
}) })
} }
@ -1737,54 +1614,26 @@ impl Excerpt {
render_header: Option<RenderHeaderFn>, render_header: Option<RenderHeaderFn>,
has_trailing_newline: bool, has_trailing_newline: bool,
) -> Self { ) -> Self {
let mut text_summary =
buffer.text_summary_for_range::<TextSummary, _>(range.to_offset(&buffer));
if header_height > 0 {
text_summary.first_line_chars = 0;
text_summary.lines.row += header_height as u32;
text_summary.lines_utf16.row += header_height as u32;
text_summary.bytes += header_height as usize;
text_summary.longest_row += header_height as u32;
}
Excerpt { Excerpt {
id, id,
text_summary: buffer.text_summary_for_range::<TextSummary, _>(range.to_offset(&buffer)),
buffer_id, buffer_id,
buffer, buffer,
range, range,
text_summary,
header_height, header_height,
render_header, render_header,
has_trailing_newline, has_trailing_newline,
} }
} }
fn header_summary(&self) -> TextSummary {
TextSummary {
bytes: self.header_height as usize,
lines: Point::new(self.header_height as u32, 0),
lines_utf16: PointUtf16::new(self.header_height as u32, 0),
first_line_chars: 0,
last_line_chars: 0,
longest_row: 0,
longest_row_chars: 0,
}
}
fn chunks_in_range<'a>( fn chunks_in_range<'a>(
&'a self, &'a self,
range: Range<usize>, range: Range<usize>,
theme: Option<&'a SyntaxTheme>, theme: Option<&'a SyntaxTheme>,
) -> ExcerptChunks<'a> { ) -> ExcerptChunks<'a> {
let content_start = self.range.start.to_offset(&self.buffer); let content_start = self.range.start.to_offset(&self.buffer);
let chunks_start = content_start + range.start.saturating_sub(self.header_height as usize); let chunks_start = content_start + range.start;
let chunks_end = content_start let chunks_end = content_start + cmp::min(range.end, self.text_summary.bytes);
+ cmp::min(range.end, self.text_summary.bytes)
.saturating_sub(self.header_height as usize);
let header_height = cmp::min(
(self.header_height as usize).saturating_sub(range.start),
range.len(),
);
let footer_height = if self.has_trailing_newline let footer_height = if self.has_trailing_newline
&& range.start <= self.text_summary.bytes && range.start <= self.text_summary.bytes
@ -1798,7 +1647,6 @@ impl Excerpt {
let content_chunks = self.buffer.chunks(chunks_start..chunks_end, theme); let content_chunks = self.buffer.chunks(chunks_start..chunks_end, theme);
ExcerptChunks { ExcerptChunks {
header_height,
content_chunks, content_chunks,
footer_height, footer_height,
} }
@ -1806,16 +1654,8 @@ impl Excerpt {
fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes { fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
let content_start = self.range.start.to_offset(&self.buffer); let content_start = self.range.start.to_offset(&self.buffer);
let bytes_start = content_start + range.start.saturating_sub(self.header_height as usize); let bytes_start = content_start + range.start;
let bytes_end = content_start let bytes_end = content_start + cmp::min(range.end, self.text_summary.bytes);
+ cmp::min(range.end, self.text_summary.bytes)
.saturating_sub(self.header_height as usize);
let header_height = cmp::min(
(self.header_height as usize).saturating_sub(range.start),
range.len(),
);
let footer_height = if self.has_trailing_newline let footer_height = if self.has_trailing_newline
&& range.start <= self.text_summary.bytes && range.start <= self.text_summary.bytes
&& range.end > self.text_summary.bytes && range.end > self.text_summary.bytes
@ -1824,11 +1664,9 @@ impl Excerpt {
} else { } else {
0 0
}; };
let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end); let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
ExcerptBytes { ExcerptBytes {
header_height,
content_bytes, content_bytes,
footer_height, footer_height,
} }
@ -1860,7 +1698,6 @@ impl fmt::Debug for Excerpt {
.field("buffer_id", &self.buffer_id) .field("buffer_id", &self.buffer_id)
.field("range", &self.range) .field("range", &self.range)
.field("text_summary", &self.text_summary) .field("text_summary", &self.text_summary)
.field("header_height", &self.header_height)
.field("has_trailing_newline", &self.has_trailing_newline) .field("has_trailing_newline", &self.has_trailing_newline)
.finish() .finish()
} }
@ -1935,7 +1772,6 @@ impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
impl<'a> MultiBufferRows<'a> { impl<'a> MultiBufferRows<'a> {
pub fn seek(&mut self, row: u32) { pub fn seek(&mut self, row: u32) {
self.header_height = 0;
self.buffer_row_range = 0..0; self.buffer_row_range = 0..0;
self.excerpts self.excerpts
@ -1952,13 +1788,8 @@ impl<'a> MultiBufferRows<'a> {
if let Some(excerpt) = self.excerpts.item() { if let Some(excerpt) = self.excerpts.item() {
let overshoot = row - self.excerpts.start().row; let overshoot = row - self.excerpts.start().row;
let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer).row; let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer).row;
let excerpt_header_height = excerpt.header_height as u32; self.buffer_row_range.start = excerpt_start + overshoot;
self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
self.header_height = excerpt_header_height.saturating_sub(overshoot);
self.buffer_row_range.start =
excerpt_start + overshoot.saturating_sub(excerpt_header_height);
self.buffer_row_range.end =
excerpt_start + excerpt.text_summary.lines.row + 1 - excerpt_header_height;
} }
} }
} }
@ -1968,10 +1799,6 @@ impl<'a> Iterator for MultiBufferRows<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
if self.header_height > 0 {
self.header_height -= 1;
return Some(None);
}
if !self.buffer_row_range.is_empty() { if !self.buffer_row_range.is_empty() {
let row = Some(self.buffer_row_range.start); let row = Some(self.buffer_row_range.start);
self.buffer_row_range.start += 1; self.buffer_row_range.start += 1;
@ -1980,11 +1807,9 @@ impl<'a> Iterator for MultiBufferRows<'a> {
self.excerpts.item()?; self.excerpts.item()?;
self.excerpts.next(&()); self.excerpts.next(&());
let excerpt = self.excerpts.item()?; let 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.start = excerpt.range.start.to_point(&excerpt.buffer).row;
self.buffer_row_range.end = self.buffer_row_range.end =
self.buffer_row_range.start + excerpt.text_summary.lines.row + 1 self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
- self.header_height;
} }
} }
} }
@ -2078,12 +1903,6 @@ impl<'a> Iterator for ExcerptBytes<'a> {
type Item = &'a [u8]; type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.header_height > 0 {
let result = &NEWLINES[..self.header_height];
self.header_height = 0;
return Some(result);
}
if let Some(chunk) = self.content_bytes.next() { if let Some(chunk) = self.content_bytes.next() {
if !chunk.is_empty() { if !chunk.is_empty() {
return Some(chunk); return Some(chunk);
@ -2104,15 +1923,6 @@ impl<'a> Iterator for ExcerptChunks<'a> {
type Item = Chunk<'a>; type Item = Chunk<'a>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.header_height > 0 {
let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.header_height]) };
self.header_height = 0;
return Some(Chunk {
text,
..Default::default()
});
}
if let Some(chunk) = self.content_chunks.next() { if let Some(chunk) = self.content_chunks.next() {
return Some(chunk); return Some(chunk);
} }
@ -2219,7 +2029,7 @@ mod tests {
subscription.consume().into_inner(), subscription.consume().into_inner(),
[Edit { [Edit {
old: 0..0, old: 0..0,
new: 0..12 new: 0..10
}] }]
); );
@ -2244,8 +2054,8 @@ mod tests {
assert_eq!( assert_eq!(
subscription.consume().into_inner(), subscription.consume().into_inner(),
[Edit { [Edit {
old: 12..12, old: 10..10,
new: 12..28 new: 10..22
}] }]
); );
@ -2256,81 +2066,64 @@ mod tests {
assert_eq!( assert_eq!(
snapshot.text(), snapshot.text(),
concat!( concat!(
"\n", // Preserve newlines "bbbb\n", // Preserve newlines
"\n", //
"bbbb\n", //
"ccccc\n", // "ccccc\n", //
"\n", //
"ddd\n", // "ddd\n", //
"eeee\n", // "eeee\n", //
"\n", //
"\n", //
"\n", //
"jj" // "jj" //
) )
); );
assert_eq!( assert_eq!(
snapshot.buffer_rows(0).collect::<Vec<_>>(), snapshot.buffer_rows(0).collect::<Vec<_>>(),
&[ [Some(1), Some(2), Some(3), Some(4), Some(3)]
None,
None,
Some(1),
Some(2),
None,
Some(3),
Some(4),
None,
None,
None,
Some(3)
]
); );
assert_eq!( assert_eq!(
snapshot.buffer_rows(2).collect::<Vec<_>>(), snapshot.buffer_rows(2).collect::<Vec<_>>(),
&[ [Some(3), Some(4), Some(3)]
Some(1),
Some(2),
None,
Some(3),
Some(4),
None,
None,
None,
Some(3)
]
); );
assert_eq!(snapshot.buffer_rows(10).collect::<Vec<_>>(), &[Some(3)]); assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
assert_eq!(snapshot.buffer_rows(11).collect::<Vec<_>>(), &[]); assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
assert_eq!(snapshot.buffer_rows(12).collect::<Vec<_>>(), &[]);
{ {
let snapshot = multibuffer.read(cx).read(cx); let snapshot = multibuffer.read(cx).read(cx);
assert_eq!( assert_eq!(
snapshot snapshot
.excerpt_headers_in_range(0..snapshot.max_point().row + 1) .excerpt_headers_in_range(0..snapshot.max_point().row + 1)
.map(|(rows, render)| (rows, render(cx).name().unwrap().to_string())) .map(|(start_row, header_height, render)| (
start_row,
header_height,
render(cx).name().unwrap().to_string()
))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
&[ &[
(0..2, "header 1".into()), (0, 2, "header 1".into()),
(4..5, "header 2".into()), (2, 1, "header 2".into()),
(7..10, "header 3".into()) (4, 3, "header 3".into())
] ]
); );
assert_eq!( assert_eq!(
snapshot snapshot
.excerpt_headers_in_range(1..5) .excerpt_headers_in_range(1..4)
.map(|(rows, render)| (rows, render(cx).name().unwrap().to_string())) .map(|(start_row, header_height, render)| (
start_row,
header_height,
render(cx).name().unwrap().to_string()
))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
&[(0..2, "header 1".into()), (4..5, "header 2".into())] &[(2, 1, "header 2".into())]
); );
assert_eq!( assert_eq!(
snapshot snapshot
.excerpt_headers_in_range(2..8) .excerpt_headers_in_range(2..5)
.map(|(rows, render)| (rows, render(cx).name().unwrap().to_string())) .map(|(start_row, header_height, render)| (
start_row,
header_height,
render(cx).name().unwrap().to_string()
))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
&[(4..5, "header 2".into()), (7..10, "header 3".into())] &[(2, 1, "header 2".into()), (4, 3, "header 3".into())]
); );
} }
@ -2348,17 +2141,11 @@ mod tests {
assert_eq!( assert_eq!(
multibuffer.read(cx).snapshot(cx).text(), multibuffer.read(cx).snapshot(cx).text(),
concat!( concat!(
"\n", // Preserve newlines "bbbb\n", // Preserve newlines
"\n", //
"bbbb\n", //
"c\n", // "c\n", //
"cc\n", // "cc\n", //
"\n", //
"ddd\n", // "ddd\n", //
"eeee\n", // "eeee\n", //
"\n", //
"\n", //
"\n", //
"jj" // "jj" //
) )
); );
@ -2366,43 +2153,32 @@ mod tests {
assert_eq!( assert_eq!(
subscription.consume().into_inner(), subscription.consume().into_inner(),
[Edit { [Edit {
old: 8..10, old: 6..8,
new: 8..9 new: 6..7
}] }]
); );
// bbbb\nc\ncc\nddd\neeee\njj
let multibuffer = multibuffer.read(cx).snapshot(cx); let multibuffer = multibuffer.read(cx).snapshot(cx);
assert_eq!( assert_eq!(
multibuffer.clip_point(Point::new(0, 0), Bias::Left), multibuffer.clip_point(Point::new(0, 5), Bias::Left),
Point::new(2, 0) Point::new(0, 4)
); );
assert_eq!( assert_eq!(
multibuffer.clip_point(Point::new(0, 0), Bias::Right), multibuffer.clip_point(Point::new(0, 5), Bias::Right),
Point::new(2, 0) Point::new(0, 4)
); );
assert_eq!( assert_eq!(
multibuffer.clip_point(Point::new(1, 0), Bias::Left), multibuffer.clip_point(Point::new(5, 1), Bias::Right),
Point::new(2, 0) Point::new(5, 1)
); );
assert_eq!( assert_eq!(
multibuffer.clip_point(Point::new(1, 0), Bias::Right), multibuffer.clip_point(Point::new(5, 2), Bias::Right),
Point::new(2, 0) Point::new(5, 2)
); );
assert_eq!( assert_eq!(
multibuffer.clip_point(Point::new(8, 0), Bias::Left), multibuffer.clip_point(Point::new(5, 3), Bias::Right),
Point::new(7, 4) Point::new(5, 2)
);
assert_eq!(
multibuffer.clip_point(Point::new(8, 0), Bias::Right),
Point::new(11, 0)
);
assert_eq!(
multibuffer.clip_point(Point::new(9, 0), Bias::Left),
Point::new(7, 4)
);
assert_eq!(
multibuffer.clip_point(Point::new(9, 0), Bias::Right),
Point::new(11, 0)
); );
} }
@ -2464,12 +2240,12 @@ mod tests {
}); });
let old_snapshot = multibuffer.read(cx).snapshot(cx); let old_snapshot = multibuffer.read(cx).snapshot(cx);
assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 1); assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 1); assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
assert_eq!(Anchor::min().to_offset(&old_snapshot), 1); assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
assert_eq!(Anchor::min().to_offset(&old_snapshot), 1); assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
assert_eq!(Anchor::max().to_offset(&old_snapshot), 12); assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
assert_eq!(Anchor::max().to_offset(&old_snapshot), 12); assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
buffer_1.update(cx, |buffer, cx| { buffer_1.update(cx, |buffer, cx| {
buffer.edit([0..0], "W", cx); buffer.edit([0..0], "W", cx);
@ -2481,19 +2257,19 @@ mod tests {
}); });
let new_snapshot = multibuffer.read(cx).snapshot(cx); let new_snapshot = multibuffer.read(cx).snapshot(cx);
assert_eq!(old_snapshot.text(), "\nabcd\n\nefghi"); assert_eq!(old_snapshot.text(), "abcd\nefghi");
assert_eq!(new_snapshot.text(), "\nWabcdX\n\nYefghiZ"); assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 1); assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 2); assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 1); assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2); assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3); assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3); assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
assert_eq!(old_snapshot.anchor_before(7).to_offset(&new_snapshot), 9); assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
assert_eq!(old_snapshot.anchor_after(7).to_offset(&new_snapshot), 10); assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
assert_eq!(old_snapshot.anchor_before(12).to_offset(&new_snapshot), 15); assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
assert_eq!(old_snapshot.anchor_after(12).to_offset(&new_snapshot), 16); assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
} }
#[gpui::test(iterations = 100)] #[gpui::test(iterations = 100)]
@ -2564,15 +2340,10 @@ 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(); let mut expected_buffer_rows = Vec::new();
for (buffer, range, header_height) in &expected_excerpts { for (buffer, range, _) 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 {
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');

View file

@ -38,7 +38,7 @@ impl Point {
pub fn saturating_sub(self, other: Self) -> Self { pub fn saturating_sub(self, other: Self) -> Self {
if self < other { if self < other {
Point::zero() Self::zero()
} else { } else {
self - other self - other
} }

View file

@ -26,6 +26,14 @@ impl PointUtf16 {
pub fn is_zero(&self) -> bool { pub fn is_zero(&self) -> bool {
self.row == 0 && self.column == 0 self.row == 0 && self.column == 0
} }
pub fn saturating_sub(self, other: Self) -> Self {
if self < other {
Self::zero()
} else {
self - other
}
}
} }
impl<'a> Add<&'a Self> for PointUtf16 { impl<'a> Add<&'a Self> for PointUtf16 {