mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-25 01:34:02 +00:00
Sketch an initial implementation for block_map::HighlightedChunks
Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
6f97a9be3b
commit
e605a5ead2
2 changed files with 98 additions and 24 deletions
|
@ -149,7 +149,9 @@ impl Rope {
|
|||
}
|
||||
|
||||
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)>();
|
||||
cursor.seek(&offset, Bias::Left, &());
|
||||
let overshoot = offset - cursor.start().0;
|
||||
|
@ -160,7 +162,9 @@ impl Rope {
|
|||
}
|
||||
|
||||
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)>();
|
||||
cursor.seek(&offset, Bias::Left, &());
|
||||
let overshoot = offset - cursor.start().0;
|
||||
|
@ -171,7 +175,9 @@ impl Rope {
|
|||
}
|
||||
|
||||
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)>();
|
||||
cursor.seek(&point, Bias::Left, &());
|
||||
let overshoot = point - cursor.start().0;
|
||||
|
@ -182,7 +188,9 @@ impl Rope {
|
|||
}
|
||||
|
||||
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)>();
|
||||
cursor.seek(&point, Bias::Left, &());
|
||||
let overshoot = point - cursor.start().0;
|
||||
|
|
|
@ -3,6 +3,7 @@ use buffer::{rope, Anchor, Bias, Point, Rope, ToOffset};
|
|||
use gpui::fonts::HighlightStyle;
|
||||
use language::HighlightedChunk;
|
||||
use parking_lot::Mutex;
|
||||
use smol::io::AsyncBufReadExt;
|
||||
use std::{borrow::Borrow, cmp, collections::HashSet, iter, ops::Range, slice, sync::Arc};
|
||||
use sum_tree::SumTree;
|
||||
|
||||
|
@ -63,11 +64,11 @@ struct TransformSummary {
|
|||
}
|
||||
|
||||
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_chunk: Option<HighlightedChunk<'a>>,
|
||||
input_chunk: HighlightedChunk<'a>,
|
||||
block_chunks: Option<BlockChunks<'a>>,
|
||||
output_position: BlockPoint,
|
||||
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> {
|
||||
pub fn insert<P, T>(
|
||||
&self,
|
||||
|
@ -202,7 +221,7 @@ impl BlockSnapshot {
|
|||
input_chunks,
|
||||
input_chunk: None,
|
||||
block_chunks: None,
|
||||
transform_cursor: cursor,
|
||||
transforms: cursor,
|
||||
output_position: BlockPoint(Point::new(rows.start, 0)),
|
||||
max_output_row: rows.end,
|
||||
}
|
||||
|
@ -258,35 +277,62 @@ impl<'a> Iterator for HighlightedChunks<'a> {
|
|||
type Item = HighlightedChunk<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(current_block) = self.block_chunks.as_mut() {
|
||||
if let Some(chunk) = current_block.next() {
|
||||
return Some(chunk);
|
||||
if self.output_row >= self.max_output_row {
|
||||
return None;
|
||||
}
|
||||
|
||||
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 {
|
||||
self.block_chunks.take();
|
||||
}
|
||||
}
|
||||
|
||||
let transform = if let Some(item) = self.transform_cursor.item() {
|
||||
item
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if let Some(block) = &transform.block {
|
||||
let of
|
||||
let transform = self.transforms.item()?;
|
||||
if let Some(block) = transform.block.as_ref() {
|
||||
let block_start = self.transforms.start().0 .0;
|
||||
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;
|
||||
self.transforms.next(&());
|
||||
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> {
|
||||
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 run_start = 0;
|
||||
while let Some((run_len, _)) = runs.peek() {
|
||||
let run_end = run_start + run_len;
|
||||
if run_end <= range.start {
|
||||
if run_end <= offset_range.start {
|
||||
run_start = run_end;
|
||||
runs.next();
|
||||
} else {
|
||||
|
@ -297,9 +343,9 @@ impl<'a> BlockChunks<'a> {
|
|||
Self {
|
||||
chunk: None,
|
||||
run_start,
|
||||
chunks: block.text.chunks_in_range(range.clone()),
|
||||
chunks: block.text.chunks_in_range(offset_range.clone()),
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
Loading…
Reference in a new issue