Store pending edits until applying them to a non-interpolated snapshot

This commit is contained in:
Antonio Scandurra 2021-07-26 17:13:49 +02:00
parent 1ef7474564
commit 9d14ca8d33

View file

@ -30,6 +30,7 @@ impl Entity for WrapMap {
pub struct Snapshot {
tab_snapshot: TabSnapshot,
transforms: SumTree<Transform>,
interpolated: bool,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
@ -170,12 +171,16 @@ impl WrapMap {
}
fn flush_edits(&mut self, cx: &mut ModelContext<Self>) {
while let Some((tab_snapshot, _)) = self.pending_edits.front() {
if tab_snapshot.version() <= self.snapshot.tab_snapshot.version() {
self.pending_edits.pop_front();
} else {
break;
if !self.snapshot.interpolated {
let mut to_remove_len = 0;
for (tab_snapshot, _) in &self.pending_edits {
if tab_snapshot.version() <= self.snapshot.tab_snapshot.version() {
to_remove_len += 1;
} else {
break;
}
}
self.pending_edits.drain(..to_remove_len);
}
if self.pending_edits.is_empty() {
@ -219,16 +224,18 @@ impl WrapMap {
}
}
while let Some((tab_snapshot, _)) = self.pending_edits.front() {
let was_interpolated = self.snapshot.interpolated;
let mut to_remove_len = 0;
for (tab_snapshot, edits) in &self.pending_edits {
if tab_snapshot.version() <= self.snapshot.tab_snapshot.version() {
self.pending_edits.pop_front();
to_remove_len += 1;
} else {
break;
self.snapshot.interpolate(tab_snapshot.clone(), &edits);
}
}
for (tab_snapshot, edits) in self.pending_edits.clone() {
self.snapshot.interpolate(tab_snapshot, &edits);
if !was_interpolated {
self.pending_edits.drain(..to_remove_len);
}
}
}
@ -243,6 +250,7 @@ impl Snapshot {
Self {
transforms,
tab_snapshot,
interpolated: true,
}
}
@ -300,6 +308,8 @@ impl Snapshot {
self.transforms = new_transforms;
self.tab_snapshot = new_tab_snapshot;
self.interpolated = true;
self.check_invariants();
}
async fn update(
@ -429,6 +439,8 @@ impl Snapshot {
self.transforms = new_transforms;
self.tab_snapshot = new_tab_snapshot;
self.interpolated = false;
self.check_invariants();
}
pub fn chunks_at(&self, point: WrapPoint) -> Chunks {
@ -525,6 +537,27 @@ impl Snapshot {
self.to_wrap_point(self.tab_snapshot.clip_point(self.to_tab_point(point), bias))
}
fn check_invariants(&self) {
#[cfg(test)]
{
assert_eq!(
TabPoint::from(self.transforms.summary().input.lines),
self.tab_snapshot.max_point()
);
{
let mut transforms = self.transforms.cursor::<(), ()>().peekable();
while let Some(transform) = transforms.next() {
let next_transform = transforms.peek();
assert!(
!transform.is_isomorphic()
|| next_transform.map_or(true, |t| !t.is_isomorphic())
);
}
}
}
}
}
impl<'a> Iterator for Chunks<'a> {
@ -759,6 +792,8 @@ mod tests {
#[gpui::test]
async fn test_random_wraps(mut cx: gpui::TestAppContext) {
cx.foreground().set_block_on_ticks(0..=50);
let iterations = env::var("ITERATIONS")
.map(|i| i.parse().expect("invalid `ITERATIONS` variable"))
.unwrap_or(100);
@ -853,31 +888,39 @@ mod tests {
let (tabs_snapshot, edits) = tab_map.sync(folds_snapshot, edits);
log::info!("Unwrapped text (expanded tabs): {:?}", tabs_snapshot.text());
interpolated_snapshot.interpolate(tabs_snapshot.clone(), &edits);
interpolated_snapshot.check_invariants(&mut rng);
interpolated_snapshot.check_invariants();
interpolated_snapshot.verify_chunks(&mut rng);
let unwrapped_text = tabs_snapshot.text();
let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper);
let mut snapshot = wrap_map.update(&mut cx, |map, cx| {
map.sync(tabs_snapshot.clone(), edits, cx)
});
snapshot.check_invariants(&mut rng);
snapshot.check_invariants();
interpolated_snapshot.verify_chunks(&mut rng);
if wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) {
notifications.recv().await.unwrap();
snapshot =
wrap_map.update(&mut cx, |map, cx| map.sync(tabs_snapshot, Vec::new(), cx));
if wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) && rng.gen_bool(0.4) {
log::info!("Waiting for wrapping to finish");
while wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) {
notifications.recv().await.unwrap();
}
}
snapshot.check_invariants(&mut rng);
let actual_text = snapshot.text();
assert_eq!(
actual_text, expected_text,
"unwrapped text is: {:?}",
unwrapped_text
);
log::info!("New wrapped text: {:?}", actual_text);
interpolated_snapshot = snapshot.clone();
if !wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) {
log::info!("Wrapping finished");
snapshot =
wrap_map.update(&mut cx, |map, cx| map.sync(tabs_snapshot, Vec::new(), cx));
snapshot.check_invariants();
interpolated_snapshot.verify_chunks(&mut rng);
let actual_text = snapshot.text();
assert_eq!(
actual_text, expected_text,
"unwrapped text is: {:?}",
unwrapped_text
);
log::info!("New wrapped text: {:?}", actual_text);
interpolated_snapshot = snapshot.clone();
}
}
}
}
@ -913,23 +956,7 @@ mod tests {
self.chunks_at(WrapPoint::zero()).collect()
}
fn check_invariants(&mut self, rng: &mut impl Rng) {
assert_eq!(
TabPoint::from(self.transforms.summary().input.lines),
self.tab_snapshot.max_point()
);
{
let mut transforms = self.transforms.cursor::<(), ()>().peekable();
while let Some(transform) = transforms.next() {
let next_transform = transforms.peek();
assert!(
!transform.is_isomorphic()
|| next_transform.map_or(true, |t| !t.is_isomorphic())
);
}
}
fn verify_chunks(&mut self, rng: &mut impl Rng) {
for _ in 0..5 {
let mut end_row = rng.gen_range(0..=self.max_point().row());
let start_row = rng.gen_range(0..=end_row);