Make block insertion work in simple cases
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
2e61a586b6
commit
c278503166
2 changed files with 229 additions and 31 deletions
|
@ -55,6 +55,7 @@ impl DisplayMap {
|
||||||
let (wraps_snapshot, _) = self
|
let (wraps_snapshot, _) = self
|
||||||
.wrap_map
|
.wrap_map
|
||||||
.update(cx, |map, cx| map.sync(tabs_snapshot.clone(), edits, cx));
|
.update(cx, |map, cx| map.sync(tabs_snapshot.clone(), edits, cx));
|
||||||
|
|
||||||
DisplayMapSnapshot {
|
DisplayMapSnapshot {
|
||||||
buffer_snapshot: self.buffer.read(cx).snapshot(),
|
buffer_snapshot: self.buffer.read(cx).snapshot(),
|
||||||
folds_snapshot,
|
folds_snapshot,
|
||||||
|
|
|
@ -1,13 +1,26 @@
|
||||||
use super::wrap_map::{self, Edit as WrapEdit, Snapshot as WrapSnapshot, WrapPoint};
|
use super::wrap_map::{self, Edit as WrapEdit, Snapshot as WrapSnapshot, WrapPoint};
|
||||||
use buffer::{rope, Anchor, Bias, Point, Rope, ToOffset};
|
use buffer::{rope, Anchor, Bias, Edit, Point, Rope, ToOffset, ToPoint as _};
|
||||||
use gpui::fonts::HighlightStyle;
|
use gpui::{fonts::HighlightStyle, AppContext, ModelHandle};
|
||||||
use language::HighlightedChunk;
|
use language::{Buffer, HighlightedChunk};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{cmp, collections::HashSet, iter, ops::Range, slice, sync::Arc};
|
use std::{
|
||||||
|
cmp,
|
||||||
|
collections::HashSet,
|
||||||
|
iter,
|
||||||
|
ops::Range,
|
||||||
|
slice,
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||||
|
Arc,
|
||||||
|
},
|
||||||
|
};
|
||||||
use sum_tree::SumTree;
|
use sum_tree::SumTree;
|
||||||
|
|
||||||
struct BlockMap {
|
struct BlockMap {
|
||||||
blocks: Vec<(BlockId, Arc<Block>)>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
next_block_id: AtomicUsize,
|
||||||
|
wrap_snapshot: Mutex<WrapSnapshot>,
|
||||||
|
blocks: Vec<Arc<Block>>,
|
||||||
transforms: Mutex<SumTree<Transform>>,
|
transforms: Mutex<SumTree<Transform>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +37,7 @@ struct BlockId(usize);
|
||||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||||
pub struct BlockPoint(super::Point);
|
pub struct BlockPoint(super::Point);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct Block {
|
struct Block {
|
||||||
id: BlockId,
|
id: BlockId,
|
||||||
position: Anchor,
|
position: Anchor,
|
||||||
|
@ -44,13 +58,13 @@ where
|
||||||
disposition: BlockDisposition,
|
disposition: BlockDisposition,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
enum BlockDisposition {
|
enum BlockDisposition {
|
||||||
Above,
|
Above,
|
||||||
Below,
|
Below,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
struct Transform {
|
struct Transform {
|
||||||
summary: TransformSummary,
|
summary: TransformSummary,
|
||||||
block: Option<Arc<Block>>,
|
block: Option<Arc<Block>>,
|
||||||
|
@ -86,34 +100,53 @@ struct InputRow(u32);
|
||||||
struct OutputRow(u32);
|
struct OutputRow(u32);
|
||||||
|
|
||||||
impl BlockMap {
|
impl BlockMap {
|
||||||
fn new(wrap_snapshot: WrapSnapshot) -> Self {
|
fn new(buffer: ModelHandle<Buffer>, wrap_snapshot: WrapSnapshot) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
buffer,
|
||||||
|
next_block_id: AtomicUsize::new(0),
|
||||||
blocks: Vec::new(),
|
blocks: Vec::new(),
|
||||||
transforms: Mutex::new(SumTree::from_item(
|
transforms: Mutex::new(SumTree::from_item(
|
||||||
Transform::isomorphic(wrap_snapshot.max_point().row() + 1),
|
Transform::isomorphic(wrap_snapshot.max_point().row() + 1),
|
||||||
&(),
|
&(),
|
||||||
)),
|
)),
|
||||||
|
wrap_snapshot: Mutex::new(wrap_snapshot),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&self, wrap_snapshot: WrapSnapshot, edits: Vec<WrapEdit>) -> BlockSnapshot {
|
fn read(
|
||||||
self.sync(&wrap_snapshot, edits);
|
&self,
|
||||||
|
wrap_snapshot: WrapSnapshot,
|
||||||
|
edits: Vec<WrapEdit>,
|
||||||
|
cx: &AppContext,
|
||||||
|
) -> BlockSnapshot {
|
||||||
|
self.apply_edits(&wrap_snapshot, edits, cx);
|
||||||
|
*self.wrap_snapshot.lock() = wrap_snapshot.clone();
|
||||||
BlockSnapshot {
|
BlockSnapshot {
|
||||||
wrap_snapshot,
|
wrap_snapshot,
|
||||||
transforms: self.transforms.lock().clone(),
|
transforms: self.transforms.lock().clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, wrap_snapshot: WrapSnapshot, edits: Vec<WrapEdit>) -> BlockMapWriter {
|
fn write(
|
||||||
self.sync(&wrap_snapshot, edits);
|
&mut self,
|
||||||
|
wrap_snapshot: WrapSnapshot,
|
||||||
|
edits: Vec<WrapEdit>,
|
||||||
|
cx: &AppContext,
|
||||||
|
) -> BlockMapWriter {
|
||||||
|
self.apply_edits(&wrap_snapshot, edits, cx);
|
||||||
|
*self.wrap_snapshot.lock() = wrap_snapshot;
|
||||||
BlockMapWriter(self)
|
BlockMapWriter(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync(&self, wrap_snapshot: &WrapSnapshot, edits: Vec<WrapEdit>) {
|
fn apply_edits(&self, wrap_snapshot: &WrapSnapshot, edits: Vec<WrapEdit>, cx: &AppContext) {
|
||||||
|
let buffer = self.buffer.read(cx);
|
||||||
let mut transforms = self.transforms.lock();
|
let mut transforms = self.transforms.lock();
|
||||||
let mut new_transforms = SumTree::new();
|
let mut new_transforms = SumTree::new();
|
||||||
let mut cursor = transforms.cursor::<InputRow>();
|
let mut cursor = transforms.cursor::<InputRow>();
|
||||||
let mut edits = edits.into_iter().peekable();
|
let mut edits = edits.into_iter().peekable();
|
||||||
|
let mut last_block_ix = 0;
|
||||||
|
let mut blocks_in_edit = Vec::new();
|
||||||
|
|
||||||
while let Some(mut edit) = edits.next() {
|
while let Some(mut edit) = edits.next() {
|
||||||
new_transforms.push_tree(
|
new_transforms.push_tree(
|
||||||
cursor.slice(&InputRow(edit.old.start), Bias::Left, &()),
|
cursor.slice(&InputRow(edit.old.start), Bias::Left, &()),
|
||||||
|
@ -147,7 +180,45 @@ impl BlockMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: process injections
|
let start_anchor = buffer.anchor_before(Point::new(edit.new.start, 0));
|
||||||
|
let end_anchor = buffer.anchor_after(Point::new(edit.new.end, 0));
|
||||||
|
let start_block_ix = match self.blocks[last_block_ix..]
|
||||||
|
.binary_search_by(|probe| probe.position.cmp(&start_anchor, buffer).unwrap())
|
||||||
|
{
|
||||||
|
Ok(ix) | Err(ix) => last_block_ix + ix,
|
||||||
|
};
|
||||||
|
let end_block_ix = match self.blocks[start_block_ix..]
|
||||||
|
.binary_search_by(|probe| probe.position.cmp(&end_anchor, buffer).unwrap())
|
||||||
|
{
|
||||||
|
Ok(ix) | Err(ix) => start_block_ix + ix,
|
||||||
|
};
|
||||||
|
last_block_ix = end_block_ix;
|
||||||
|
|
||||||
|
blocks_in_edit.clear();
|
||||||
|
blocks_in_edit.extend(
|
||||||
|
self.blocks[start_block_ix..end_block_ix]
|
||||||
|
.iter()
|
||||||
|
.map(|block| (block.position.to_point(buffer).row, block)),
|
||||||
|
);
|
||||||
|
blocks_in_edit.sort_unstable_by_key(|(row, block)| (*row, block.disposition));
|
||||||
|
|
||||||
|
for (row, block) in blocks_in_edit.iter().copied() {
|
||||||
|
let insertion_row = if block.disposition.is_above() {
|
||||||
|
row
|
||||||
|
} else {
|
||||||
|
row + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_transforms_end = new_transforms.summary().input_rows;
|
||||||
|
if new_transforms_end < insertion_row {
|
||||||
|
new_transforms.push(
|
||||||
|
Transform::isomorphic(insertion_row - new_transforms_end),
|
||||||
|
&(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_transforms.push(Transform::block(block.clone()), &());
|
||||||
|
}
|
||||||
|
|
||||||
let new_transforms_end = new_transforms.summary().input_rows;
|
let new_transforms_end = new_transforms.summary().input_rows;
|
||||||
if new_transforms_end < edit.new.end {
|
if new_transforms_end < edit.new.end {
|
||||||
|
@ -183,14 +254,58 @@ impl BlockPoint {
|
||||||
|
|
||||||
impl<'a> BlockMapWriter<'a> {
|
impl<'a> BlockMapWriter<'a> {
|
||||||
pub fn insert<P, T>(
|
pub fn insert<P, T>(
|
||||||
&self,
|
&mut self,
|
||||||
blocks: impl IntoIterator<Item = BlockProperties<P, T>>,
|
blocks: impl IntoIterator<Item = BlockProperties<P, T>>,
|
||||||
|
cx: &AppContext,
|
||||||
) -> Vec<BlockId>
|
) -> Vec<BlockId>
|
||||||
where
|
where
|
||||||
P: ToOffset + Clone,
|
P: ToOffset + Clone,
|
||||||
T: Into<Rope> + Clone,
|
T: Into<Rope> + Clone,
|
||||||
{
|
{
|
||||||
vec![]
|
let buffer = self.0.buffer.read(cx);
|
||||||
|
let mut ids = Vec::new();
|
||||||
|
let mut edits = Vec::<Edit<u32>>::new();
|
||||||
|
|
||||||
|
for block in blocks {
|
||||||
|
let id = BlockId(self.0.next_block_id.fetch_add(1, SeqCst));
|
||||||
|
ids.push(id);
|
||||||
|
|
||||||
|
let position = buffer.anchor_before(block.position);
|
||||||
|
let row = position.to_point(buffer).row;
|
||||||
|
|
||||||
|
let block_ix = match self
|
||||||
|
.0
|
||||||
|
.blocks
|
||||||
|
.binary_search_by(|probe| probe.position.cmp(&position, buffer).unwrap())
|
||||||
|
{
|
||||||
|
Ok(ix) | Err(ix) => ix,
|
||||||
|
};
|
||||||
|
let mut text = block.text.into();
|
||||||
|
text.push("\n");
|
||||||
|
self.0.blocks.insert(
|
||||||
|
block_ix,
|
||||||
|
Arc::new(Block {
|
||||||
|
id,
|
||||||
|
position,
|
||||||
|
text,
|
||||||
|
runs: block.runs,
|
||||||
|
disposition: block.disposition,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(edit_ix) = edits.binary_search_by_key(&row, |edit| edit.old.start) {
|
||||||
|
edits.insert(
|
||||||
|
edit_ix,
|
||||||
|
Edit {
|
||||||
|
old: row..(row + 1),
|
||||||
|
new: row..(row + 1),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.0.apply_edits(&*self.0.wrap_snapshot.lock(), edits, cx);
|
||||||
|
ids
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&self, ids: HashSet<BlockId>) {
|
pub fn remove(&self, ids: HashSet<BlockId>) {
|
||||||
|
@ -269,6 +384,16 @@ impl Transform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn block(block: Arc<Block>) -> Self {
|
||||||
|
Self {
|
||||||
|
summary: TransformSummary {
|
||||||
|
input_rows: 0,
|
||||||
|
output_rows: block.text.summary().lines.row,
|
||||||
|
},
|
||||||
|
block: Some(block),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn is_isomorphic(&self) -> bool {
|
fn is_isomorphic(&self) -> bool {
|
||||||
self.block.is_none()
|
self.block.is_none()
|
||||||
}
|
}
|
||||||
|
@ -283,7 +408,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(block_chunks) = self.block_chunks.as_mut() {
|
if let Some(block_chunks) = self.block_chunks.as_mut() {
|
||||||
if let Some(mut block_chunk) = block_chunks.next() {
|
if let Some(block_chunk) = block_chunks.next() {
|
||||||
self.output_row += block_chunk.text.matches('\n').count() as u32;
|
self.output_row += block_chunk.text.matches('\n').count() as u32;
|
||||||
return Some(block_chunk);
|
return Some(block_chunk);
|
||||||
} else {
|
} else {
|
||||||
|
@ -306,7 +431,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.input_chunk.text.is_empty() {
|
if self.input_chunk.text.is_empty() {
|
||||||
self.input_chunk = self.input_chunks.next().unwrap();
|
self.input_chunk = self.input_chunks.next()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let transform_end = self.transforms.end(&()).0 .0;
|
let transform_end = self.transforms.end(&()).0 .0;
|
||||||
|
@ -314,8 +439,11 @@ impl<'a> Iterator for HighlightedChunks<'a> {
|
||||||
offset_for_row(self.input_chunk.text, transform_end - self.output_row);
|
offset_for_row(self.input_chunk.text, transform_end - self.output_row);
|
||||||
self.output_row += prefix_rows;
|
self.output_row += prefix_rows;
|
||||||
let (prefix, suffix) = self.input_chunk.text.split_at(prefix_bytes);
|
let (prefix, suffix) = self.input_chunk.text.split_at(prefix_bytes);
|
||||||
|
|
||||||
self.input_chunk.text = suffix;
|
self.input_chunk.text = suffix;
|
||||||
|
if self.output_row == transform_end {
|
||||||
|
self.transforms.next(&());
|
||||||
|
}
|
||||||
|
|
||||||
Some(HighlightedChunk {
|
Some(HighlightedChunk {
|
||||||
text: prefix,
|
text: prefix,
|
||||||
..self.input_chunk
|
..self.input_chunk
|
||||||
|
@ -417,20 +545,25 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for OutputRow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BlockDisposition {
|
||||||
|
fn is_above(&self) -> bool {
|
||||||
|
matches!(self, BlockDisposition::Above)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Count the number of bytes prior to a target row.
|
// 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.
|
// If the string doesn't contain the target row, return the total number of rows it does contain.
|
||||||
// Otherwise return the target row itself.
|
// Otherwise return the target row itself.
|
||||||
fn offset_for_row(s: &str, target_row: u32) -> (u32, usize) {
|
fn offset_for_row(s: &str, target_row: u32) -> (u32, usize) {
|
||||||
assert!(target_row > 0);
|
|
||||||
let mut row = 0;
|
let mut row = 0;
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
for (ix, line) in s.split('\n').enumerate() {
|
for (ix, line) in s.split('\n').enumerate() {
|
||||||
if ix > 0 {
|
if ix > 0 {
|
||||||
row += 1;
|
row += 1;
|
||||||
offset += 1;
|
offset += 1;
|
||||||
if row as u32 >= target_row {
|
}
|
||||||
break;
|
if row as u32 >= target_row {
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
offset += line.len();
|
offset += line.len();
|
||||||
}
|
}
|
||||||
|
@ -441,13 +574,78 @@ fn offset_for_row(s: &str, target_row: u32) -> (u32, usize) {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::display_map::{fold_map::FoldMap, tab_map::TabMap, wrap_map::WrapMap};
|
use crate::display_map::{fold_map::FoldMap, tab_map::TabMap, wrap_map::WrapMap};
|
||||||
use buffer::{RandomCharIter, ToPoint as _};
|
use buffer::RandomCharIter;
|
||||||
use language::Buffer;
|
use language::Buffer;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn test_basic_blocks(cx: &mut gpui::MutableAppContext) {
|
||||||
|
let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap();
|
||||||
|
let font_id = cx
|
||||||
|
.font_cache()
|
||||||
|
.select_font(family_id, &Default::default())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let text = "aaa\nbbb\nccc\nddd\n";
|
||||||
|
|
||||||
|
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
|
||||||
|
let (fold_map, folds_snapshot) = FoldMap::new(buffer.clone(), cx);
|
||||||
|
let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1);
|
||||||
|
let (wrap_map, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, None, cx);
|
||||||
|
let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot.clone());
|
||||||
|
|
||||||
|
let mut writer = block_map.write(wraps_snapshot.clone(), vec![], cx);
|
||||||
|
writer.insert(
|
||||||
|
vec![
|
||||||
|
BlockProperties {
|
||||||
|
position: Point::new(1, 0),
|
||||||
|
text: "BLOCK 1",
|
||||||
|
disposition: BlockDisposition::Above,
|
||||||
|
runs: vec![],
|
||||||
|
},
|
||||||
|
BlockProperties {
|
||||||
|
position: Point::new(1, 2),
|
||||||
|
text: "BLOCK 2",
|
||||||
|
disposition: BlockDisposition::Above,
|
||||||
|
runs: vec![],
|
||||||
|
},
|
||||||
|
BlockProperties {
|
||||||
|
position: Point::new(3, 2),
|
||||||
|
text: "BLOCK 3",
|
||||||
|
disposition: BlockDisposition::Below,
|
||||||
|
runs: vec![],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut snapshot = block_map.read(wraps_snapshot, vec![], cx);
|
||||||
|
assert_eq!(
|
||||||
|
snapshot.text(),
|
||||||
|
"aaa\nBLOCK 1\nBLOCK 2\nbbb\nccc\nddd\nBLOCK 3\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Insert a line break, separating two block decorations into separate
|
||||||
|
// lines.
|
||||||
|
buffer.update(cx, |buffer, cx| {
|
||||||
|
buffer.edit([Point::new(1, 1)..Point::new(1, 1)], "!!!\n", cx)
|
||||||
|
});
|
||||||
|
|
||||||
|
let (folds_snapshot, fold_edits) = fold_map.read(cx);
|
||||||
|
let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits);
|
||||||
|
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||||
|
wrap_map.sync(tabs_snapshot, tab_edits, cx)
|
||||||
|
});
|
||||||
|
let mut snapshot = block_map.read(wraps_snapshot, wrap_edits, cx);
|
||||||
|
assert_eq!(
|
||||||
|
snapshot.text(),
|
||||||
|
"aaa\nBLOCK 1\nb!!!\nBLOCK 2\nbb\nccc\nddd\nBLOCK 3\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test(iterations = 100)]
|
#[gpui::test(iterations = 100)]
|
||||||
fn test_random(cx: &mut gpui::MutableAppContext, mut rng: StdRng) {
|
fn test_random_blocks(cx: &mut gpui::MutableAppContext, mut rng: StdRng) {
|
||||||
let operations = env::var("OPERATIONS")
|
let operations = env::var("OPERATIONS")
|
||||||
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
|
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
|
||||||
.unwrap_or(10);
|
.unwrap_or(10);
|
||||||
|
@ -461,7 +659,6 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let font_size = 14.0;
|
let font_size = 14.0;
|
||||||
|
|
||||||
log::info!("Tab size: {}", tab_size);
|
|
||||||
log::info!("Wrap width: {:?}", wrap_width);
|
log::info!("Wrap width: {:?}", wrap_width);
|
||||||
|
|
||||||
let buffer = cx.add_model(|cx| {
|
let buffer = cx.add_model(|cx| {
|
||||||
|
@ -473,7 +670,7 @@ mod tests {
|
||||||
let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), tab_size);
|
let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), tab_size);
|
||||||
let (wrap_map, wraps_snapshot) =
|
let (wrap_map, wraps_snapshot) =
|
||||||
WrapMap::new(tabs_snapshot, font_id, font_size, wrap_width, cx);
|
WrapMap::new(tabs_snapshot, font_id, font_size, wrap_width, cx);
|
||||||
let mut block_map = BlockMap::new(wraps_snapshot);
|
let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot);
|
||||||
let mut expected_blocks = Vec::new();
|
let mut expected_blocks = Vec::new();
|
||||||
|
|
||||||
for _ in 0..operations {
|
for _ in 0..operations {
|
||||||
|
@ -519,11 +716,11 @@ mod tests {
|
||||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||||
wrap_map.sync(tabs_snapshot, tab_edits, cx)
|
wrap_map.sync(tabs_snapshot, tab_edits, cx)
|
||||||
});
|
});
|
||||||
let block_map = block_map.write(wraps_snapshot, wrap_edits);
|
let mut block_map = block_map.write(wraps_snapshot, wrap_edits, cx);
|
||||||
|
|
||||||
expected_blocks.extend(
|
expected_blocks.extend(
|
||||||
block_map
|
block_map
|
||||||
.insert(block_properties.clone())
|
.insert(block_properties.clone(), cx)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(block_properties),
|
.zip(block_properties),
|
||||||
);
|
);
|
||||||
|
@ -543,7 +740,7 @@ mod tests {
|
||||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||||
wrap_map.sync(tabs_snapshot, tab_edits, cx)
|
wrap_map.sync(tabs_snapshot, tab_edits, cx)
|
||||||
});
|
});
|
||||||
let block_map = block_map.write(wraps_snapshot, wrap_edits);
|
let block_map = block_map.write(wraps_snapshot, wrap_edits, cx);
|
||||||
|
|
||||||
block_map.remove(block_ids_to_remove);
|
block_map.remove(block_ids_to_remove);
|
||||||
}
|
}
|
||||||
|
@ -557,7 +754,7 @@ mod tests {
|
||||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||||
wrap_map.sync(tabs_snapshot, tab_edits, cx)
|
wrap_map.sync(tabs_snapshot, tab_edits, cx)
|
||||||
});
|
});
|
||||||
let mut blocks_snapshot = block_map.read(wraps_snapshot.clone(), wrap_edits);
|
let mut blocks_snapshot = block_map.read(wraps_snapshot.clone(), wrap_edits, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
blocks_snapshot.transforms.summary().input_rows,
|
blocks_snapshot.transforms.summary().input_rows,
|
||||||
wraps_snapshot.max_point().row() + 1
|
wraps_snapshot.max_point().row() + 1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue