From 0fff7d9166af911d498a283ffa687cf2befdadd0 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 10 Nov 2021 17:44:56 -0700 Subject: [PATCH] WIP: Probably the wrong direction --- crates/buffer/src/rope.rs | 23 +- .../editor/src/display_map/injection_map.rs | 233 +++++++++++++----- crates/sum_tree/src/lib.rs | 6 + 3 files changed, 190 insertions(+), 72 deletions(-) diff --git a/crates/buffer/src/rope.rs b/crates/buffer/src/rope.rs index 3cf43bd160..5498c403bf 100644 --- a/crates/buffer/src/rope.rs +++ b/crates/buffer/src/rope.rs @@ -303,7 +303,7 @@ impl<'a> Cursor<'a> { if let Some(start_chunk) = self.chunks.item() { let start_ix = self.offset - self.chunks.start(); let end_ix = cmp::min(end_offset, self.chunks.end(&())) - self.chunks.start(); - summary.add_assign(&D::from_summary(&TextSummary::from( + summary.add_assign(&D::from_text_summary(&TextSummary::from( &start_chunk.0[start_ix..end_ix], ))); } @@ -313,7 +313,9 @@ impl<'a> Cursor<'a> { summary.add_assign(&self.chunks.summary(&end_offset, Bias::Right, &())); if let Some(end_chunk) = self.chunks.item() { let end_ix = end_offset - self.chunks.start(); - summary.add_assign(&D::from_summary(&TextSummary::from(&end_chunk.0[..end_ix]))); + summary.add_assign(&D::from_text_summary(&TextSummary::from( + &end_chunk.0[..end_ix], + ))); } } @@ -634,13 +636,16 @@ impl std::ops::AddAssign for TextSummary { } pub trait TextDimension<'a>: Dimension<'a, TextSummary> { - fn from_summary(summary: &TextSummary) -> Self; + fn from_text_summary(summary: &TextSummary) -> Self; fn add_assign(&mut self, other: &Self); } impl<'a, D1: TextDimension<'a>, D2: TextDimension<'a>> TextDimension<'a> for (D1, D2) { - fn from_summary(summary: &TextSummary) -> Self { - (D1::from_summary(summary), D2::from_summary(summary)) + fn from_text_summary(summary: &TextSummary) -> Self { + ( + D1::from_text_summary(summary), + D2::from_text_summary(summary), + ) } fn add_assign(&mut self, other: &Self) { @@ -650,7 +655,7 @@ impl<'a, D1: TextDimension<'a>, D2: TextDimension<'a>> TextDimension<'a> for (D1 } impl<'a> TextDimension<'a> for TextSummary { - fn from_summary(summary: &TextSummary) -> Self { + fn from_text_summary(summary: &TextSummary) -> Self { summary.clone() } @@ -666,7 +671,7 @@ impl<'a> sum_tree::Dimension<'a, TextSummary> for usize { } impl<'a> TextDimension<'a> for usize { - fn from_summary(summary: &TextSummary) -> Self { + fn from_text_summary(summary: &TextSummary) -> Self { summary.bytes } @@ -682,7 +687,7 @@ impl<'a> sum_tree::Dimension<'a, TextSummary> for Point { } impl<'a> TextDimension<'a> for Point { - fn from_summary(summary: &TextSummary) -> Self { + fn from_text_summary(summary: &TextSummary) -> Self { summary.lines } @@ -698,7 +703,7 @@ impl<'a> sum_tree::Dimension<'a, TextSummary> for PointUtf16 { } impl<'a> TextDimension<'a> for PointUtf16 { - fn from_summary(summary: &TextSummary) -> Self { + fn from_text_summary(summary: &TextSummary) -> Self { summary.lines_utf16 } diff --git a/crates/editor/src/display_map/injection_map.rs b/crates/editor/src/display_map/injection_map.rs index 3bd142fe78..06a147c33d 100644 --- a/crates/editor/src/display_map/injection_map.rs +++ b/crates/editor/src/display_map/injection_map.rs @@ -1,13 +1,15 @@ use std::{ - cmp, mem, + cmp::Ordering, + mem, sync::atomic::{AtomicUsize, Ordering::SeqCst}, }; -use buffer::{Anchor, Bias, Edit, Point, Rope, TextSummary}; +use buffer::{rope::TextDimension, Anchor, Bias, Edit, Rope, TextSummary, ToOffset}; use gpui::{fonts::HighlightStyle, AppContext, ModelHandle}; use language::Buffer; use parking_lot::Mutex; -use sum_tree::SumTree; +use sum_tree::{SeekTarget, SumTree}; +use util::post_inc; #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)] pub struct InjectionId(usize); @@ -16,14 +18,14 @@ pub struct InjectionMap { buffer: ModelHandle, transforms: Mutex>, injections: SumTree, - injection_contents: SumTree, version: AtomicUsize, last_sync: Mutex, + next_injection_id: usize, } pub struct InjectionSnapshot { transforms: SumTree, - injection_contents: SumTree, + injections: SumTree, buffer_snapshot: language::Snapshot, pub version: usize, } @@ -37,13 +39,6 @@ struct SyncState { diagnostics_update_count: usize, } -#[derive(Clone, Debug)] -struct Injection { - id: InjectionId, - position: Anchor, - is_block: bool, -} - #[derive(Clone, Debug)] struct InjectionSummary { min_id: InjectionId, @@ -53,25 +48,28 @@ struct InjectionSummary { } #[derive(Clone, Debug)] -struct InjectionContent { - injection_id: InjectionId, - runs: Vec<(usize, HighlightStyle)>, +struct Injection { + id: InjectionId, text: Rope, + runs: Vec<(usize, HighlightStyle)>, } #[derive(Clone, Debug, Default, PartialEq)] struct Transform { - summary: TransformSummary, + input: TextSummary, + output: TextSummary, injection_id: Option, } #[derive(Clone, Debug, Default, Eq, PartialEq)] struct TransformSummary { - output: TextSummary, input: TextSummary, + output: TextSummary, + min_injection_id: InjectionId, + max_injection_id: InjectionId, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug, Default)] struct InjectionOffset(usize); impl sum_tree::Summary for InjectionId { @@ -88,7 +86,7 @@ impl InjectionMap { // self.check_invariants(cx); let snapshot = InjectionSnapshot { transforms: self.transforms.lock().clone(), - injection_contents: self.injection_contents.clone(), + injections: self.injections.clone(), buffer_snapshot: self.buffer.read(cx).snapshot(), version: self.version.load(SeqCst), }; @@ -146,11 +144,11 @@ impl InjectionMap { let mut cursor = transforms.cursor::(); while let Some(mut edit) = buffer_edits_iter.next() { - new_transforms.push_tree(cursor.slice(&edit.old.start, Bias::Left, &()), &()); + new_transforms.push_tree(cursor.slice(&edit.old.start, Bias::Right, &()), &()); edit.new.start -= edit.old.start - cursor.start(); edit.old.start = *cursor.start(); - cursor.seek(&edit.old.end, Bias::Right, &()); + cursor.seek(&edit.old.end, Bias::Left, &()); cursor.next(&()); let mut delta = edit.new.len() as isize - edit.old.len() as isize; @@ -158,7 +156,7 @@ impl InjectionMap { edit.old.end = *cursor.start(); if let Some(next_edit) = buffer_edits_iter.peek() { - if next_edit.old.start > edit.old.end { + if next_edit.old.start >= edit.old.end { break; } @@ -167,7 +165,7 @@ impl InjectionMap { if next_edit.old.end >= edit.old.end { edit.old.end = next_edit.old.end; - cursor.seek(&edit.old.end, Bias::Right, &()); + cursor.seek(&edit.old.end, Bias::Left, &()); cursor.next(&()); } } else { @@ -177,54 +175,142 @@ impl InjectionMap { edit.new.end = ((edit.new.start + edit.old.len()) as isize + delta) as usize; - let anchor = buffer.anchor_before(edit.new.start); - let mut injections_cursor = self.injections.cursor::(); - // folds_cursor.seek(&Fold(anchor..Anchor::max()), Bias::Left, &buffer); + if !edit.new.is_empty() { + let text_summary = buffer.text_summary_for_range(edit.new.start..edit.new.end); + new_transforms.push( + Transform { + input: text_summary.clone(), + output: text_summary, + injection_id: None, + }, + &(), + ); + } + } + new_transforms.push_tree(cursor.suffix(&()), &()); + drop(cursor); + + let injection_edits = { + let mut old_transforms = transforms.cursor::<(usize, InjectionOffset)>(); + let mut new_transforms = new_transforms.cursor::<(usize, InjectionOffset)>(); + + buffer_edits + .into_iter() + .map(|edit| { + old_transforms.seek(&edit.old.start, Bias::Right, &()); + let old_start = + old_transforms.start().1 .0 + (edit.old.start - old_transforms.start().0); + + old_transforms.seek_forward(&edit.old.end, Bias::Left, &()); + let old_end = + old_transforms.start().1 .0 + (edit.old.end - old_transforms.start().0); + + new_transforms.seek(&edit.new.start, Bias::Right, &()); + let new_start = + new_transforms.start().1 .0 + (edit.new.start - new_transforms.start().0); + + new_transforms.seek_forward(&edit.new.end, Bias::Left, &()); + let new_end = + new_transforms.start().1 .0 + (edit.new.end - new_transforms.start().0); + + Edit { + old: InjectionOffset(old_start)..InjectionOffset(old_end), + new: InjectionOffset(new_start)..InjectionOffset(new_end), + } + }) + .collect() + }; + + *transforms = new_transforms; + injection_edits + } +} + +impl<'a> InjectionMapWriter<'a> { + pub fn insert<'b, T, U>( + &mut self, + injections: T, + cx: &AppContext, + ) -> ( + Vec, + InjectionSnapshot, + Vec>, + ) + where + T: IntoIterator)>, + U: ToOffset, + { + let buffer = self.0.buffer.read(cx); + let mut injections = injections + .into_iter() + .map(|(position, text, runs)| (position.to_offset(buffer), text, runs)) + .peekable(); + let mut edits = Vec::new(); + let mut injection_ids = Vec::new(); + let mut new_transforms = SumTree::new(); + let mut transforms = self.0.transforms.lock(); + let mut cursor = transforms.cursor::(); + + while let Some((injection_offset, text, runs)) = injections.next() { + new_transforms.push_tree(cursor.slice(&injection_offset, Bias::Right, &()), &()); + let new_transforms_end = new_transforms.summary().input.bytes; + if injection_offset > new_transforms_end { + new_transforms.push( + Transform::isomorphic( + buffer.text_summary_for_range(new_transforms_end..injection_offset), + ), + &(), + ); + } + + let injection = Injection { + id: InjectionId(post_inc(&mut self.0.next_injection_id)), + runs, + text: text.into(), + }; + new_transforms.push( + Transform { + input: Default::default(), + output: injection.text.summary(), + injection_id: Some(injection.id), + }, + &(), + ); + self.0.injections.push(injection, &()); + + if let Some((next_injection_offset, _, _)) = injections.peek() { + let old_transform_end = cursor.end(&()); + if *next_injection_offset > old_transform_end { + new_transforms.push( + Transform::isomorphic( + buffer.text_summary_for_range(new_transforms_end..old_transform_end), + ), + &(), + ); + cursor.next(&()); + } + } } - todo!() + (injection_ids, todo!(), edits) } } impl sum_tree::Item for Injection { - type Summary = InjectionSummary; - - fn summary(&self) -> Self::Summary { - InjectionSummary { - min_id: self.id, - max_id: self.id, - min_position: self.position.clone(), - max_position: self.position.clone(), - } - } -} - -impl sum_tree::Summary for InjectionSummary { - type Context = buffer::Snapshot; - - fn add_summary(&mut self, summary: &Self, _: &buffer::Snapshot) { - self.max_position = summary.max_position.clone(); - self.min_id = cmp::min(self.min_id, summary.min_id); - self.max_id = cmp::max(self.max_id, summary.max_id); - } -} - -impl Default for InjectionSummary { - fn default() -> Self { - Self { - min_id: InjectionId(0), - max_id: InjectionId(usize::MAX), - min_position: Anchor::max(), - max_position: Anchor::min(), - } - } -} - -impl sum_tree::Item for InjectionContent { type Summary = InjectionId; fn summary(&self) -> Self::Summary { - self.injection_id + self.id + } +} + +impl Transform { + fn isomorphic(text_summary: TextSummary) -> Self { + Self { + input: text_summary.clone(), + output: text_summary, + injection_id: None, + } } } @@ -232,7 +318,22 @@ impl sum_tree::Item for Transform { type Summary = TransformSummary; fn summary(&self) -> Self::Summary { - self.summary.clone() + let min_injection_id; + let max_injection_id; + if let Some(id) = self.injection_id { + min_injection_id = id; + max_injection_id = id; + } else { + min_injection_id = InjectionId(usize::MAX); + max_injection_id = InjectionId(0); + } + + TransformSummary { + input: self.input.clone(), + output: self.output.clone(), + min_injection_id, + max_injection_id, + } } } @@ -250,3 +351,9 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize { *self += summary.input.bytes } } + +impl<'a> sum_tree::Dimension<'a, TransformSummary> for InjectionOffset { + fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { + self.0 += summary.output.bytes + } +} diff --git a/crates/sum_tree/src/lib.rs b/crates/sum_tree/src/lib.rs index eeef956324..8b4a45519f 100644 --- a/crates/sum_tree/src/lib.rs +++ b/crates/sum_tree/src/lib.rs @@ -31,6 +31,12 @@ pub trait Summary: Default + Clone + fmt::Debug { pub trait Dimension<'a, S: Summary>: Clone + fmt::Debug + Default { fn add_summary(&mut self, _summary: &'a S, _: &S::Context); + + fn from_summary(summary: &'a S, cx: &S::Context) -> Self { + let mut dimension = Self::default(); + dimension.add_summary(summary, cx); + dimension + } } impl<'a, T: Summary> Dimension<'a, T> for T {