diff --git a/zed/src/editor/display_map/wrap_map.rs b/zed/src/editor/display_map/wrap_map.rs index f7740509dc..92da9f376f 100644 --- a/zed/src/editor/display_map/wrap_map.rs +++ b/zed/src/editor/display_map/wrap_map.rs @@ -253,29 +253,44 @@ impl BackgroundWrapper { let font_size = self.config.font_size; let wrap_width = self.config.wrap_width; - let mut new_transforms; - { - struct RowEdit { - old_rows: Range, - new_rows: Range, + struct RowEdit { + old_rows: Range, + new_rows: Range, + } + + let mut edits = edits.into_iter().peekable(); + let mut row_edits = Vec::new(); + while let Some(edit) = edits.next() { + let mut row_edit = RowEdit { + old_rows: edit.old_lines.start.row()..edit.old_lines.end.row() + 1, + new_rows: edit.new_lines.start.row()..edit.new_lines.end.row() + 1, + }; + + while let Some(next_edit) = edits.peek() { + if next_edit.old_lines.start.row() <= row_edit.old_rows.end { + row_edit.old_rows.end = next_edit.old_lines.end.row() + 1; + row_edit.new_rows.end = next_edit.new_lines.end.row() + 1; + edits.next(); + } else { + break; + } } - let mut edits = edits - .into_iter() - .map(|edit| RowEdit { - old_rows: edit.old_lines.start.row()..edit.old_lines.end.row() + 1, - new_rows: edit.new_lines.start.row()..edit.new_lines.end.row() + 1, - }) - .peekable(); + row_edits.push(row_edit); + } + + let mut new_transforms; + { + let mut row_edits = row_edits.into_iter().peekable(); let mut old_cursor = self.snapshot.transforms.cursor::(); new_transforms = old_cursor.slice( - &InputPoint::new(edits.peek().unwrap().old_rows.start, 0), + &InputPoint::new(row_edits.peek().unwrap().old_rows.start, 0), Bias::Right, &(), ); - while let Some(edit) = edits.next() { + while let Some(edit) = row_edits.next() { if edit.new_rows.start > new_transforms.summary().input.lines.row { new_transforms.push( Transform::isomorphic(new_snapshot.text_summary_for_rows( @@ -339,7 +354,7 @@ impl BackgroundWrapper { ); } - if let Some(next_edit) = edits.peek() { + if let Some(next_edit) = row_edits.peek() { if next_edit.old_rows.start > old_cursor.seek_end(&()).row() { old_cursor.next(&()); new_transforms.push_tree( @@ -358,8 +373,11 @@ impl BackgroundWrapper { } } - self.snapshot.transforms = new_transforms; - self.snapshot.version = new_snapshot.version(); + self.snapshot = Snapshot { + transforms: new_transforms, + version: new_snapshot.version(), + input: new_snapshot, + }; } } @@ -447,6 +465,7 @@ mod tests { util::RandomCharIter, }; use futures::StreamExt; + use gpui::fonts::FontId; use rand::prelude::*; use std::env; @@ -500,8 +519,9 @@ mod tests { let mut rng = StdRng::seed_from_u64(seed); let buffer = cx.add_model(|cx| { - let len = rng.gen_range(0..32); + let len = rng.gen_range(0..10); let text = RandomCharIter::new(&mut rng).take(len).collect::(); + dbg!(&text); Buffer::new(0, text, cx) }); let fold_map = FoldMap::new(buffer.clone(), cx.as_ref()); @@ -530,21 +550,13 @@ mod tests { }; wrapper.sync(tabs_snapshot.clone(), vec![edit]); - let mut expected_text = String::new(); let unwrapped_text = tabs_snapshot.text(); - let mut unwrapped_lines = unwrapped_text.split('\n').peekable(); - while let Some(line) = unwrapped_lines.next() { - let mut prev_ix = 0; - for ix in font_system.wrap_line(line, font_id, 14.0, config.wrap_width) { - expected_text.push_str(&line[prev_ix..ix]); - expected_text.push('\n'); - prev_ix = ix; - } - expected_text.push_str(&line[prev_ix..]); - if unwrapped_lines.peek().is_some() { - expected_text.push('\n'); - } - } + let expected_text = wrap_text( + &unwrapped_text, + config.wrap_width, + font_id, + font_system.as_ref(), + ); let actual_text = wrapper .snapshot @@ -556,6 +568,57 @@ mod tests { "unwrapped text is: {:?}", unwrapped_text ); + + for _i in 0..operations { + buffer.update(cx, |buffer, cx| buffer.randomly_mutate(&mut rng, cx)); + let (snapshot, edits) = fold_map.read(cx.as_ref()); + let (snapshot, edits) = tab_map.sync(snapshot, edits); + let unwrapped_text = snapshot.text(); + let expected_text = wrap_text( + &unwrapped_text, + config.wrap_width, + font_id, + font_system.as_ref(), + ); + wrapper.sync(snapshot, edits); + + dbg!(&unwrapped_text); + dbg!(&expected_text); + dbg!(wrapper.snapshot.transforms.items(&())); + + let actual_text = wrapper + .snapshot + .chunks_at(OutputPoint::zero()) + .collect::(); + assert_eq!( + actual_text, expected_text, + "unwrapped text is: {:?}", + unwrapped_text + ); + } } } + + fn wrap_text( + unwrapped_text: &str, + wrap_width: f32, + font_id: FontId, + font_system: &dyn FontSystem, + ) -> String { + let mut wrapped_text = String::new(); + for (row, line) in unwrapped_text.split('\n').enumerate() { + if row > 0 { + wrapped_text.push('\n') + } + + let mut prev_ix = 0; + for ix in font_system.wrap_line(line, font_id, 14.0, wrap_width) { + wrapped_text.push_str(&line[prev_ix..ix]); + wrapped_text.push('\n'); + prev_ix = ix; + } + wrapped_text.push_str(&line[prev_ix..]); + } + wrapped_text + } }