Eliminate non-highlighted chunks APIs

Now we only have a single code path for chunks across all layers, but highlighting is optional and controlled by a flag.

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Nathan Sobo
2021-11-16 16:51:38 -08:00
committed by Max Brunsfeld
co-authored by Max Brunsfeld
parent 7dd9b9539e
commit 52a4c15c14
9 changed files with 206 additions and 379 deletions
+54 -51
View File
@@ -1,7 +1,7 @@
use super::wrap_map::{self, Edit as WrapEdit, Snapshot as WrapSnapshot, WrapPoint};
use buffer::{rope, Anchor, Bias, Edit, Point, Rope, ToOffset, ToPoint as _};
use gpui::{fonts::HighlightStyle, AppContext, ModelHandle};
use language::{Buffer, HighlightedChunk};
use language::{Buffer, Chunk};
use parking_lot::Mutex;
use std::{
cmp::{self, Ordering},
@@ -52,14 +52,14 @@ where
P: Clone,
T: Clone,
{
position: P,
text: T,
runs: Vec<(usize, HighlightStyle)>,
disposition: BlockDisposition,
pub position: P,
pub text: T,
pub runs: Vec<(usize, HighlightStyle)>,
pub disposition: BlockDisposition,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum BlockDisposition {
pub enum BlockDisposition {
Above,
Below,
}
@@ -76,10 +76,10 @@ struct TransformSummary {
output: Point,
}
pub struct HighlightedChunks<'a> {
pub struct Chunks<'a> {
transforms: sum_tree::Cursor<'a, Transform, (BlockPoint, WrapPoint)>,
input_chunks: wrap_map::HighlightedChunks<'a>,
input_chunk: HighlightedChunk<'a>,
input_chunks: wrap_map::Chunks<'a>,
input_chunk: Chunk<'a>,
block_chunks: Option<BlockChunks<'a>>,
output_position: BlockPoint,
max_output_position: BlockPoint,
@@ -433,12 +433,12 @@ impl<'a> BlockMapWriter<'a> {
impl BlockSnapshot {
#[cfg(test)]
fn text(&mut self) -> String {
self.highlighted_chunks_for_rows(0..self.max_point().0.row + 1)
self.chunks(0..self.max_point().0.row + 1, false)
.map(|chunk| chunk.text)
.collect()
}
pub fn highlighted_chunks_for_rows(&mut self, rows: Range<u32>) -> HighlightedChunks {
pub fn chunks(&self, rows: Range<u32>, highlights: bool) -> Chunks {
let max_output_position = self.max_point().min(BlockPoint::new(rows.end, 0));
let mut cursor = self.transforms.cursor::<(BlockPoint, WrapPoint)>();
let output_position = BlockPoint::new(rows.start, 0);
@@ -449,8 +449,8 @@ impl BlockSnapshot {
let input_end_row = self.to_wrap_point(BlockPoint::new(rows.end, 0)).row();
let input_chunks = self
.wrap_snapshot
.highlighted_chunks_for_rows(input_start_row..input_end_row);
HighlightedChunks {
.chunks(input_start_row..input_end_row, highlights);
Chunks {
input_chunks,
input_chunk: Default::default(),
block_chunks: None,
@@ -532,9 +532,9 @@ impl BlockSnapshot {
}
}
pub fn to_block_point(&self, wrap_point: WrapPoint) -> BlockPoint {
pub fn to_block_point(&self, wrap_point: WrapPoint, bias: Bias) -> BlockPoint {
let mut cursor = self.transforms.cursor::<(WrapPoint, BlockPoint)>();
cursor.seek(&wrap_point, Bias::Right, &());
cursor.seek(&wrap_point, bias, &());
while let Some(item) = cursor.item() {
if item.is_isomorphic() {
break;
@@ -581,8 +581,8 @@ impl Transform {
}
}
impl<'a> Iterator for HighlightedChunks<'a> {
type Item = HighlightedChunk<'a>;
impl<'a> Iterator for Chunks<'a> {
type Item = Chunk<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.output_position >= self.max_output_position {
@@ -630,7 +630,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
self.transforms.next(&());
}
Some(HighlightedChunk {
Some(Chunk {
text: prefix,
..self.input_chunk
})
@@ -665,7 +665,7 @@ impl<'a> BlockChunks<'a> {
}
impl<'a> Iterator for BlockChunks<'a> {
type Item = HighlightedChunk<'a>;
type Item = Chunk<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.chunk.is_none() {
@@ -693,7 +693,7 @@ impl<'a> Iterator for BlockChunks<'a> {
Some(suffix)
};
Some(HighlightedChunk {
Some(Chunk {
text: chunk,
highlight_id: Default::default(),
diagnostic: None,
@@ -712,33 +712,36 @@ impl<'a> Iterator for BufferRows<'a> {
let (buffer_row, is_wrapped) = self.input_buffer_row.unwrap();
let in_block = self.in_block;
log::info!(
"============== Iterator next. Output row: {}, Input row: {}, Buffer row: {}, In block {} ===============",
self.output_row,
self.input_row,
buffer_row,
in_block
);
// log::info!(
// "============== next - (output_row: {}, input_row: {}, buffer_row: {}, in_block: {}) ===============",
// self.output_row,
// self.input_row,
// buffer_row,
// in_block
// );
self.output_row += 1;
let output_point = BlockPoint::new(self.output_row, 0);
let transform_end = self.transforms.end(&()).0;
// if output_point > transform_end || output_point == transform_end && in_block {
if output_point >= transform_end {
log::info!(" Calling next once");
// log::info!(" Calling next once");
self.transforms.next(&());
if self.transforms.end(&()).0 < output_point {
log::info!(" Calling next twice");
// log::info!(" Calling next twice");
self.transforms.next(&());
}
self.in_block = self.transforms.item().map_or(false, |t| !t.is_isomorphic());
log::info!(
" Advanced to the next transform (block text: {:?}). Output row: {}, Transform starts at: {:?}",
self.transforms.item().and_then(|t| t.block.as_ref()).map(|b| b.text.to_string()),
self.output_row,
self.transforms.start().1
);
if let Some(transform) = self.transforms.item() {
self.in_block = !transform.is_isomorphic();
}
// log::info!(
// " Advanced to the next transform (block text: {:?}). Output row: {}, Transform starts at: {:?}",
// self.transforms.item().and_then(|t| t.block.as_ref()).map(|b| b.text.to_string()),
// self.output_row,
// self.transforms.start().1
// );
let mut new_input_position = self.transforms.start().1 .0;
if self.transforms.item().map_or(false, |t| t.is_isomorphic()) {
@@ -749,24 +752,24 @@ impl<'a> Iterator for BufferRows<'a> {
if new_input_position.row > self.input_row {
self.input_row = new_input_position.row;
self.input_buffer_row = self.input_buffer_rows.next();
log::info!(
" Advanced the input buffer row. Input row: {}, Input buffer row {:?}",
self.input_row,
self.input_buffer_row
)
// log::info!(
// " Advanced the input buffer row. Input row: {}, Input buffer row {:?}",
// self.input_row,
// self.input_buffer_row
// )
}
} else if self.transforms.item().map_or(true, |t| t.is_isomorphic()) {
self.input_row += 1;
self.input_buffer_row = self.input_buffer_rows.next();
log::info!(
" Advancing in isomorphic transform (off the end: {}). Input row: {}, Input buffer row {:?}",
self.transforms.item().is_none(),
self.input_row,
self.input_buffer_row
)
// log::info!(
// " Advancing in isomorphic transform (off the end: {}). Input row: {}, Input buffer row {:?}",
// self.transforms.item().is_none(),
// self.input_row,
// self.input_buffer_row
// )
}
Some((buffer_row, !is_wrapped && !in_block))
Some((buffer_row, false))
}
}
@@ -886,7 +889,7 @@ mod tests {
"aaa\nBLOCK 1\nBLOCK 2\nbbb\nccc\nddd\nBLOCK 3"
);
assert_eq!(
snapshot.to_block_point(WrapPoint::new(1, 0)),
snapshot.to_block_point(WrapPoint::new(1, 0), Bias::Right),
BlockPoint::new(3, 0)
);
assert_eq!(
@@ -1194,7 +1197,7 @@ mod tests {
}
let soft_wrapped = wraps_snapshot.to_tab_point(WrapPoint::new(row, 0)).column() > 0;
expected_buffer_rows.push((buffer_row, !soft_wrapped));
expected_buffer_rows.push((buffer_row, false));
expected_text.push_str(input_line);
while let Some((_, block)) = sorted_blocks.peek() {
@@ -1215,7 +1218,7 @@ mod tests {
assert_eq!(blocks_snapshot.text(), expected_text);
for row in 0..=blocks_snapshot.wrap_snapshot.max_point().row() {
let wrap_point = WrapPoint::new(row, 0);
let block_point = blocks_snapshot.to_block_point(wrap_point);
let block_point = blocks_snapshot.to_block_point(wrap_point, Bias::Right);
assert_eq!(blocks_snapshot.to_wrap_point(block_point), wrap_point);
}
+21 -84
View File
@@ -1,7 +1,6 @@
use gpui::{AppContext, ModelHandle};
use language::{
Anchor, AnchorRangeExt, Buffer, HighlightId, HighlightedChunk, Point, PointUtf16, TextSummary,
ToOffset,
Anchor, AnchorRangeExt, Buffer, Chunk, HighlightId, Point, PointUtf16, TextSummary, ToOffset,
};
use parking_lot::Mutex;
use std::{
@@ -499,7 +498,9 @@ pub struct Snapshot {
impl Snapshot {
#[cfg(test)]
pub fn text(&self) -> String {
self.chunks_at(FoldOffset(0)).collect()
self.chunks(FoldOffset(0)..self.len(), false)
.map(|c| c.text)
.collect()
}
#[cfg(test)]
@@ -551,7 +552,6 @@ impl Snapshot {
summary
}
#[cfg(test)]
pub fn len(&self) -> FoldOffset {
FoldOffset(self.transforms.summary().output.bytes)
}
@@ -628,21 +628,13 @@ impl Snapshot {
false
}
pub fn chunks_at(&self, offset: FoldOffset) -> Chunks {
let mut transform_cursor = self.transforms.cursor::<(FoldOffset, usize)>();
transform_cursor.seek(&offset, Bias::Right, &());
let overshoot = offset.0 - transform_cursor.start().0 .0;
let buffer_offset = transform_cursor.start().1 + overshoot;
Chunks {
transform_cursor,
buffer_offset,
buffer_chunks: self
.buffer_snapshot
.text_for_range(buffer_offset..self.buffer_snapshot.len()),
}
pub fn chars_at(&self, start: FoldPoint) -> impl '_ + Iterator<Item = char> {
let start = start.to_offset(self);
self.chunks(start..self.len(), false)
.flat_map(|chunk| chunk.text.chars())
}
pub fn highlighted_chunks(&mut self, range: Range<FoldOffset>) -> HighlightedChunks {
pub fn chunks(&self, range: Range<FoldOffset>, enable_highlights: bool) -> Chunks {
let mut transform_cursor = self.transforms.cursor::<(FoldOffset, usize)>();
transform_cursor.seek(&range.end, Bias::Right, &());
@@ -653,21 +645,16 @@ impl Snapshot {
let overshoot = range.start.0 - transform_cursor.start().0 .0;
let buffer_start = transform_cursor.start().1 + overshoot;
HighlightedChunks {
Chunks {
transform_cursor,
buffer_offset: buffer_start,
buffer_chunks: self
.buffer_snapshot
.highlighted_text_for_range(buffer_start..buffer_end),
.chunks(buffer_start..buffer_end, enable_highlights),
buffer_chunk: None,
}
}
pub fn chars_at<'a>(&'a self, point: FoldPoint) -> impl Iterator<Item = char> + 'a {
let offset = point.to_offset(self);
self.chunks_at(offset).flat_map(str::chars)
}
#[cfg(test)]
pub fn clip_offset(&self, offset: FoldOffset, bias: Bias) -> FoldOffset {
let mut cursor = self.transforms.cursor::<(FoldOffset, usize)>();
@@ -948,66 +935,13 @@ impl<'a> Iterator for BufferRows<'a> {
pub struct Chunks<'a> {
transform_cursor: Cursor<'a, Transform, (FoldOffset, usize)>,
buffer_chunks: buffer::Chunks<'a>,
buffer_chunks: language::Chunks<'a>,
buffer_chunk: Option<(usize, Chunk<'a>)>,
buffer_offset: usize,
}
impl<'a> Iterator for Chunks<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
let transform = if let Some(item) = self.transform_cursor.item() {
item
} else {
return None;
};
// If we're in a fold, then return the fold's display text and
// advance the transform and buffer cursors to the end of the fold.
if let Some(output_text) = transform.output_text {
self.buffer_offset += transform.summary.input.bytes;
self.buffer_chunks.seek(self.buffer_offset);
while self.buffer_offset >= self.transform_cursor.end(&()).1
&& self.transform_cursor.item().is_some()
{
self.transform_cursor.next(&());
}
return Some(output_text);
}
// Otherwise, take a chunk from the buffer's text.
if let Some(mut chunk) = self.buffer_chunks.peek() {
let offset_in_chunk = self.buffer_offset - self.buffer_chunks.offset();
chunk = &chunk[offset_in_chunk..];
// Truncate the chunk so that it ends at the next fold.
let region_end = self.transform_cursor.end(&()).1 - self.buffer_offset;
if chunk.len() >= region_end {
chunk = &chunk[0..region_end];
self.transform_cursor.next(&());
} else {
self.buffer_chunks.next();
}
self.buffer_offset += chunk.len();
return Some(chunk);
}
None
}
}
pub struct HighlightedChunks<'a> {
transform_cursor: Cursor<'a, Transform, (FoldOffset, usize)>,
buffer_chunks: language::HighlightedChunks<'a>,
buffer_chunk: Option<(usize, HighlightedChunk<'a>)>,
buffer_offset: usize,
}
impl<'a> Iterator for HighlightedChunks<'a> {
type Item = HighlightedChunk<'a>;
type Item = Chunk<'a>;
fn next(&mut self) -> Option<Self::Item> {
let transform = if let Some(item) = self.transform_cursor.item() {
@@ -1029,7 +963,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
self.transform_cursor.next(&());
}
return Some(HighlightedChunk {
return Some(Chunk {
text: output_text,
highlight_id: HighlightId::default(),
diagnostic: None,
@@ -1428,11 +1362,14 @@ mod tests {
}
for _ in 0..5 {
let offset = snapshot
let start = snapshot
.clip_offset(FoldOffset(rng.gen_range(0..=snapshot.len().0)), Bias::Right);
assert_eq!(
snapshot.chunks_at(offset).collect::<String>(),
&expected_text[offset.0..],
snapshot
.chunks(start..snapshot.len(), false)
.map(|c| c.text)
.collect::<String>(),
&expected_text[start.0..],
);
}
+26 -80
View File
@@ -1,6 +1,6 @@
use super::fold_map::{self, FoldEdit, FoldPoint, Snapshot as FoldSnapshot, ToFoldPoint};
use buffer::Point;
use language::{rope, HighlightedChunk};
use language::{rope, Chunk};
use parking_lot::Mutex;
use std::{mem, ops::Range};
use sum_tree::Bias;
@@ -22,6 +22,7 @@ impl TabMap {
mut fold_edits: Vec<FoldEdit>,
) -> (Snapshot, Vec<Edit>) {
let mut old_snapshot = self.0.lock();
let max_offset = old_snapshot.fold_snapshot.len();
let new_snapshot = Snapshot {
fold_snapshot,
tab_size: old_snapshot.tab_size,
@@ -32,11 +33,11 @@ impl TabMap {
let mut delta = 0;
for chunk in old_snapshot
.fold_snapshot
.chunks_at(fold_edit.old_bytes.end)
.chunks(fold_edit.old_bytes.end..max_offset, false)
{
let patterns: &[_] = &['\t', '\n'];
if let Some(ix) = chunk.find(patterns) {
if &chunk[ix..ix + 1] == "\t" {
if let Some(ix) = chunk.text.find(patterns) {
if &chunk.text[ix..ix + 1] == "\t" {
fold_edit.old_bytes.end.0 += delta + ix + 1;
fold_edit.new_bytes.end.0 += delta + ix + 1;
}
@@ -44,7 +45,7 @@ impl TabMap {
break;
}
delta += chunk.len();
delta += chunk.text.len();
}
}
@@ -110,7 +111,10 @@ impl Snapshot {
let mut first_line_chars = 0;
let mut first_line_bytes = 0;
for c in self.chunks_at(range.start).flat_map(|chunk| chunk.chars()) {
for c in self
.chunks(range.start..self.max_point(), false)
.flat_map(|chunk| chunk.text.chars())
{
if c == '\n'
|| (range.start.row() == range.end.row() && first_line_bytes == range.end.column())
{
@@ -123,8 +127,11 @@ impl Snapshot {
let mut last_line_chars = 0;
let mut last_line_bytes = 0;
for c in self
.chunks_at(TabPoint::new(range.end.row(), 0).max(range.start))
.flat_map(|chunk| chunk.chars())
.chunks(
TabPoint::new(range.end.row(), 0).max(range.start)..self.max_point(),
false,
)
.flat_map(|chunk| chunk.text.chars())
{
if last_line_bytes == range.end.column() {
break;
@@ -146,21 +153,7 @@ impl Snapshot {
self.fold_snapshot.version
}
pub fn chunks_at(&self, point: TabPoint) -> Chunks {
let (point, expanded_char_column, to_next_stop) = self.to_fold_point(point, Bias::Left);
let fold_chunks = self
.fold_snapshot
.chunks_at(point.to_offset(&self.fold_snapshot));
Chunks {
fold_chunks,
column: expanded_char_column,
tab_size: self.tab_size,
chunk: &SPACES[0..to_next_stop],
skip_leading_tab: to_next_stop > 0,
}
}
pub fn highlighted_chunks(&mut self, range: Range<TabPoint>) -> HighlightedChunks {
pub fn chunks(&self, range: Range<TabPoint>, highlights: bool) -> Chunks {
let (input_start, expanded_char_column, to_next_stop) =
self.to_fold_point(range.start, Bias::Left);
let input_start = input_start.to_offset(&self.fold_snapshot);
@@ -168,13 +161,13 @@ impl Snapshot {
.to_fold_point(range.end, Bias::Right)
.0
.to_offset(&self.fold_snapshot);
HighlightedChunks {
Chunks {
fold_chunks: self
.fold_snapshot
.highlighted_chunks(input_start..input_end),
.chunks(input_start..input_end, highlights),
column: expanded_char_column,
tab_size: self.tab_size,
chunk: HighlightedChunk {
chunk: Chunk {
text: &SPACES[0..to_next_stop],
..Default::default()
},
@@ -188,7 +181,9 @@ impl Snapshot {
#[cfg(test)]
pub fn text(&self) -> String {
self.chunks_at(Default::default()).collect()
self.chunks(TabPoint::zero()..self.max_point(), false)
.map(|chunk| chunk.text)
.collect()
}
pub fn max_point(&self) -> TabPoint {
@@ -379,63 +374,14 @@ const SPACES: &'static str = " ";
pub struct Chunks<'a> {
fold_chunks: fold_map::Chunks<'a>,
chunk: &'a str,
chunk: Chunk<'a>,
column: usize,
tab_size: usize,
skip_leading_tab: bool,
}
impl<'a> Iterator for Chunks<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
if self.chunk.is_empty() {
if let Some(chunk) = self.fold_chunks.next() {
self.chunk = chunk;
if self.skip_leading_tab {
self.chunk = &self.chunk[1..];
self.skip_leading_tab = false;
}
} else {
return None;
}
}
for (ix, c) in self.chunk.char_indices() {
match c {
'\t' => {
if ix > 0 {
let (prefix, suffix) = self.chunk.split_at(ix);
self.chunk = suffix;
return Some(prefix);
} else {
self.chunk = &self.chunk[1..];
let len = self.tab_size - self.column % self.tab_size;
self.column += len;
return Some(&SPACES[0..len]);
}
}
'\n' => self.column = 0,
_ => self.column += 1,
}
}
let result = Some(self.chunk);
self.chunk = "";
result
}
}
pub struct HighlightedChunks<'a> {
fold_chunks: fold_map::HighlightedChunks<'a>,
chunk: HighlightedChunk<'a>,
column: usize,
tab_size: usize,
skip_leading_tab: bool,
}
impl<'a> Iterator for HighlightedChunks<'a> {
type Item = HighlightedChunk<'a>;
type Item = Chunk<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.chunk.text.is_empty() {
@@ -456,7 +402,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
if ix > 0 {
let (prefix, suffix) = self.chunk.text.split_at(ix);
self.chunk.text = suffix;
return Some(HighlightedChunk {
return Some(Chunk {
text: prefix,
..self.chunk
});
@@ -464,7 +410,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
self.chunk.text = &self.chunk.text[1..];
let len = self.tab_size - self.column % self.tab_size;
self.column += len;
return Some(HighlightedChunk {
return Some(Chunk {
text: &SPACES[0..len],
..self.chunk
});
+22 -81
View File
@@ -7,7 +7,7 @@ use gpui::{
fonts::FontId, text_layout::LineWrapper, Entity, ModelContext, ModelHandle, MutableAppContext,
Task,
};
use language::{HighlightedChunk, Point};
use language::{Chunk, Point};
use lazy_static::lazy_static;
use smol::future::yield_now;
use std::{collections::VecDeque, mem, ops::Range, time::Duration};
@@ -54,14 +54,7 @@ pub struct WrapPoint(pub super::Point);
pub struct Chunks<'a> {
input_chunks: tab_map::Chunks<'a>,
input_chunk: &'a str,
output_position: WrapPoint,
transforms: Cursor<'a, Transform, (WrapPoint, TabPoint)>,
}
pub struct HighlightedChunks<'a> {
input_chunks: tab_map::HighlightedChunks<'a>,
input_chunk: HighlightedChunk<'a>,
input_chunk: Chunk<'a>,
output_position: WrapPoint,
max_output_row: u32,
transforms: Cursor<'a, Transform, (WrapPoint, TabPoint)>,
@@ -430,10 +423,15 @@ impl Snapshot {
let mut line = String::new();
let mut remaining = None;
let mut chunks = new_tab_snapshot.chunks_at(TabPoint::new(edit.new_rows.start, 0));
let mut chunks = new_tab_snapshot.chunks(
TabPoint::new(edit.new_rows.start, 0)..new_tab_snapshot.max_point(),
false,
);
let mut edit_transforms = Vec::<Transform>::new();
for _ in edit.new_rows.start..edit.new_rows.end {
while let Some(chunk) = remaining.take().or_else(|| chunks.next()) {
while let Some(chunk) =
remaining.take().or_else(|| chunks.next().map(|c| c.text))
{
if let Some(ix) = chunk.find('\n') {
line.push_str(&chunk[..ix + 1]);
remaining = Some(&chunk[ix + 1..]);
@@ -552,24 +550,12 @@ impl Snapshot {
unsafe { Patch::new_unchecked(wrap_edits) }
}
pub fn chunks_at(&self, wrap_row: u32) -> Chunks {
let point = WrapPoint::new(wrap_row, 0);
let mut transforms = self.transforms.cursor::<(WrapPoint, TabPoint)>();
transforms.seek(&point, Bias::Right, &());
let mut input_position = TabPoint(transforms.start().1 .0);
if transforms.item().map_or(false, |t| t.is_isomorphic()) {
input_position.0 += point.0 - transforms.start().0 .0;
}
let input_chunks = self.tab_snapshot.chunks_at(input_position);
Chunks {
input_chunks,
transforms,
output_position: point,
input_chunk: "",
}
pub fn text_chunks(&self, wrap_row: u32) -> impl Iterator<Item = &str> {
self.chunks(wrap_row..self.max_point().row() + 1, false)
.map(|h| h.text)
}
pub fn highlighted_chunks_for_rows(&mut self, rows: Range<u32>) -> HighlightedChunks {
pub fn chunks(&self, rows: Range<u32>, highlights: bool) -> Chunks {
let output_start = WrapPoint::new(rows.start, 0);
let output_end = WrapPoint::new(rows.end, 0);
let mut transforms = self.transforms.cursor::<(WrapPoint, TabPoint)>();
@@ -581,8 +567,8 @@ impl Snapshot {
let input_end = self
.to_tab_point(output_end)
.min(self.tab_snapshot.max_point());
HighlightedChunks {
input_chunks: self.tab_snapshot.highlighted_chunks(input_start..input_end),
Chunks {
input_chunks: self.tab_snapshot.chunks(input_start..input_end, highlights),
input_chunk: Default::default(),
output_position: output_start,
max_output_row: rows.end,
@@ -600,7 +586,7 @@ impl Snapshot {
pub fn line_len(&self, row: u32) -> u32 {
let mut len = 0;
for chunk in self.chunks_at(row) {
for chunk in self.text_chunks(row) {
if let Some(newline_ix) = chunk.find('\n') {
len += newline_ix;
break;
@@ -733,52 +719,7 @@ impl Snapshot {
}
impl<'a> Iterator for Chunks<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
let transform = self.transforms.item()?;
if let Some(display_text) = transform.display_text {
if self.output_position > self.transforms.start().0 {
self.output_position.0.column += transform.summary.output.lines.column;
self.transforms.next(&());
return Some(&display_text[1..]);
} else {
self.output_position.0 += transform.summary.output.lines;
self.transforms.next(&());
return Some(display_text);
}
}
if self.input_chunk.is_empty() {
self.input_chunk = self.input_chunks.next().unwrap();
}
let mut input_len = 0;
let transform_end = self.transforms.end(&()).0;
for c in self.input_chunk.chars() {
let char_len = c.len_utf8();
input_len += char_len;
if c == '\n' {
*self.output_position.row_mut() += 1;
*self.output_position.column_mut() = 0;
} else {
*self.output_position.column_mut() += char_len as u32;
}
if self.output_position >= transform_end {
self.transforms.next(&());
break;
}
}
let (prefix, suffix) = self.input_chunk.split_at(input_len);
self.input_chunk = suffix;
Some(prefix)
}
}
impl<'a> Iterator for HighlightedChunks<'a> {
type Item = HighlightedChunk<'a>;
type Item = Chunk<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.output_position.row() >= self.max_output_row {
@@ -803,7 +744,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
self.output_position.0 += summary;
self.transforms.next(&());
return Some(HighlightedChunk {
return Some(Chunk {
text: &display_text[start_ix..end_ix],
..self.input_chunk
});
@@ -833,7 +774,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
let (prefix, suffix) = self.input_chunk.text.split_at(input_len);
self.input_chunk.text = suffix;
Some(HighlightedChunk {
Some(Chunk {
text: prefix,
..self.input_chunk
})
@@ -1216,7 +1157,7 @@ mod tests {
impl Snapshot {
pub fn text(&self) -> String {
self.chunks_at(0).collect()
self.text_chunks(0).collect()
}
fn verify_chunks(&mut self, rng: &mut impl Rng) {
@@ -1225,7 +1166,7 @@ mod tests {
let start_row = rng.gen_range(0..=end_row);
end_row += 1;
let mut expected_text = self.chunks_at(start_row).collect::<String>();
let mut expected_text = self.text_chunks(start_row).collect::<String>();
if expected_text.ends_with("\n") {
expected_text.push('\n');
}
@@ -1239,7 +1180,7 @@ mod tests {
}
let actual_text = self
.highlighted_chunks_for_rows(start_row..end_row)
.chunks(start_row..end_row, false)
.map(|c| c.text)
.collect::<String>();
assert_eq!(