wip

Cole Miller created

Change summary

crates/editor/src/split.rs              | 210 +++++++++++---------------
crates/multi_buffer/src/multi_buffer.rs |  11 +
crates/multi_buffer/src/path_key.rs     |   8 +
3 files changed, 109 insertions(+), 120 deletions(-)

Detailed changes

crates/editor/src/split.rs 🔗

@@ -1,16 +1,13 @@
-use std::ops::Range;
+use std::{ops::Range, sync::Arc};
 
-use buffer_diff::{BufferDiff, BufferDiffSnapshot};
-use collections::HashMap;
 use feature_flags::{FeatureFlag, FeatureFlagAppExt as _};
 use gpui::{
     Action, AppContext as _, Entity, EventEmitter, Focusable, NoAction, Subscription, WeakEntity,
 };
-use language::{Buffer, BufferSnapshot, Capability};
-use multi_buffer::{Anchor, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey};
+use language::{Buffer, Capability, LanguageRegistry};
+use multi_buffer::{Anchor, ExcerptRange, MultiBuffer, PathKey};
 use project::Project;
 use rope::Point;
-use text::{BufferId, OffsetRangeExt as _};
 use ui::{
     App, Context, InteractiveElement as _, IntoElement as _, ParentElement as _, Render,
     Styled as _, Window, div,
@@ -140,86 +137,18 @@ impl SplittableEditor {
             return;
         };
         let project = workspace.read(cx).project().clone();
-        let language_registry = project.read(cx).languages().clone();
-
-        let primary_multibuffer = self.primary_editor.read(cx).buffer().read(cx);
-
-        let base_text_buffers_by_main_buffer_id: HashMap<
-            BufferId,
-            (Entity<Buffer>, BufferDiffSnapshot),
-        > = primary_multibuffer
-            .all_buffer_ids_iter()
-            .filter_map(|main_buffer_id| {
-                let diff = primary_multibuffer.diff_for(main_buffer_id)?;
-                let base_text_buffer = cx.new(|cx| {
-                    let base_text = diff.read(cx).base_text();
-                    let mut buffer = Buffer::local_normalized(
-                        base_text.as_rope().clone(),
-                        base_text.line_ending(),
-                        cx,
-                    );
-                    buffer.set_language(base_text.language().cloned(), cx);
-                    buffer.set_language_registry(language_registry.clone());
-                    buffer
-                });
-                Some((
-                    main_buffer_id,
-                    (base_text_buffer, diff.read(cx).snapshot(cx)),
-                ))
-            })
-            .collect();
-        let snapshot = primary_multibuffer.snapshot(cx);
-        let mut excerpt_ranges_by_base_buffer: HashMap<
-            Entity<Buffer>,
-            (PathKey, Vec<ExcerptRange<Point>>),
-        > = HashMap::default();
-        for (path_key, excerpt_id) in primary_multibuffer.excerpts_with_paths() {
-            let main_buffer = snapshot.buffer_for_excerpt(*excerpt_id).unwrap();
-            let excerpt_range = snapshot.excerpt_range_for_excerpt(*excerpt_id).unwrap();
-            let (base_text_buffer, diff) = base_text_buffers_by_main_buffer_id
-                .get(&main_buffer.remote_id())
-                .unwrap();
-            let point_to_base_text_point = |point: Point| {
-                let row = diff.row_to_base_text_row(point.row, &main_buffer);
-                let column = diff.base_text().line_len(row);
-                Point::new(row, column)
-            };
-            let primary = excerpt_range.primary.to_point(&main_buffer);
-            let context = excerpt_range.context.to_point(&main_buffer);
-            let translated_range = ExcerptRange {
-                primary: point_to_base_text_point(primary.start)
-                    ..point_to_base_text_point(primary.end),
-                context: point_to_base_text_point(context.start)
-                    ..point_to_base_text_point(context.end),
-            };
-            excerpt_ranges_by_base_buffer
-                .entry(base_text_buffer.clone())
-                .or_insert((path_key.clone(), Vec::new()))
-                .1
-                .push(translated_range);
-        }
-
-        let secondary_multibuffer = cx.new(|cx| {
-            let mut multibuffer = MultiBuffer::new(Capability::ReadOnly);
-            for (base_text_buffer, (path_key, ranges)) in excerpt_ranges_by_base_buffer {
-                let base_text_buffer_snapshot = base_text_buffer.read(cx).snapshot();
-                multibuffer.update_path_excerpts(
-                    path_key,
-                    base_text_buffer,
-                    &base_text_buffer_snapshot,
-                    ranges,
-                    cx,
-                );
-            }
-            multibuffer
-        });
-        let secondary_editor =
-            cx.new(|cx| Editor::for_multibuffer(secondary_multibuffer, Some(project), window, cx));
 
         // FIXME
         // - have to subscribe to the diffs to update the base text buffers (and handle language changed I think?)
-        // - implement SplittableEditor::set_excerpts_for_path
 
+        let secondary_editor = cx.new(|cx| {
+            let multibuffer = cx.new(|cx| {
+                let mut multibuffer = MultiBuffer::new(Capability::ReadOnly);
+                multibuffer.set_all_diff_hunks_expanded(cx);
+                multibuffer
+            });
+            Editor::for_multibuffer(multibuffer, Some(project.clone()), window, cx)
+        });
         let secondary_pane = cx.new(|cx| {
             let mut pane = Pane::new(
                 workspace.downgrade(),
@@ -260,15 +189,20 @@ impl SplittableEditor {
             has_latest_selection: false,
             _subscriptions: subscriptions,
         };
-        for (path_key, diff, original_range, original_buffer) in whatever {
-            secondary.sync_path_excerpts_for_buffer(
-                path_key,
-                diff,
-                original_range,
-                original_buffer,
-                cx,
-            );
-        }
+        self.primary_editor.update(cx, |editor, cx| {
+            editor.buffer().update(cx, |primary_multibuffer, cx| {
+                primary_multibuffer.set_show_deleted_hunks(false, cx);
+                let paths = primary_multibuffer.paths().collect::<Vec<_>>();
+                for path in paths {
+                    secondary.sync_path_excerpts(
+                        path,
+                        primary_multibuffer,
+                        project.read(cx).languages().clone(),
+                        cx,
+                    );
+                }
+            })
+        });
         self.secondary = Some(secondary);
 
         let primary_pane = self.panes.first_pane();
@@ -284,8 +218,8 @@ impl SplittableEditor {
         };
         self.panes.remove(&secondary.pane).unwrap();
         self.primary_editor.update(cx, |primary, cx| {
-            primary.buffer().update(cx, |buffer, _| {
-                buffer.set_filter_mode(None);
+            primary.buffer().update(cx, |buffer, cx| {
+                buffer.set_show_deleted_hunks(true, cx);
             });
         });
         cx.notify();
@@ -316,17 +250,28 @@ impl SplittableEditor {
         context_line_count: u32,
         cx: &mut Context<Self>,
     ) -> (Vec<Range<Anchor>>, bool) {
-        let (anchors, added_a_new_excerpt) =
-            self.primary_editor
-                .read(cx)
-                .buffer()
-                .update(cx, |multibuffer, cx| {
-                    multibuffer.set_excerpts_for_path(path, buffer, ranges, context_line_count, cx)
-                });
-        if let Some(secondary) = &mut self.secondary {
-            secondary.sync_path_excerpts_for_buffer(cx);
-        }
-        (anchors, added_a_new_excerpt)
+        self.primary_editor.update(cx, |editor, cx| {
+            editor.buffer().update(cx, |primary_multibuffer, cx| {
+                let (anchors, added_a_new_excerpt) = primary_multibuffer.set_excerpts_for_path(
+                    path.clone(),
+                    buffer,
+                    ranges,
+                    context_line_count,
+                    cx,
+                );
+                if let Some(secondary) = &mut self.secondary
+                    && let Some(languages) = self
+                        .workspace
+                        .update(cx, |workspace, cx| {
+                            workspace.project().read(cx).languages().clone()
+                        })
+                        .ok()
+                {
+                    secondary.sync_path_excerpts(path, primary_multibuffer, languages, cx);
+                }
+                (anchors, added_a_new_excerpt)
+            })
+        })
     }
 }
 
@@ -367,35 +312,62 @@ impl Render for SplittableEditor {
 }
 
 impl SecondaryEditor {
-    fn sync_path_excerpts_for_buffer(
+    fn sync_path_excerpts(
         &mut self,
         path_key: PathKey,
-        main_buffer: &BufferSnapshot,
-        primary_multibuffer: &MultiBuffer,
+        primary_multibuffer: &mut MultiBuffer,
+        languages: Arc<LanguageRegistry>,
         cx: &mut App,
     ) {
+        let excerpt_id = primary_multibuffer
+            .excerpts_for_path(&path_key)
+            .next()
+            .unwrap();
+        let primary_multibuffer_snapshot = primary_multibuffer.snapshot(cx);
+        let main_buffer = primary_multibuffer_snapshot
+            .buffer_for_excerpt(excerpt_id)
+            .unwrap();
         let diff = primary_multibuffer
             .diff_for(main_buffer.remote_id())
             .unwrap();
         let diff = diff.read(cx).snapshot(cx);
-        // option 1: hold onto the base text buffers in splittable editor so that we can check whether they exist yet
-        // option 2: have the multibuffer continue to be fully responsible for holding the base text buffers; then need to be able to get a buffer out of the multibuffer based on a pathkey
-        let base_text_buffer = self.editor.update(cx, |editor, cx| {
-            editor
-                .buffer()
-                .update(cx, |buffer, cx| buffer.buffer_for_path_key)
-        });
+        let base_text_buffer = self
+            .editor
+            .update(cx, |editor, cx| {
+                editor.buffer().update(cx, |secondary_multibuffer, cx| {
+                    let excerpt_id = secondary_multibuffer.excerpts_for_path(&path_key).next()?;
+                    let secondary_buffer_snapshot = secondary_multibuffer.snapshot(cx);
+                    let buffer = secondary_buffer_snapshot
+                        .buffer_for_excerpt(excerpt_id)
+                        .unwrap();
+                    Some(secondary_multibuffer.buffer(buffer.remote_id()).unwrap())
+                })
+            })
+            .unwrap_or_else(|| {
+                cx.new(|cx| {
+                    let base_text = diff.base_text();
+                    let mut buffer = Buffer::local_normalized(
+                        base_text.as_rope().clone(),
+                        base_text.line_ending(),
+                        cx,
+                    );
+                    buffer.set_language(base_text.language().cloned(), cx);
+                    buffer.set_language_registry(languages);
+                    buffer
+                })
+            });
+        let base_text_buffer_snapshot = base_text_buffer.read(cx).snapshot();
         let new = primary_multibuffer
             .excerpts_for_buffer(main_buffer.remote_id(), cx)
             .into_iter()
-            .map(|(excerpt_id, excerpt_range)| {
+            .map(|(_, excerpt_range)| {
                 let point_to_base_text_point = |point: Point| {
-                    let row = diff.row_to_base_text_row(point.row, &main_buffer);
+                    let row = diff.row_to_base_text_row(point.row, main_buffer);
                     let column = diff.base_text().line_len(row);
                     Point::new(row, column)
                 };
-                let primary = excerpt_range.primary.to_point(&main_buffer);
-                let context = excerpt_range.context.to_point(&main_buffer);
+                let primary = excerpt_range.primary.to_point(main_buffer);
+                let context = excerpt_range.context.to_point(main_buffer);
                 ExcerptRange {
                     primary: point_to_base_text_point(primary.start)
                         ..point_to_base_text_point(primary.end),
@@ -410,7 +382,7 @@ impl SecondaryEditor {
                 buffer.update_path_excerpts(
                     path_key,
                     base_text_buffer,
-                    base_text_buffer_snapshot,
+                    &base_text_buffer_snapshot,
                     new,
                     cx,
                 )

crates/multi_buffer/src/multi_buffer.rs 🔗

@@ -610,6 +610,7 @@ pub struct MultiBufferSnapshot {
     replaced_excerpts: TreeMap<ExcerptId, ExcerptId>,
     trailing_excerpt_update_count: usize,
     all_diff_hunks_expanded: bool,
+    show_deleted_hunks: bool,
     show_headers: bool,
 }
 
@@ -1089,6 +1090,7 @@ impl MultiBuffer {
             capability,
             MultiBufferSnapshot {
                 show_headers: true,
+                show_deleted_hunks: true,
                 ..MultiBufferSnapshot::default()
             },
         )
@@ -1862,6 +1864,7 @@ impl MultiBuffer {
             replaced_excerpts,
             trailing_excerpt_update_count,
             all_diff_hunks_expanded: _,
+            show_deleted_hunks: _,
             show_headers: _,
         } = self.snapshot.get_mut();
         let start = ExcerptDimension(MultiBufferOffset::ZERO);
@@ -2652,6 +2655,11 @@ impl MultiBuffer {
         self.expand_or_collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], false, cx);
     }
 
+    pub fn set_show_deleted_hunks(&mut self, show: bool, cx: &mut Context<Self>) {
+        self.snapshot.get_mut().show_deleted_hunks = show;
+        self.expand_or_collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], true, cx);
+    }
+
     pub fn has_multiple_hunks(&self, cx: &App) -> bool {
         self.read(cx)
             .diff_hunks_in_range(Anchor::min()..Anchor::max())
@@ -2989,6 +2997,7 @@ impl MultiBuffer {
             replaced_excerpts: _,
             trailing_excerpt_update_count: _,
             all_diff_hunks_expanded: _,
+            show_deleted_hunks: _,
             show_headers: _,
         } = snapshot;
         *is_dirty = false;
@@ -3382,10 +3391,10 @@ impl MultiBuffer {
                             excerpt.id
                         );
 
-                        // FIXME don't push the deleted region if this is the RHS of a split
                         if !hunk.diff_base_byte_range.is_empty()
                             && hunk_buffer_range.start >= edit_buffer_start
                             && hunk_buffer_range.start <= excerpt_buffer_end
+                            && snapshot.show_deleted_hunks
                         {
                             let base_text = diff.base_text();
                             let mut text_cursor =

crates/multi_buffer/src/path_key.rs 🔗

@@ -69,6 +69,14 @@ impl MultiBuffer {
             .flat_map(|(key, ex_ids)| ex_ids.iter().map(move |id| (key, id)))
     }
 
+    pub fn excerpts_for_path(&self, path: &PathKey) -> impl '_ + Iterator<Item = ExcerptId> {

+        self.excerpts_by_path

+            .get(path)

+            .into_iter()

+            .flatten()

+            .copied()

+    }

+

     /// Sets excerpts, returns `true` if at least one new excerpt was added.
     pub fn set_excerpts_for_path(
         &mut self,