mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-12 21:32:40 +00:00
Store pending edits until applying them to a non-interpolated snapshot
This commit is contained in:
parent
1ef7474564
commit
9d14ca8d33
1 changed files with 70 additions and 43 deletions
|
@ -30,6 +30,7 @@ impl Entity for WrapMap {
|
||||||
pub struct Snapshot {
|
pub struct Snapshot {
|
||||||
tab_snapshot: TabSnapshot,
|
tab_snapshot: TabSnapshot,
|
||||||
transforms: SumTree<Transform>,
|
transforms: SumTree<Transform>,
|
||||||
|
interpolated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
|
@ -170,12 +171,16 @@ impl WrapMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_edits(&mut self, cx: &mut ModelContext<Self>) {
|
fn flush_edits(&mut self, cx: &mut ModelContext<Self>) {
|
||||||
while let Some((tab_snapshot, _)) = self.pending_edits.front() {
|
if !self.snapshot.interpolated {
|
||||||
if tab_snapshot.version() <= self.snapshot.tab_snapshot.version() {
|
let mut to_remove_len = 0;
|
||||||
self.pending_edits.pop_front();
|
for (tab_snapshot, _) in &self.pending_edits {
|
||||||
} else {
|
if tab_snapshot.version() <= self.snapshot.tab_snapshot.version() {
|
||||||
break;
|
to_remove_len += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
self.pending_edits.drain(..to_remove_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.pending_edits.is_empty() {
|
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() {
|
if tab_snapshot.version() <= self.snapshot.tab_snapshot.version() {
|
||||||
self.pending_edits.pop_front();
|
to_remove_len += 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
self.snapshot.interpolate(tab_snapshot.clone(), &edits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (tab_snapshot, edits) in self.pending_edits.clone() {
|
if !was_interpolated {
|
||||||
self.snapshot.interpolate(tab_snapshot, &edits);
|
self.pending_edits.drain(..to_remove_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,6 +250,7 @@ impl Snapshot {
|
||||||
Self {
|
Self {
|
||||||
transforms,
|
transforms,
|
||||||
tab_snapshot,
|
tab_snapshot,
|
||||||
|
interpolated: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,6 +308,8 @@ impl Snapshot {
|
||||||
|
|
||||||
self.transforms = new_transforms;
|
self.transforms = new_transforms;
|
||||||
self.tab_snapshot = new_tab_snapshot;
|
self.tab_snapshot = new_tab_snapshot;
|
||||||
|
self.interpolated = true;
|
||||||
|
self.check_invariants();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update(
|
async fn update(
|
||||||
|
@ -429,6 +439,8 @@ impl Snapshot {
|
||||||
|
|
||||||
self.transforms = new_transforms;
|
self.transforms = new_transforms;
|
||||||
self.tab_snapshot = new_tab_snapshot;
|
self.tab_snapshot = new_tab_snapshot;
|
||||||
|
self.interpolated = false;
|
||||||
|
self.check_invariants();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chunks_at(&self, point: WrapPoint) -> Chunks {
|
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))
|
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> {
|
impl<'a> Iterator for Chunks<'a> {
|
||||||
|
@ -759,6 +792,8 @@ mod tests {
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_random_wraps(mut cx: gpui::TestAppContext) {
|
async fn test_random_wraps(mut cx: gpui::TestAppContext) {
|
||||||
|
cx.foreground().set_block_on_ticks(0..=50);
|
||||||
|
|
||||||
let iterations = env::var("ITERATIONS")
|
let iterations = env::var("ITERATIONS")
|
||||||
.map(|i| i.parse().expect("invalid `ITERATIONS` variable"))
|
.map(|i| i.parse().expect("invalid `ITERATIONS` variable"))
|
||||||
.unwrap_or(100);
|
.unwrap_or(100);
|
||||||
|
@ -853,31 +888,39 @@ mod tests {
|
||||||
let (tabs_snapshot, edits) = tab_map.sync(folds_snapshot, edits);
|
let (tabs_snapshot, edits) = tab_map.sync(folds_snapshot, edits);
|
||||||
log::info!("Unwrapped text (expanded tabs): {:?}", tabs_snapshot.text());
|
log::info!("Unwrapped text (expanded tabs): {:?}", tabs_snapshot.text());
|
||||||
interpolated_snapshot.interpolate(tabs_snapshot.clone(), &edits);
|
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 unwrapped_text = tabs_snapshot.text();
|
||||||
let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper);
|
let expected_text = wrap_text(&unwrapped_text, wrap_width, &mut line_wrapper);
|
||||||
let mut snapshot = wrap_map.update(&mut cx, |map, cx| {
|
let mut snapshot = wrap_map.update(&mut cx, |map, cx| {
|
||||||
map.sync(tabs_snapshot.clone(), edits, 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()) {
|
if wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) && rng.gen_bool(0.4) {
|
||||||
notifications.recv().await.unwrap();
|
log::info!("Waiting for wrapping to finish");
|
||||||
snapshot =
|
while wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) {
|
||||||
wrap_map.update(&mut cx, |map, cx| map.sync(tabs_snapshot, Vec::new(), cx));
|
notifications.recv().await.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot.check_invariants(&mut rng);
|
if !wrap_map.read_with(&cx, |map, _| map.is_rewrapping()) {
|
||||||
let actual_text = snapshot.text();
|
log::info!("Wrapping finished");
|
||||||
assert_eq!(
|
snapshot =
|
||||||
actual_text, expected_text,
|
wrap_map.update(&mut cx, |map, cx| map.sync(tabs_snapshot, Vec::new(), cx));
|
||||||
"unwrapped text is: {:?}",
|
snapshot.check_invariants();
|
||||||
unwrapped_text
|
interpolated_snapshot.verify_chunks(&mut rng);
|
||||||
);
|
let actual_text = snapshot.text();
|
||||||
log::info!("New wrapped text: {:?}", actual_text);
|
assert_eq!(
|
||||||
|
actual_text, expected_text,
|
||||||
interpolated_snapshot = snapshot.clone();
|
"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()
|
self.chunks_at(WrapPoint::zero()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_invariants(&mut self, rng: &mut impl Rng) {
|
fn verify_chunks(&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())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
let mut end_row = rng.gen_range(0..=self.max_point().row());
|
let mut end_row = rng.gen_range(0..=self.max_point().row());
|
||||||
let start_row = rng.gen_range(0..=end_row);
|
let start_row = rng.gen_range(0..=end_row);
|
||||||
|
|
Loading…
Reference in a new issue