Sketch an initial implementation for block_map::HighlightedChunks

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Nathan Sobo 2021-11-12 14:51:25 -07:00
parent 6f97a9be3b
commit e605a5ead2
2 changed files with 98 additions and 24 deletions

View file

@ -149,7 +149,9 @@ impl Rope {
} }
pub fn offset_to_point(&self, offset: usize) -> Point { pub fn offset_to_point(&self, offset: usize) -> Point {
assert!(offset <= self.summary().bytes); if offset >= self.summary().bytes {
return self.summary().lines;
}
let mut cursor = self.chunks.cursor::<(usize, Point)>(); let mut cursor = self.chunks.cursor::<(usize, Point)>();
cursor.seek(&offset, Bias::Left, &()); cursor.seek(&offset, Bias::Left, &());
let overshoot = offset - cursor.start().0; let overshoot = offset - cursor.start().0;
@ -160,7 +162,9 @@ impl Rope {
} }
pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 { pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 {
assert!(offset <= self.summary().bytes); if offset >= self.summary().bytes {
return self.summary().lines_utf16;
}
let mut cursor = self.chunks.cursor::<(usize, PointUtf16)>(); let mut cursor = self.chunks.cursor::<(usize, PointUtf16)>();
cursor.seek(&offset, Bias::Left, &()); cursor.seek(&offset, Bias::Left, &());
let overshoot = offset - cursor.start().0; let overshoot = offset - cursor.start().0;
@ -171,7 +175,9 @@ impl Rope {
} }
pub fn point_to_offset(&self, point: Point) -> usize { pub fn point_to_offset(&self, point: Point) -> usize {
assert!(point <= self.summary().lines); if point >= self.summary().lines {
return self.summary().bytes;
}
let mut cursor = self.chunks.cursor::<(Point, usize)>(); let mut cursor = self.chunks.cursor::<(Point, usize)>();
cursor.seek(&point, Bias::Left, &()); cursor.seek(&point, Bias::Left, &());
let overshoot = point - cursor.start().0; let overshoot = point - cursor.start().0;
@ -182,7 +188,9 @@ impl Rope {
} }
pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize { pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
assert!(point <= self.summary().lines_utf16); if point >= self.summary().lines_utf16 {
return self.summary().bytes;
}
let mut cursor = self.chunks.cursor::<(PointUtf16, usize)>(); let mut cursor = self.chunks.cursor::<(PointUtf16, usize)>();
cursor.seek(&point, Bias::Left, &()); cursor.seek(&point, Bias::Left, &());
let overshoot = point - cursor.start().0; let overshoot = point - cursor.start().0;

View file

@ -3,6 +3,7 @@ use buffer::{rope, Anchor, Bias, Point, Rope, ToOffset};
use gpui::fonts::HighlightStyle; use gpui::fonts::HighlightStyle;
use language::HighlightedChunk; use language::HighlightedChunk;
use parking_lot::Mutex; use parking_lot::Mutex;
use smol::io::AsyncBufReadExt;
use std::{borrow::Borrow, cmp, collections::HashSet, iter, ops::Range, slice, sync::Arc}; use std::{borrow::Borrow, cmp, collections::HashSet, iter, ops::Range, slice, sync::Arc};
use sum_tree::SumTree; use sum_tree::SumTree;
@ -63,11 +64,11 @@ struct TransformSummary {
} }
struct HighlightedChunks<'a> { struct HighlightedChunks<'a> {
transform_cursor: sum_tree::Cursor<'a, Transform, (OutputRow, InputRow)>, transforms: sum_tree::Cursor<'a, Transform, (OutputRow, InputRow)>,
input_chunks: wrap_map::HighlightedChunks<'a>, input_chunks: wrap_map::HighlightedChunks<'a>,
input_chunk: Option<HighlightedChunk<'a>>, input_chunk: HighlightedChunk<'a>,
block_chunks: Option<BlockChunks<'a>>, block_chunks: Option<BlockChunks<'a>>,
output_position: BlockPoint, output_row: u32,
max_output_row: u32, max_output_row: u32,
} }
@ -163,6 +164,24 @@ impl BlockMap {
} }
} }
impl BlockPoint {
fn row(&self) -> u32 {
self.0.row
}
fn row_mut(&self) -> &mut u32 {
&mut self.0.row
}
fn column(&self) -> u32 {
self.0.column
}
fn column_mut(&self) -> &mut u32 {
&mut self.0.column
}
}
impl<'a> BlockMapWriter<'a> { impl<'a> BlockMapWriter<'a> {
pub fn insert<P, T>( pub fn insert<P, T>(
&self, &self,
@ -202,7 +221,7 @@ impl BlockSnapshot {
input_chunks, input_chunks,
input_chunk: None, input_chunk: None,
block_chunks: None, block_chunks: None,
transform_cursor: cursor, transforms: cursor,
output_position: BlockPoint(Point::new(rows.start, 0)), output_position: BlockPoint(Point::new(rows.start, 0)),
max_output_row: rows.end, max_output_row: rows.end,
} }
@ -258,35 +277,62 @@ impl<'a> Iterator for HighlightedChunks<'a> {
type Item = HighlightedChunk<'a>; type Item = HighlightedChunk<'a>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if let Some(current_block) = self.block_chunks.as_mut() { if self.output_row >= self.max_output_row {
if let Some(chunk) = current_block.next() { return None;
return Some(chunk); }
if let Some(block_chunks) = self.block_chunks.as_mut() {
if let Some(mut block_chunk) = block_chunks.next() {
self.output_row += block_chunk.text.matches('\n').count() as u32;
return Some(block_chunk);
} else { } else {
self.block_chunks.take(); self.block_chunks.take();
} }
} }
let transform = if let Some(item) = self.transform_cursor.item() { let transform = self.transforms.item()?;
item if let Some(block) = transform.block.as_ref() {
} else { let block_start = self.transforms.start().0 .0;
return None; let block_end = self.transforms.end(&()).0 .0;
}; let start_row_in_block = self.output_row - block_start;
let end_row_in_block = cmp::min(self.max_output_row, block_end) - block_start;
if let Some(block) = &transform.block { self.transforms.next(&());
let of let mut block_chunks = BlockChunks::new(block, start_row_in_block..end_row_in_block);
if let Some(block_chunk) = block_chunks.next() {
self.output_row += block_chunk.text.matches('\n').count() as u32;
return Some(block_chunk);
}
} }
None if self.input_chunk.text.is_empty() {
self.input_chunk = self.input_chunks.next().unwrap();
}
let transform_end = self.transforms.end(&()).0 .0;
let (prefix_rows, prefix_bytes) =
offset_for_row(self.input_chunk.text, transform_end - self.output_row);
self.output_row += prefix_rows;
let (prefix, suffix) = self.input_chunk.text.split_at(prefix_bytes);
self.input_chunk.text = suffix;
Some(HighlightedChunk {
text: prefix,
..self.input_chunk
})
} }
} }
impl<'a> BlockChunks<'a> { impl<'a> BlockChunks<'a> {
fn new(block: &'a Block, range: Range<usize>) -> Self { fn new(block: &'a Block, row_range: Range<u32>) -> Self {
let point_range = Point::new(row_range.start, 0)..Point::new(row_range.end, 0);
let offset_range = block.text.point_to_offset(point_range.start)
..block.text.point_to_offset(point_range.end);
let mut runs = block.runs.iter().peekable(); let mut runs = block.runs.iter().peekable();
let mut run_start = 0; let mut run_start = 0;
while let Some((run_len, _)) = runs.peek() { while let Some((run_len, _)) = runs.peek() {
let run_end = run_start + run_len; let run_end = run_start + run_len;
if run_end <= range.start { if run_end <= offset_range.start {
run_start = run_end; run_start = run_end;
runs.next(); runs.next();
} else { } else {
@ -297,9 +343,9 @@ impl<'a> BlockChunks<'a> {
Self { Self {
chunk: None, chunk: None,
run_start, run_start,
chunks: block.text.chunks_in_range(range.clone()), chunks: block.text.chunks_in_range(offset_range.clone()),
runs, runs,
offset: range.start, offset: offset_range.start,
} }
} }
} }
@ -370,6 +416,26 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for OutputRow {
} }
} }
// Count the number of bytes prior to a target row.
// If the string doesn't contain the target row, return the total number of rows it does contain.
// Otherwise return the target row itself.
fn offset_for_row(s: &str, target_row: u32) -> (u32, usize) {
assert!(target_row > 0);
let mut row = 0;
let mut offset = 0;
for (ix, line) in s.split('\n').enumerate() {
if ix > 0 {
row += 1;
offset += 1;
if row as u32 >= target_row {
break;
}
}
offset += line.len();
}
(row, offset)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;