Recompute layers above tab map entirely when tab size changes
Antonio Scandurra
created 3 years ago
Previously, we wouldn't generate any `TabEdit` when the tab size
changed, causing coordinate spaces in `WrapMap` and `BlockMap` to
become outdated.
This commit generates a synthetic edit that covers the entire `TabMap`
to ensure layers above are synchronized.
Change summary
crates/editor/src/display_map.rs | 33 ++++++++++++++++++++++++++
crates/editor/src/display_map/tab_map.rs | 12 +++++++-
2 files changed, 43 insertions(+), 2 deletions(-)
Detailed changes
@@ -1351,6 +1351,39 @@ pub mod tests {
)
}
+ #[gpui::test]
+ fn test_changing_tab_size(cx: &mut gpui::MutableAppContext) {
+ cx.set_global({
+ let mut settings = Settings::test(cx);
+ settings.editor_overrides.tab_size = Some(NonZeroU32::new(4).unwrap());
+ settings
+ });
+ let buffer = MultiBuffer::build_simple("\ta\n\tb\n\tc", cx);
+ let font_cache = cx.font_cache();
+ let family_id = font_cache.load_family(&["Helvetica"]).unwrap();
+ let font_id = font_cache
+ .select_font(family_id, &Default::default())
+ .unwrap();
+ let font_size = 14.0;
+
+ let map =
+ cx.add_model(|cx| DisplayMap::new(buffer.clone(), font_id, font_size, None, 1, 1, cx));
+ assert_eq!(
+ map.update(cx, |map, cx| map.snapshot(cx)).text(),
+ " a\n b\n c"
+ );
+
+ cx.set_global({
+ let mut settings = Settings::test(cx);
+ settings.editor_overrides.tab_size = Some(NonZeroU32::new(2).unwrap());
+ settings
+ });
+ assert_eq!(
+ map.update(cx, |map, cx| map.snapshot(cx)).text(),
+ " a\n b\n c"
+ );
+ }
+
fn syntax_chunks<'a>(
rows: Range<u32>,
map: &ModelHandle<DisplayMap>,
@@ -27,19 +27,27 @@ impl TabMap {
tab_size: NonZeroU32,
) -> (TabSnapshot, Vec<TabEdit>) {
let mut old_snapshot = self.0.lock();
- let max_offset = old_snapshot.fold_snapshot.len();
let new_snapshot = TabSnapshot {
fold_snapshot,
tab_size,
};
+ if old_snapshot.tab_size != new_snapshot.tab_size {
+ let edits = vec![TabEdit {
+ old: TabPoint::zero()..old_snapshot.max_point(),
+ new: TabPoint::zero()..new_snapshot.max_point(),
+ }];
+ return (new_snapshot, edits);
+ }
+
+ let old_max_offset = old_snapshot.fold_snapshot.len();
let mut tab_edits = Vec::with_capacity(fold_edits.len());
for fold_edit in &mut fold_edits {
let mut delta = 0;
for chunk in
old_snapshot
.fold_snapshot
- .chunks(fold_edit.old.end..max_offset, false, None)
+ .chunks(fold_edit.old.end..old_max_offset, false, None)
{
let patterns: &[_] = &['\t', '\n'];
if let Some(ix) = chunk.text.find(patterns) {