From a88b63d83c0fdea064f6e9777b1cbceba9ccd643 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 29 Mar 2021 09:46:04 +0200 Subject: [PATCH] Ensure `FoldMap` always contains at least one transform Previously, when splicing an edit that deleted all transforms, we would leave the `FoldMap` empty, thus violating a bunch of downstream invariants and e.g. causing the `BufferRows` iterator to not return any buffer row. This commit ensures we always have at least one transform (an isomorphic one, specifically) and adds additional test coverage for the `FoldMap::buffer_rows` method by adding it to the randomized tests. --- zed/src/editor/display_map/fold_map.rs | 41 +++++++++++++++++++++++++- zed/src/sum_tree/mod.rs | 1 - 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index 4a6b97bf30..3544e08799 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -320,6 +320,16 @@ impl FoldMap { } new_transforms.push_tree(cursor.suffix()); + if new_transforms.is_empty() { + let text_summary = buffer.text_summary(); + new_transforms.push(Transform { + summary: TransformSummary { + display: text_summary.clone(), + buffer: text_summary, + }, + display_text: None, + }); + } drop(cursor); self.transforms = new_transforms; @@ -571,8 +581,19 @@ mod tests { use crate::editor::ToPoint; use crate::util::RandomCharIter; use rand::prelude::*; + use std::env; - for seed in 0..100 { + let iterations = env::var("ITERATIONS") + .map(|i| i.parse().expect("invalid `ITERATIONS` variable")) + .unwrap_or(100); + let seed_range = if let Ok(seed) = env::var("SEED") { + let seed = seed.parse().expect("invalid `SEED` variable"); + seed..seed + 1 + } else { + 0..iterations + }; + + for seed in seed_range { println!("{:?}", seed); let mut rng = StdRng::seed_from_u64(seed); @@ -625,11 +646,29 @@ mod tests { let buffer = map.buffer.as_ref(app); let mut expected_text = buffer.text(); + let mut expected_buffer_rows = Vec::new(); + let mut next_row = buffer.max_point().row; for fold_range in map.merged_fold_ranges(app).into_iter().rev() { + let fold_start = buffer.point_for_offset(fold_range.start).unwrap(); + let fold_end = buffer.point_for_offset(fold_range.end).unwrap(); + expected_buffer_rows.extend((fold_end.row + 1..=next_row).rev()); + next_row = fold_start.row; + expected_text.replace_range(fold_range.start..fold_range.end, "…"); } + expected_buffer_rows.extend((0..=next_row).rev()); + expected_buffer_rows.reverse(); + assert_eq!(map.text(app), expected_text); + for (idx, buffer_row) in expected_buffer_rows.iter().enumerate() { + let display_row = map.to_display_point(Point::new(*buffer_row, 0)).row(); + assert_eq!( + map.buffer_rows(display_row).unwrap().collect::>(), + expected_buffer_rows[idx..], + ); + } + Ok::<(), anyhow::Error>(()) })?; diff --git a/zed/src/sum_tree/mod.rs b/zed/src/sum_tree/mod.rs index 47dc31797b..5957a58ecb 100644 --- a/zed/src/sum_tree/mod.rs +++ b/zed/src/sum_tree/mod.rs @@ -102,7 +102,6 @@ impl SumTree { } } - #[cfg(test)] pub fn is_empty(&self) -> bool { match self.0.as_ref() { Node::Internal { .. } => false,