git: Use LHS/RHS terminology consistently for side-by-side diff (#47949)

Cole Miller , cameron , and Jakub Konka created

We were using primary/secondary in some places which is just
unnecessarily confusing.

Release Notes:

- N/A

Co-authored-by: cameron <cameron.studdstreet@gmail.com>
Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>

Change summary

crates/agent_ui/src/text_thread_editor.rs |   4 
crates/editor/src/split.rs                | 559 ++++++++++++------------
crates/editor/src/split_editor_view.rs    |   6 
crates/git_ui/src/project_diff.rs         | 106 ++--
4 files changed, 325 insertions(+), 350 deletions(-)

Detailed changes

crates/agent_ui/src/text_thread_editor.rs 🔗

@@ -1551,7 +1551,7 @@ impl TextThreadEditor {
             project_diff
                 .editor()
                 .read(cx)
-                .primary_editor()
+                .rhs_editor()
                 .read(cx)
                 .buffer()
                 .clone()
@@ -1560,7 +1560,7 @@ impl TextThreadEditor {
         // Extract all stored comments from all hunks
         let all_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)> =
             project_diff.update(cx, |project_diff, cx| {
-                let editor = project_diff.editor().read(cx).primary_editor().clone();
+                let editor = project_diff.editor().read(cx).rhs_editor().clone();
                 editor.update(cx, |editor, cx| editor.take_all_review_comments(cx))
             });
 

crates/editor/src/split.rs 🔗

@@ -270,9 +270,9 @@ struct JumpToCorrespondingRow;
 pub struct ToggleLockedCursors;
 
 pub struct SplittableEditor {
-    primary_multibuffer: Entity<MultiBuffer>,
-    primary_editor: Entity<Editor>,
-    secondary: Option<SecondaryEditor>,
+    rhs_multibuffer: Entity<MultiBuffer>,
+    rhs_editor: Entity<Editor>,
+    lhs: Option<LhsEditor>,
     panes: PaneGroup,
     workspace: WeakEntity<Workspace>,
     split_state: Entity<SplitEditorState>,
@@ -280,7 +280,7 @@ pub struct SplittableEditor {
     _subscriptions: Vec<Subscription>,
 }
 
-struct SecondaryEditor {
+struct LhsEditor {
     multibuffer: Entity<MultiBuffer>,
     editor: Entity<Editor>,
     pane: Entity<Pane>,
@@ -289,42 +289,38 @@ struct SecondaryEditor {
 }
 
 impl SplittableEditor {
-    pub fn primary_editor(&self) -> &Entity<Editor> {
-        &self.primary_editor
+    pub fn rhs_editor(&self) -> &Entity<Editor> {
+        &self.rhs_editor
     }
 
-    pub fn secondary_editor(&self) -> Option<&Entity<Editor>> {
-        self.secondary.as_ref().map(|s| &s.editor)
+    pub fn lhs_editor(&self) -> Option<&Entity<Editor>> {
+        self.lhs.as_ref().map(|s| &s.editor)
     }
 
     pub fn is_split(&self) -> bool {
-        self.secondary.is_some()
+        self.lhs.is_some()
     }
 
     pub fn last_selected_editor(&self) -> &Entity<Editor> {
-        if let Some(secondary) = &self.secondary
-            && secondary.has_latest_selection
+        if let Some(lhs) = &self.lhs
+            && lhs.has_latest_selection
         {
-            &secondary.editor
+            &lhs.editor
         } else {
-            &self.primary_editor
+            &self.rhs_editor
         }
     }
 
     pub fn new_unsplit(
-        primary_multibuffer: Entity<MultiBuffer>,
+        rhs_multibuffer: Entity<MultiBuffer>,
         project: Entity<Project>,
         workspace: Entity<Workspace>,
         window: &mut Window,
         cx: &mut Context<Self>,
     ) -> Self {
-        let primary_editor = cx.new(|cx| {
-            let mut editor = Editor::for_multibuffer(
-                primary_multibuffer.clone(),
-                Some(project.clone()),
-                window,
-                cx,
-            );
+        let rhs_editor = cx.new(|cx| {
+            let mut editor =
+                Editor::for_multibuffer(rhs_multibuffer.clone(), Some(project.clone()), window, cx);
             editor.set_expand_all_diff_hunks(cx);
             editor
         });
@@ -340,38 +336,39 @@ impl SplittableEditor {
                 cx,
             );
             pane.set_should_display_tab_bar(|_, _| false);
-            pane.add_item(primary_editor.boxed_clone(), true, true, None, window, cx);
+            pane.add_item(rhs_editor.boxed_clone(), true, true, None, window, cx);
             pane
         });
         let panes = PaneGroup::new(pane);
-        // TODO(split-diff) we might want to tag editor events with whether they came from primary/secondary
-        let subscriptions = vec![cx.subscribe(
-            &primary_editor,
-            |this, _, event: &EditorEvent, cx| match event {
-                EditorEvent::ExpandExcerptsRequested {
-                    excerpt_ids,
-                    lines,
-                    direction,
-                } => {
-                    this.expand_excerpts(excerpt_ids.iter().copied(), *lines, *direction, cx);
-                }
-                EditorEvent::SelectionsChanged { .. } => {
-                    if let Some(secondary) = &mut this.secondary {
-                        secondary.has_latest_selection = false;
+        // TODO(split-diff) we might want to tag editor events with whether they came from rhs/lhs
+        let subscriptions =
+            vec![cx.subscribe(
+                &rhs_editor,
+                |this, _, event: &EditorEvent, cx| match event {
+                    EditorEvent::ExpandExcerptsRequested {
+                        excerpt_ids,
+                        lines,
+                        direction,
+                    } => {
+                        this.expand_excerpts(excerpt_ids.iter().copied(), *lines, *direction, cx);
                     }
-                    cx.emit(event.clone());
-                }
-                _ => cx.emit(event.clone()),
-            },
-        )];
+                    EditorEvent::SelectionsChanged { .. } => {
+                        if let Some(lhs) = &mut this.lhs {
+                            lhs.has_latest_selection = false;
+                        }
+                        cx.emit(event.clone());
+                    }
+                    _ => cx.emit(event.clone()),
+                },
+            )];
 
         window.defer(cx, {
             let workspace = workspace.downgrade();
-            let primary_editor = primary_editor.downgrade();
+            let rhs_editor = rhs_editor.downgrade();
             move |window, cx| {
                 workspace
                     .update(cx, |workspace, cx| {
-                        primary_editor.update(cx, |editor, cx| {
+                        rhs_editor.update(cx, |editor, cx| {
                             editor.added_to_workspace(workspace, window, cx);
                         })
                     })
@@ -380,9 +377,9 @@ impl SplittableEditor {
         });
         let split_state = cx.new(|cx| SplitEditorState::new(cx));
         Self {
-            primary_editor,
-            primary_multibuffer,
-            secondary: None,
+            rhs_editor,
+            rhs_multibuffer,
+            lhs: None,
             panes,
             workspace: workspace.downgrade(),
             split_state,
@@ -395,7 +392,7 @@ impl SplittableEditor {
         if !cx.has_flag::<SplitDiffFeatureFlag>() {
             return;
         }
-        if self.secondary.is_some() {
+        if self.lhs.is_some() {
             return;
         }
         let Some(workspace) = self.workspace.upgrade() else {
@@ -403,23 +400,19 @@ impl SplittableEditor {
         };
         let project = workspace.read(cx).project().clone();
 
-        let secondary_multibuffer = cx.new(|cx| {
+        let lhs_multibuffer = cx.new(|cx| {
             let mut multibuffer = MultiBuffer::new(Capability::ReadOnly);
             multibuffer.set_all_diff_hunks_expanded(cx);
             multibuffer
         });
-        let secondary_editor = cx.new(|cx| {
-            let mut editor = Editor::for_multibuffer(
-                secondary_multibuffer.clone(),
-                Some(project.clone()),
-                window,
-                cx,
-            );
+        let lhs_editor = cx.new(|cx| {
+            let mut editor =
+                Editor::for_multibuffer(lhs_multibuffer.clone(), Some(project.clone()), window, cx);
             editor.number_deleted_lines = true;
             editor.set_delegate_expand_excerpts(true);
             editor
         });
-        let secondary_pane = cx.new(|cx| {
+        let lhs_pane = cx.new(|cx| {
             let mut pane = Pane::new(
                 workspace.downgrade(),
                 workspace.read(cx).project().clone(),
@@ -432,7 +425,7 @@ impl SplittableEditor {
             );
             pane.set_should_display_tab_bar(|_, _| false);
             pane.add_item(
-                ItemHandle::boxed_clone(&secondary_editor),
+                ItemHandle::boxed_clone(&lhs_editor),
                 false,
                 false,
                 None,
@@ -442,83 +435,81 @@ impl SplittableEditor {
             pane
         });
 
-        let subscriptions = vec![cx.subscribe(
-            &secondary_editor,
-            |this, _, event: &EditorEvent, cx| match event {
-                EditorEvent::ExpandExcerptsRequested {
-                    excerpt_ids,
-                    lines,
-                    direction,
-                } => {
-                    if this.secondary.is_some() {
-                        let primary_display_map = this.primary_editor.read(cx).display_map.read(cx);
-                        let primary_ids: Vec<_> = excerpt_ids
-                            .iter()
-                            .filter_map(|id| {
-                                primary_display_map.companion_excerpt_to_my_excerpt(*id, cx)
-                            })
-                            .collect();
-                        this.expand_excerpts(primary_ids.into_iter(), *lines, *direction, cx);
+        let subscriptions =
+            vec![cx.subscribe(
+                &lhs_editor,
+                |this, _, event: &EditorEvent, cx| match event {
+                    EditorEvent::ExpandExcerptsRequested {
+                        excerpt_ids,
+                        lines,
+                        direction,
+                    } => {
+                        if this.lhs.is_some() {
+                            let rhs_display_map = this.rhs_editor.read(cx).display_map.read(cx);
+                            let rhs_ids: Vec<_> = excerpt_ids
+                                .iter()
+                                .filter_map(|id| {
+                                    rhs_display_map.companion_excerpt_to_my_excerpt(*id, cx)
+                                })
+                                .collect();
+                            this.expand_excerpts(rhs_ids.into_iter(), *lines, *direction, cx);
+                        }
                     }
-                }
-                EditorEvent::SelectionsChanged { .. } => {
-                    if let Some(secondary) = &mut this.secondary {
-                        secondary.has_latest_selection = true;
+                    EditorEvent::SelectionsChanged { .. } => {
+                        if let Some(lhs) = &mut this.lhs {
+                            lhs.has_latest_selection = true;
+                        }
+                        cx.emit(event.clone());
                     }
-                    cx.emit(event.clone());
-                }
-                _ => cx.emit(event.clone()),
-            },
-        )];
-        let mut secondary = SecondaryEditor {
-            editor: secondary_editor,
-            multibuffer: secondary_multibuffer,
-            pane: secondary_pane.clone(),
+                    _ => cx.emit(event.clone()),
+                },
+            )];
+        let mut lhs = LhsEditor {
+            editor: lhs_editor,
+            multibuffer: lhs_multibuffer,
+            pane: lhs_pane.clone(),
             has_latest_selection: false,
             _subscriptions: subscriptions,
         };
-        let primary_display_map = self.primary_editor.read(cx).display_map.clone();
-        let secondary_display_map = secondary.editor.read(cx).display_map.clone();
-        let rhs_display_map_id = primary_display_map.entity_id();
+        let rhs_display_map = self.rhs_editor.read(cx).display_map.clone();
+        let lhs_display_map = lhs.editor.read(cx).display_map.clone();
+        let rhs_display_map_id = rhs_display_map.entity_id();
 
-        self.primary_editor.update(cx, |editor, cx| {
+        self.rhs_editor.update(cx, |editor, cx| {
             editor.set_delegate_expand_excerpts(true);
-            editor.buffer().update(cx, |primary_multibuffer, cx| {
-                primary_multibuffer.set_show_deleted_hunks(false, cx);
-                primary_multibuffer.set_use_extended_diff_range(true, cx);
+            editor.buffer().update(cx, |rhs_multibuffer, cx| {
+                rhs_multibuffer.set_show_deleted_hunks(false, cx);
+                rhs_multibuffer.set_use_extended_diff_range(true, cx);
             })
         });
 
         let path_diffs: Vec<_> = {
-            let primary_multibuffer = self.primary_multibuffer.read(cx);
-            primary_multibuffer
+            let rhs_multibuffer = self.rhs_multibuffer.read(cx);
+            rhs_multibuffer
                 .paths()
                 .filter_map(|path| {
-                    let excerpt_id = primary_multibuffer.excerpts_for_path(path).next()?;
-                    let snapshot = primary_multibuffer.snapshot(cx);
+                    let excerpt_id = rhs_multibuffer.excerpts_for_path(path).next()?;
+                    let snapshot = rhs_multibuffer.snapshot(cx);
                     let buffer = snapshot.buffer_for_excerpt(excerpt_id)?;
-                    let diff = primary_multibuffer.diff_for(buffer.remote_id())?;
+                    let diff = rhs_multibuffer.diff_for(buffer.remote_id())?;
                     Some((path.clone(), diff))
                 })
                 .collect()
         };
 
-        let primary_folded_buffers = primary_display_map.read(cx).folded_buffers().clone();
+        let rhs_folded_buffers = rhs_display_map.read(cx).folded_buffers().clone();
 
         let mut companion = Companion::new(
             rhs_display_map_id,
-            primary_folded_buffers,
+            rhs_folded_buffers,
             convert_rhs_rows_to_lhs,
             convert_lhs_rows_to_rhs,
         );
 
         for (path, diff) in path_diffs {
-            for (lhs, rhs) in secondary.update_path_excerpts_from_primary(
-                path,
-                &self.primary_multibuffer,
-                diff.clone(),
-                cx,
-            ) {
+            for (lhs, rhs) in
+                lhs.update_path_excerpts_from_rhs(path, &self.rhs_multibuffer, diff.clone(), cx)
+            {
                 companion.add_excerpt_mapping(lhs, rhs);
             }
             companion.add_buffer_mapping(
@@ -529,22 +520,19 @@ impl SplittableEditor {
 
         let companion = cx.new(|_| companion);
 
-        primary_display_map.update(cx, |dm, cx| {
-            dm.set_companion(
-                Some((secondary_display_map.downgrade(), companion.clone())),
-                cx,
-            );
+        rhs_display_map.update(cx, |dm, cx| {
+            dm.set_companion(Some((lhs_display_map.downgrade(), companion.clone())), cx);
         });
-        secondary_display_map.update(cx, |dm, cx| {
-            dm.set_companion(Some((primary_display_map.downgrade(), companion)), cx);
+        lhs_display_map.update(cx, |dm, cx| {
+            dm.set_companion(Some((rhs_display_map.downgrade(), companion)), cx);
         });
 
-        let primary_weak = self.primary_editor.downgrade();
-        let secondary_weak = secondary.editor.downgrade();
+        let rhs_weak = self.rhs_editor.downgrade();
+        let lhs_weak = lhs.editor.downgrade();
 
         let this = cx.entity().downgrade();
-        self.primary_editor.update(cx, |editor, _cx| {
-            editor.set_scroll_companion(Some(secondary_weak));
+        self.rhs_editor.update(cx, |editor, _cx| {
+            editor.set_scroll_companion(Some(lhs_weak));
             let this = this.clone();
             editor.set_on_local_selections_changed(Some(Box::new(
                 move |cursor_position, window, cx| {
@@ -560,8 +548,8 @@ impl SplittableEditor {
                 },
             )));
         });
-        secondary.editor.update(cx, |editor, _cx| {
-            editor.set_scroll_companion(Some(primary_weak));
+        lhs.editor.update(cx, |editor, _cx| {
+            editor.set_scroll_companion(Some(rhs_weak));
             let this = this.clone();
             editor.set_on_local_selections_changed(Some(Box::new(
                 move |cursor_position, window, cx| {
@@ -578,25 +566,25 @@ impl SplittableEditor {
             )));
         });
 
-        let primary_scroll_position = self
-            .primary_editor
+        let rhs_scroll_position = self
+            .rhs_editor
             .update(cx, |editor, cx| editor.scroll_position(cx));
-        secondary.editor.update(cx, |editor, cx| {
-            editor.set_scroll_position_internal(primary_scroll_position, false, false, window, cx);
+        lhs.editor.update(cx, |editor, cx| {
+            editor.set_scroll_position_internal(rhs_scroll_position, false, false, window, cx);
         });
 
-        // Copy soft wrap state from primary (source of truth) to secondary
-        let primary_soft_wrap_override = self.primary_editor.read(cx).soft_wrap_mode_override;
-        secondary.editor.update(cx, |editor, cx| {
-            editor.soft_wrap_mode_override = primary_soft_wrap_override;
+        // Copy soft wrap state from rhs (source of truth) to lhs
+        let rhs_soft_wrap_override = self.rhs_editor.read(cx).soft_wrap_mode_override;
+        lhs.editor.update(cx, |editor, cx| {
+            editor.soft_wrap_mode_override = rhs_soft_wrap_override;
             cx.notify();
         });
 
-        self.secondary = Some(secondary);
+        self.lhs = Some(lhs);
 
-        let primary_pane = self.panes.first_pane();
+        let rhs_pane = self.panes.first_pane();
         self.panes
-            .split(&primary_pane, &secondary_pane, SplitDirection::Left, cx)
+            .split(&rhs_pane, &lhs_pane, SplitDirection::Left, cx)
             .unwrap();
         cx.notify();
     }
@@ -607,13 +595,13 @@ impl SplittableEditor {
         window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        if let Some(secondary) = &mut self.secondary {
-            if !secondary.has_latest_selection {
-                secondary.editor.read(cx).focus_handle(cx).focus(window, cx);
-                secondary.editor.update(cx, |editor, cx| {
+        if let Some(lhs) = &mut self.lhs {
+            if !lhs.has_latest_selection {
+                lhs.editor.read(cx).focus_handle(cx).focus(window, cx);
+                lhs.editor.update(cx, |editor, cx| {
                     editor.request_autoscroll(Autoscroll::fit(), cx);
                 });
-                secondary.has_latest_selection = true;
+                lhs.has_latest_selection = true;
                 cx.notify();
             } else {
                 cx.propagate();
@@ -629,16 +617,13 @@ impl SplittableEditor {
         window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        if let Some(secondary) = &mut self.secondary {
-            if secondary.has_latest_selection {
-                self.primary_editor
-                    .read(cx)
-                    .focus_handle(cx)
-                    .focus(window, cx);
-                self.primary_editor.update(cx, |editor, cx| {
+        if let Some(lhs) = &mut self.lhs {
+            if lhs.has_latest_selection {
+                self.rhs_editor.read(cx).focus_handle(cx).focus(window, cx);
+                self.rhs_editor.update(cx, |editor, cx| {
                     editor.request_autoscroll(Autoscroll::fit(), cx);
                 });
-                secondary.has_latest_selection = false;
+                lhs.has_latest_selection = false;
                 cx.notify();
             } else {
                 cx.propagate();
@@ -664,25 +649,25 @@ impl SplittableEditor {
 
     fn sync_cursor_to_other_side(
         &mut self,
-        from_primary: bool,
+        from_rhs: bool,
         source_point: Point,
         window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        let Some(secondary) = &self.secondary else {
+        let Some(lhs) = &self.lhs else {
             return;
         };
 
-        let target_editor = if from_primary {
-            &secondary.editor
+        let target_editor = if from_rhs {
+            &lhs.editor
         } else {
-            &self.primary_editor
+            &self.rhs_editor
         };
 
-        let (source_multibuffer, target_multibuffer) = if from_primary {
-            (&self.primary_multibuffer, &secondary.multibuffer)
+        let (source_multibuffer, target_multibuffer) = if from_rhs {
+            (&self.rhs_multibuffer, &lhs.multibuffer)
         } else {
-            (&secondary.multibuffer, &self.primary_multibuffer)
+            (&lhs.multibuffer, &self.rhs_multibuffer)
         };
 
         let source_snapshot = source_multibuffer.read(cx).snapshot(cx);
@@ -720,7 +705,7 @@ impl SplittableEditor {
     }
 
     fn toggle_split(&mut self, _: &ToggleSplitDiff, window: &mut Window, cx: &mut Context<Self>) {
-        if self.secondary.is_some() {
+        if self.lhs.is_some() {
             self.unsplit(&UnsplitDiff, window, cx);
         } else {
             self.split(&SplitDiff, window, cx);
@@ -733,7 +718,7 @@ impl SplittableEditor {
         _window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        if self.secondary.is_some() {
+        if self.lhs.is_some() {
             cx.stop_propagation();
         } else {
             cx.propagate();
@@ -746,9 +731,9 @@ impl SplittableEditor {
         _window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        // Only block breakpoint actions when the left (secondary) editor has focus
-        if let Some(secondary) = &self.secondary {
-            if secondary.has_latest_selection {
+        // Only block breakpoint actions when the left (lhs) editor has focus
+        if let Some(lhs) = &self.lhs {
+            if lhs.has_latest_selection {
                 cx.stop_propagation();
             } else {
                 cx.propagate();
@@ -764,9 +749,9 @@ impl SplittableEditor {
         _window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        // Only block breakpoint actions when the left (secondary) editor has focus
-        if let Some(secondary) = &self.secondary {
-            if secondary.has_latest_selection {
+        // Only block breakpoint actions when the left (lhs) editor has focus
+        if let Some(lhs) = &self.lhs {
+            if lhs.has_latest_selection {
                 cx.stop_propagation();
             } else {
                 cx.propagate();
@@ -782,9 +767,9 @@ impl SplittableEditor {
         _window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        // Only block breakpoint actions when the left (secondary) editor has focus
-        if let Some(secondary) = &self.secondary {
-            if secondary.has_latest_selection {
+        // Only block breakpoint actions when the left (lhs) editor has focus
+        if let Some(lhs) = &self.lhs {
+            if lhs.has_latest_selection {
                 cx.stop_propagation();
             } else {
                 cx.propagate();
@@ -800,9 +785,9 @@ impl SplittableEditor {
         _window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        // Only block breakpoint actions when the left (secondary) editor has focus
-        if let Some(secondary) = &self.secondary {
-            if secondary.has_latest_selection {
+        // Only block breakpoint actions when the left (lhs) editor has focus
+        if let Some(lhs) = &self.lhs {
+            if lhs.has_latest_selection {
                 cx.stop_propagation();
             } else {
                 cx.propagate();
@@ -818,7 +803,7 @@ impl SplittableEditor {
         _window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        if self.secondary.is_some() {
+        if self.lhs.is_some() {
             cx.stop_propagation();
         } else {
             cx.propagate();
@@ -831,14 +816,14 @@ impl SplittableEditor {
         window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        if let Some(secondary) = &self.secondary {
+        if let Some(lhs) = &self.lhs {
             cx.stop_propagation();
 
-            let is_secondary_focused = secondary.has_latest_selection;
-            let (focused_editor, other_editor) = if is_secondary_focused {
-                (&secondary.editor, &self.primary_editor)
+            let is_lhs_focused = lhs.has_latest_selection;
+            let (focused_editor, other_editor) = if is_lhs_focused {
+                (&lhs.editor, &self.rhs_editor)
             } else {
-                (&self.primary_editor, &secondary.editor)
+                (&self.rhs_editor, &lhs.editor)
             };
 
             // Toggle the focused editor
@@ -858,23 +843,23 @@ impl SplittableEditor {
     }
 
     fn unsplit(&mut self, _: &UnsplitDiff, _: &mut Window, cx: &mut Context<Self>) {
-        let Some(secondary) = self.secondary.take() else {
+        let Some(lhs) = self.lhs.take() else {
             return;
         };
-        self.panes.remove(&secondary.pane, cx).unwrap();
-        self.primary_editor.update(cx, |primary, cx| {
-            primary.set_on_local_selections_changed(None);
-            primary.set_scroll_companion(None);
-            primary.set_delegate_expand_excerpts(false);
-            primary.buffer().update(cx, |buffer, cx| {
+        self.panes.remove(&lhs.pane, cx).unwrap();
+        self.rhs_editor.update(cx, |rhs, cx| {
+            rhs.set_on_local_selections_changed(None);
+            rhs.set_scroll_companion(None);
+            rhs.set_delegate_expand_excerpts(false);
+            rhs.buffer().update(cx, |buffer, cx| {
                 buffer.set_show_deleted_hunks(true, cx);
                 buffer.set_use_extended_diff_range(false, cx);
             });
-            primary.display_map.update(cx, |dm, cx| {
+            rhs.display_map.update(cx, |dm, cx| {
                 dm.set_companion(None, cx);
             });
         });
-        secondary.editor.update(cx, |editor, _cx| {
+        lhs.editor.update(cx, |editor, _cx| {
             editor.set_on_local_selections_changed(None);
             editor.set_scroll_companion(None);
         });
@@ -888,12 +873,12 @@ impl SplittableEditor {
         cx: &mut Context<Self>,
     ) {
         self.workspace = workspace.weak_handle();
-        self.primary_editor.update(cx, |primary_editor, cx| {
-            primary_editor.added_to_workspace(workspace, window, cx);
+        self.rhs_editor.update(cx, |rhs_editor, cx| {
+            rhs_editor.added_to_workspace(workspace, window, cx);
         });
-        if let Some(secondary) = &self.secondary {
-            secondary.editor.update(cx, |secondary_editor, cx| {
-                secondary_editor.added_to_workspace(workspace, window, cx);
+        if let Some(lhs) = &self.lhs {
+            lhs.editor.update(cx, |lhs_editor, cx| {
+                lhs_editor.added_to_workspace(workspace, window, cx);
             });
         }
     }
@@ -907,40 +892,39 @@ impl SplittableEditor {
         diff: Entity<BufferDiff>,
         cx: &mut Context<Self>,
     ) -> (Vec<Range<Anchor>>, bool) {
-        let primary_display_map = self.primary_editor.read(cx).display_map.clone();
-        let secondary_display_map = self
-            .secondary
+        let rhs_display_map = self.rhs_editor.read(cx).display_map.clone();
+        let lhs_display_map = self
+            .lhs
             .as_ref()
             .map(|s| s.editor.read(cx).display_map.clone());
 
         let (anchors, added_a_new_excerpt) =
-            self.primary_multibuffer
-                .update(cx, |primary_multibuffer, cx| {
-                    let (anchors, added_a_new_excerpt) = primary_multibuffer.set_excerpts_for_path(
-                        path.clone(),
-                        buffer.clone(),
-                        ranges,
-                        context_line_count,
-                        cx,
-                    );
-                    if !anchors.is_empty()
-                        && primary_multibuffer
-                            .diff_for(buffer.read(cx).remote_id())
-                            .is_none_or(|old_diff| old_diff.entity_id() != diff.entity_id())
-                    {
-                        primary_multibuffer.add_diff(diff.clone(), cx);
-                    }
-                    (anchors, added_a_new_excerpt)
-                });
+            self.rhs_multibuffer.update(cx, |rhs_multibuffer, cx| {
+                let (anchors, added_a_new_excerpt) = rhs_multibuffer.set_excerpts_for_path(
+                    path.clone(),
+                    buffer.clone(),
+                    ranges,
+                    context_line_count,
+                    cx,
+                );
+                if !anchors.is_empty()
+                    && rhs_multibuffer
+                        .diff_for(buffer.read(cx).remote_id())
+                        .is_none_or(|old_diff| old_diff.entity_id() != diff.entity_id())
+                {
+                    rhs_multibuffer.add_diff(diff.clone(), cx);
+                }
+                (anchors, added_a_new_excerpt)
+            });
 
-        if let Some(secondary) = &mut self.secondary {
-            if let Some(secondary_display_map) = &secondary_display_map {
-                secondary.sync_path_excerpts(
+        if let Some(lhs) = &mut self.lhs {
+            if let Some(lhs_display_map) = &lhs_display_map {
+                lhs.sync_path_excerpts(
                     path,
-                    &self.primary_multibuffer,
+                    &self.rhs_multibuffer,
                     diff,
-                    &primary_display_map,
-                    secondary_display_map,
+                    &rhs_display_map,
+                    lhs_display_map,
                     cx,
                 );
             }
@@ -957,9 +941,9 @@ impl SplittableEditor {
         cx: &mut Context<Self>,
     ) {
         let mut corresponding_paths = HashMap::default();
-        self.primary_multibuffer.update(cx, |multibuffer, cx| {
+        self.rhs_multibuffer.update(cx, |multibuffer, cx| {
             let snapshot = multibuffer.snapshot(cx);
-            if self.secondary.is_some() {
+            if self.lhs.is_some() {
                 corresponding_paths = excerpt_ids
                     .clone()
                     .map(|excerpt_id| {
@@ -973,16 +957,16 @@ impl SplittableEditor {
             multibuffer.expand_excerpts(excerpt_ids.clone(), lines, direction, cx);
         });
 
-        if let Some(secondary) = &mut self.secondary {
-            let primary_display_map = self.primary_editor.read(cx).display_map.clone();
-            let secondary_display_map = secondary.editor.read(cx).display_map.clone();
+        if let Some(lhs) = &mut self.lhs {
+            let rhs_display_map = self.rhs_editor.read(cx).display_map.clone();
+            let lhs_display_map = lhs.editor.read(cx).display_map.clone();
             for (path, diff) in corresponding_paths {
-                secondary.sync_path_excerpts(
+                lhs.sync_path_excerpts(
                     path,
-                    &self.primary_multibuffer,
+                    &self.rhs_multibuffer,
                     diff,
-                    &primary_display_map,
-                    &secondary_display_map,
+                    &rhs_display_map,
+                    &lhs_display_map,
                     cx,
                 );
             }
@@ -990,21 +974,20 @@ impl SplittableEditor {
     }
 
     pub fn remove_excerpts_for_path(&mut self, path: PathKey, cx: &mut Context<Self>) {
-        self.primary_multibuffer.update(cx, |buffer, cx| {
+        self.rhs_multibuffer.update(cx, |buffer, cx| {
             buffer.remove_excerpts_for_path(path.clone(), cx)
         });
-        if let Some(secondary) = &self.secondary {
-            let primary_display_map = self.primary_editor.read(cx).display_map.clone();
-            let secondary_display_map = secondary.editor.read(cx).display_map.clone();
-            secondary.remove_mappings_for_path(
+        if let Some(lhs) = &self.lhs {
+            let rhs_display_map = self.rhs_editor.read(cx).display_map.clone();
+            let lhs_display_map = lhs.editor.read(cx).display_map.clone();
+            lhs.remove_mappings_for_path(
                 &path,
-                &self.primary_multibuffer,
-                &primary_display_map,
-                &secondary_display_map,
+                &self.rhs_multibuffer,
+                &rhs_display_map,
+                &lhs_display_map,
                 cx,
             );
-            secondary
-                .multibuffer
+            lhs.multibuffer
                 .update(cx, |buffer, cx| buffer.remove_excerpts_for_path(path, cx))
         }
     }
@@ -1021,21 +1004,21 @@ impl SplittableEditor {
 
         self.debug_print(cx);
 
-        let secondary = self.secondary.as_ref().unwrap();
-        let primary_excerpts = self.primary_multibuffer.read(cx).excerpt_ids();
-        let secondary_excerpts = secondary.multibuffer.read(cx).excerpt_ids();
+        let lhs = self.lhs.as_ref().unwrap();
+        let rhs_excerpts = self.rhs_multibuffer.read(cx).excerpt_ids();
+        let lhs_excerpts = lhs.multibuffer.read(cx).excerpt_ids();
         assert_eq!(
-            secondary_excerpts.len(),
-            primary_excerpts.len(),
+            lhs_excerpts.len(),
+            rhs_excerpts.len(),
             "mismatch in excerpt count"
         );
 
         if quiesced {
-            let rhs_snapshot = secondary
+            let rhs_snapshot = lhs
                 .editor
                 .update(cx, |editor, cx| editor.display_snapshot(cx));
             let lhs_snapshot = self
-                .primary_editor
+                .rhs_editor
                 .update(cx, |editor, cx| editor.display_snapshot(cx));
 
             let lhs_max_row = lhs_snapshot.max_point().row();
@@ -1118,20 +1101,20 @@ impl SplittableEditor {
         cx: &mut App,
         mut extract: impl FnMut(&crate::DisplaySnapshot) -> T,
     ) {
-        let secondary = self.secondary.as_ref().expect("requires split");
-        let primary_snapshot = self.primary_editor.update(cx, |editor, cx| {
+        let lhs = self.lhs.as_ref().expect("requires split");
+        let rhs_snapshot = self.rhs_editor.update(cx, |editor, cx| {
             editor.display_map.update(cx, |map, cx| map.snapshot(cx))
         });
-        let secondary_snapshot = secondary.editor.update(cx, |editor, cx| {
+        let lhs_snapshot = lhs.editor.update(cx, |editor, cx| {
             editor.display_map.update(cx, |map, cx| map.snapshot(cx))
         });
 
-        let primary_t = extract(&primary_snapshot);
-        let secondary_t = extract(&secondary_snapshot);
+        let rhs_t = extract(&rhs_snapshot);
+        let lhs_t = extract(&lhs_snapshot);
 
-        if primary_t != secondary_t {
+        if rhs_t != lhs_t {
             self.debug_print(cx);
-            pretty_assertions::assert_eq!(primary_t, secondary_t);
+            pretty_assertions::assert_eq!(rhs_t, lhs_t);
         }
     }
 
@@ -1141,11 +1124,11 @@ impl SplittableEditor {
         use buffer_diff::DiffHunkStatusKind;
 
         assert!(
-            self.secondary.is_some(),
-            "debug_print is only useful when secondary editor exists"
+            self.lhs.is_some(),
+            "debug_print is only useful when lhs editor exists"
         );
 
-        let secondary = self.secondary.as_ref().unwrap();
+        let lhs = self.lhs.as_ref().unwrap();
 
         // Get terminal width, default to 80 if unavailable
         let terminal_width = std::env::var("COLUMNS")
@@ -1158,16 +1141,16 @@ impl SplittableEditor {
         let side_width = (terminal_width - separator.len()) / 2;
 
         // Get display snapshots for both editors
-        let secondary_snapshot = secondary.editor.update(cx, |editor, cx| {
+        let lhs_snapshot = lhs.editor.update(cx, |editor, cx| {
             editor.display_map.update(cx, |map, cx| map.snapshot(cx))
         });
-        let primary_snapshot = self.primary_editor.update(cx, |editor, cx| {
+        let rhs_snapshot = self.rhs_editor.update(cx, |editor, cx| {
             editor.display_map.update(cx, |map, cx| map.snapshot(cx))
         });
 
-        let secondary_max_row = secondary_snapshot.max_point().row().0;
-        let primary_max_row = primary_snapshot.max_point().row().0;
-        let max_row = secondary_max_row.max(primary_max_row);
+        let lhs_max_row = lhs_snapshot.max_point().row().0;
+        let rhs_max_row = rhs_snapshot.max_point().row().0;
+        let max_row = lhs_max_row.max(rhs_max_row);
 
         // Build a map from display row -> block type string
         // Each row of a multi-row block gets an entry with the same block type
@@ -1202,8 +1185,8 @@ impl SplittableEditor {
             block_map
         }
 
-        let secondary_blocks = build_block_map(&secondary_snapshot, secondary_max_row);
-        let primary_blocks = build_block_map(&primary_snapshot, primary_max_row);
+        let lhs_blocks = build_block_map(&lhs_snapshot, lhs_max_row);
+        let rhs_blocks = build_block_map(&rhs_snapshot, rhs_max_row);
 
         fn display_width(s: &str) -> usize {
             unicode_width::UnicodeWidthStr::width(s)
@@ -1335,39 +1318,39 @@ impl SplittableEditor {
         }
 
         // Collect row infos for both sides
-        let secondary_row_infos: Vec<_> = secondary_snapshot
+        let lhs_row_infos: Vec<_> = lhs_snapshot
             .row_infos(DisplayRow(0))
-            .take((secondary_max_row + 1) as usize)
+            .take((lhs_max_row + 1) as usize)
             .collect();
-        let primary_row_infos: Vec<_> = primary_snapshot
+        let rhs_row_infos: Vec<_> = rhs_snapshot
             .row_infos(DisplayRow(0))
-            .take((primary_max_row + 1) as usize)
+            .take((rhs_max_row + 1) as usize)
             .collect();
 
         // Calculate cumulative bytes for each side (only counting non-block rows)
-        let mut secondary_cumulative = Vec::with_capacity((secondary_max_row + 1) as usize);
+        let mut lhs_cumulative = Vec::with_capacity((lhs_max_row + 1) as usize);
         let mut cumulative = 0usize;
-        for row in 0..=secondary_max_row {
-            if !secondary_blocks.contains_key(&row) {
-                cumulative += secondary_snapshot.line(DisplayRow(row)).len() + 1; // +1 for newline
+        for row in 0..=lhs_max_row {
+            if !lhs_blocks.contains_key(&row) {
+                cumulative += lhs_snapshot.line(DisplayRow(row)).len() + 1; // +1 for newline
             }
-            secondary_cumulative.push(cumulative);
+            lhs_cumulative.push(cumulative);
         }
 
-        let mut primary_cumulative = Vec::with_capacity((primary_max_row + 1) as usize);
+        let mut rhs_cumulative = Vec::with_capacity((rhs_max_row + 1) as usize);
         cumulative = 0;
-        for row in 0..=primary_max_row {
-            if !primary_blocks.contains_key(&row) {
-                cumulative += primary_snapshot.line(DisplayRow(row)).len() + 1;
+        for row in 0..=rhs_max_row {
+            if !rhs_blocks.contains_key(&row) {
+                cumulative += rhs_snapshot.line(DisplayRow(row)).len() + 1;
             }
-            primary_cumulative.push(cumulative);
+            rhs_cumulative.push(cumulative);
         }
 
         // Print header
         eprintln!();
         eprintln!("{}", "═".repeat(terminal_width));
-        let header_left = format!("{:^width$}", "SECONDARY (LEFT)", width = side_width);
-        let header_right = format!("{:^width$}", "PRIMARY (RIGHT)", width = side_width);
+        let header_left = format!("{:^width$}", "(LHS)", width = side_width);
+        let header_right = format!("{:^width$}", "(RHS)", width = side_width);
         eprintln!("{}{}{}", header_left, separator, header_right);
         eprintln!(
             "{:^width$}{}{:^width$}",
@@ -1382,20 +1365,20 @@ impl SplittableEditor {
         for row in 0..=max_row {
             let left = format_row(
                 row,
-                secondary_max_row,
-                &secondary_snapshot,
-                &secondary_blocks,
-                &secondary_row_infos,
-                &secondary_cumulative,
+                lhs_max_row,
+                &lhs_snapshot,
+                &lhs_blocks,
+                &lhs_row_infos,
+                &lhs_cumulative,
                 side_width,
             );
             let right = format_row(
                 row,
-                primary_max_row,
-                &primary_snapshot,
-                &primary_blocks,
-                &primary_row_infos,
-                &primary_cumulative,
+                rhs_max_row,
+                &rhs_snapshot,
+                &rhs_blocks,
+                &rhs_row_infos,
+                &rhs_cumulative,
                 side_width,
             );
             eprintln!("{}{}{}", left, separator, right);
@@ -1423,12 +1406,12 @@ impl SplittableEditor {
 
         for _ in 0..mutation_count {
             let paths = self
-                .primary_multibuffer
+                .rhs_multibuffer
                 .read(cx)
                 .paths()
                 .cloned()
                 .collect::<Vec<_>>();
-            let excerpt_ids = self.primary_multibuffer.read(cx).excerpt_ids();
+            let excerpt_ids = self.rhs_multibuffer.read(cx).excerpt_ids();
 
             if rng.random_bool(0.2) && !excerpt_ids.is_empty() {
                 let mut excerpts = HashSet::default();
@@ -1494,7 +1477,7 @@ impl SplittableEditor {
 impl EventEmitter<EditorEvent> for SplittableEditor {}
 impl Focusable for SplittableEditor {
     fn focus_handle(&self, cx: &App) -> gpui::FocusHandle {
-        self.primary_editor.read(cx).focus_handle(cx)
+        self.rhs_editor.read(cx).focus_handle(cx)
     }
 }
 
@@ -1504,11 +1487,11 @@ impl Render for SplittableEditor {
         _window: &mut ui::Window,
         cx: &mut ui::Context<Self>,
     ) -> impl ui::IntoElement {
-        let inner = if self.secondary.is_some() {
-            let style = self.primary_editor.read(cx).create_style(cx);
+        let inner = if self.lhs.is_some() {
+            let style = self.rhs_editor.read(cx).create_style(cx);
             SplitEditorView::new(cx.entity(), style, self.split_state.clone()).into_any_element()
         } else {
-            self.primary_editor.clone().into_any_element()
+            self.rhs_editor.clone().into_any_element()
         };
         div()
             .id("splittable-editor")

crates/editor/src/split_editor_view.rs 🔗

@@ -148,12 +148,12 @@ impl RenderOnce for SplitEditorView {
         let splittable_editor = self.splittable_editor.read(cx);
 
         assert!(
-            splittable_editor.secondary_editor().is_some(),
+            splittable_editor.lhs_editor().is_some(),
             "`SplitEditorView` requires `SplittableEditor` to be in split mode"
         );
 
-        let lhs_editor = splittable_editor.secondary_editor().unwrap().clone();
-        let rhs_editor = splittable_editor.primary_editor().clone();
+        let lhs_editor = splittable_editor.lhs_editor().unwrap().clone();
+        let rhs_editor = splittable_editor.rhs_editor().clone();
 
         let mut lhs = EditorElement::new(&lhs_editor, self.style.clone());
         let mut rhs = EditorElement::new(&rhs_editor, self.style.clone());

crates/git_ui/src/project_diff.rs 🔗

@@ -218,7 +218,7 @@ impl ProjectDiff {
 
     pub fn autoscroll(&self, cx: &mut Context<Self>) {
         self.editor.update(cx, |editor, cx| {
-            editor.primary_editor().update(cx, |editor, cx| {
+            editor.rhs_editor().update(cx, |editor, cx| {
                 editor.request_autoscroll(Autoscroll::fit(), cx);
             })
         })
@@ -288,35 +288,33 @@ impl ProjectDiff {
                 window,
                 cx,
             );
-            diff_display_editor
-                .primary_editor()
-                .update(cx, |editor, cx| {
-                    editor.disable_diagnostics(cx);
-                    editor.set_show_diff_review_button(true, cx);
-
-                    match branch_diff.read(cx).diff_base() {
-                        DiffBase::Head => {
-                            editor.register_addon(GitPanelAddon {
-                                workspace: workspace.downgrade(),
-                            });
-                        }
-                        DiffBase::Merge { .. } => {
-                            editor.register_addon(BranchDiffAddon {
-                                branch_diff: branch_diff.clone(),
-                            });
-                            editor.start_temporary_diff_override();
-                            editor.set_render_diff_hunk_controls(
-                                Arc::new(|_, _, _, _, _, _, _, _| gpui::Empty.into_any_element()),
-                                cx,
-                            );
-                        }
+            diff_display_editor.rhs_editor().update(cx, |editor, cx| {
+                editor.disable_diagnostics(cx);
+                editor.set_show_diff_review_button(true, cx);
+
+                match branch_diff.read(cx).diff_base() {
+                    DiffBase::Head => {
+                        editor.register_addon(GitPanelAddon {
+                            workspace: workspace.downgrade(),
+                        });
                     }
-                });
+                    DiffBase::Merge { .. } => {
+                        editor.register_addon(BranchDiffAddon {
+                            branch_diff: branch_diff.clone(),
+                        });
+                        editor.start_temporary_diff_override();
+                        editor.set_render_diff_hunk_controls(
+                            Arc::new(|_, _, _, _, _, _, _, _| gpui::Empty.into_any_element()),
+                            cx,
+                        );
+                    }
+                }
+            });
             diff_display_editor
         });
         let editor_subscription = cx.subscribe_in(&editor, window, Self::handle_editor_event);
 
-        let primary_editor = editor.read(cx).primary_editor().clone();
+        let primary_editor = editor.read(cx).rhs_editor().clone();
         let review_comment_subscription =
             cx.subscribe(&primary_editor, |this, _editor, event: &EditorEvent, cx| {
                 if let EditorEvent::ReviewCommentsChanged { total_count } = event {
@@ -443,7 +441,7 @@ impl ProjectDiff {
 
     fn move_to_beginning(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         self.editor.update(cx, |editor, cx| {
-            editor.primary_editor().update(cx, |editor, cx| {
+            editor.rhs_editor().update(cx, |editor, cx| {
                 editor.move_to_beginning(&Default::default(), window, cx);
             });
         });
@@ -452,7 +450,7 @@ impl ProjectDiff {
     fn move_to_path(&mut self, path_key: PathKey, window: &mut Window, cx: &mut Context<Self>) {
         if let Some(position) = self.multibuffer.read(cx).location_for_path(&path_key, cx) {
             self.editor.update(cx, |editor, cx| {
-                editor.primary_editor().update(cx, |editor, cx| {
+                editor.rhs_editor().update(cx, |editor, cx| {
                     editor.change_selections(
                         SelectionEffects::scroll(Autoscroll::focused()),
                         window,
@@ -480,7 +478,7 @@ impl ProjectDiff {
 
     fn button_states(&self, cx: &App) -> ButtonStates {
         let is_split = self.editor.read(cx).is_split();
-        let editor = self.editor.read(cx).primary_editor().read(cx);
+        let editor = self.editor.read(cx).rhs_editor().read(cx);
         let snapshot = self.multibuffer.read(cx).snapshot(cx);
         let prev_next = snapshot.diff_hunks().nth(1).is_some();
         let mut selection = true;
@@ -494,7 +492,7 @@ impl ProjectDiff {
             if let Some((excerpt_id, _, range)) = self
                 .editor
                 .read(cx)
-                .primary_editor()
+                .rhs_editor()
                 .read(cx)
                 .active_excerpt(cx)
             {
@@ -603,7 +601,7 @@ impl ProjectDiff {
         let conflict_addon = self
             .editor
             .read(cx)
-            .primary_editor()
+            .rhs_editor()
             .read(cx)
             .addon::<ConflictAddon>()
             .expect("project diff editor should have a conflict addon");
@@ -635,12 +633,7 @@ impl ProjectDiff {
         };
 
         let (was_empty, is_excerpt_newly_added) = self.editor.update(cx, |editor, cx| {
-            let was_empty = editor
-                .primary_editor()
-                .read(cx)
-                .buffer()
-                .read(cx)
-                .is_empty();
+            let was_empty = editor.rhs_editor().read(cx).buffer().read(cx).is_empty();
             let (_, is_newly_added) = editor.set_excerpts_for_path(
                 path_key.clone(),
                 buffer,
@@ -653,7 +646,7 @@ impl ProjectDiff {
         });
 
         self.editor.update(cx, |editor, cx| {
-            editor.primary_editor().update(cx, |editor, cx| {
+            editor.rhs_editor().update(cx, |editor, cx| {
                 if was_empty {
                     editor.change_selections(
                         SelectionEffects::no_scroll(),
@@ -837,7 +830,7 @@ impl Item for ProjectDiff {
 
     fn deactivated(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         self.editor.update(cx, |editor, cx| {
-            editor.primary_editor().update(cx, |primary_editor, cx| {
+            editor.rhs_editor().update(cx, |primary_editor, cx| {
                 primary_editor.deactivated(window, cx);
             })
         });
@@ -850,7 +843,7 @@ impl Item for ProjectDiff {
         cx: &mut Context<Self>,
     ) -> bool {
         self.editor.update(cx, |editor, cx| {
-            editor.primary_editor().update(cx, |primary_editor, cx| {
+            editor.rhs_editor().update(cx, |primary_editor, cx| {
                 primary_editor.navigate(data, window, cx)
             })
         })
@@ -883,7 +876,7 @@ impl Item for ProjectDiff {
 
     fn as_searchable(&self, _: &Entity<Self>, cx: &App) -> Option<Box<dyn SearchableItemHandle>> {
         // TODO(split-diff) SplitEditor should be searchable
-        Some(Box::new(self.editor.read(cx).primary_editor().clone()))
+        Some(Box::new(self.editor.read(cx).rhs_editor().clone()))
     }
 
     fn for_each_project_item(
@@ -893,7 +886,7 @@ impl Item for ProjectDiff {
     ) {
         self.editor
             .read(cx)
-            .primary_editor()
+            .rhs_editor()
             .read(cx)
             .for_each_project_item(cx, f)
     }
@@ -905,7 +898,7 @@ impl Item for ProjectDiff {
         cx: &mut Context<Self>,
     ) {
         self.editor.update(cx, |editor, cx| {
-            editor.primary_editor().update(cx, |primary_editor, _| {
+            editor.rhs_editor().update(cx, |primary_editor, _| {
                 primary_editor.set_nav_history(Some(nav_history));
             })
         });
@@ -952,7 +945,7 @@ impl Item for ProjectDiff {
         cx: &mut Context<Self>,
     ) -> Task<Result<()>> {
         self.editor.update(cx, |editor, cx| {
-            editor.primary_editor().update(cx, |primary_editor, cx| {
+            editor.rhs_editor().update(cx, |primary_editor, cx| {
                 primary_editor.save(options, project, window, cx)
             })
         })
@@ -975,7 +968,7 @@ impl Item for ProjectDiff {
         cx: &mut Context<Self>,
     ) -> Task<Result<()>> {
         self.editor.update(cx, |editor, cx| {
-            editor.primary_editor().update(cx, |primary_editor, cx| {
+            editor.rhs_editor().update(cx, |primary_editor, cx| {
                 primary_editor.reload(project, window, cx)
             })
         })
@@ -990,7 +983,7 @@ impl Item for ProjectDiff {
         if type_id == TypeId::of::<Self>() {
             Some(self_handle.clone().into())
         } else if type_id == TypeId::of::<Editor>() {
-            Some(self.editor.read(cx).primary_editor().clone().into())
+            Some(self.editor.read(cx).rhs_editor().clone().into())
         } else {
             None
         }
@@ -1911,7 +1904,7 @@ mod tests {
         });
         cx.run_until_parked();
 
-        let editor = diff.read_with(cx, |diff, cx| diff.editor.read(cx).primary_editor().clone());
+        let editor = diff.read_with(cx, |diff, cx| diff.editor.read(cx).rhs_editor().clone());
         assert_state_with_diff(
             &editor,
             cx,
@@ -1971,7 +1964,7 @@ mod tests {
                 window,
                 cx,
             );
-            diff.editor.read(cx).primary_editor().clone()
+            diff.editor.read(cx).rhs_editor().clone()
         });
         assert_state_with_diff(
             &editor,
@@ -1992,7 +1985,7 @@ mod tests {
                 window,
                 cx,
             );
-            diff.editor.read(cx).primary_editor().clone()
+            diff.editor.read(cx).rhs_editor().clone()
         });
         assert_state_with_diff(
             &editor,
@@ -2044,8 +2037,7 @@ mod tests {
         });
         cx.run_until_parked();
 
-        let diff_editor =
-            diff.read_with(cx, |diff, cx| diff.editor.read(cx).primary_editor().clone());
+        let diff_editor = diff.read_with(cx, |diff, cx| diff.editor.read(cx).rhs_editor().clone());
 
         assert_state_with_diff(
             &diff_editor,
@@ -2169,7 +2161,7 @@ mod tests {
             workspace.active_item_as::<ProjectDiff>(cx).unwrap()
         });
         cx.focus(&item);
-        let editor = item.read_with(cx, |item, cx| item.editor.read(cx).primary_editor().clone());
+        let editor = item.read_with(cx, |item, cx| item.editor.read(cx).rhs_editor().clone());
 
         let mut cx = EditorTestContext::for_editor_in(editor, cx).await;
 
@@ -2283,7 +2275,7 @@ mod tests {
             workspace.active_item_as::<ProjectDiff>(cx).unwrap()
         });
         cx.focus(&item);
-        let editor = item.read_with(cx, |item, cx| item.editor.read(cx).primary_editor().clone());
+        let editor = item.read_with(cx, |item, cx| item.editor.read(cx).rhs_editor().clone());
 
         let mut cx = EditorTestContext::for_editor_in(editor, cx).await;
 
@@ -2330,7 +2322,7 @@ mod tests {
         cx.run_until_parked();
 
         cx.update(|window, cx| {
-            let editor = diff.read(cx).editor.read(cx).primary_editor().clone();
+            let editor = diff.read(cx).editor.read(cx).rhs_editor().clone();
             let excerpt_ids = editor.read(cx).buffer().read(cx).excerpt_ids();
             assert_eq!(excerpt_ids.len(), 1);
             let excerpt_id = excerpt_ids[0];
@@ -2347,7 +2339,7 @@ mod tests {
                 .read(cx)
                 .editor
                 .read(cx)
-                .primary_editor()
+                .rhs_editor()
                 .read(cx)
                 .addon::<ConflictAddon>()
                 .unwrap()
@@ -2432,7 +2424,7 @@ mod tests {
         );
         cx.run_until_parked();
 
-        let editor = diff.read_with(cx, |diff, cx| diff.editor.read(cx).primary_editor().clone());
+        let editor = diff.read_with(cx, |diff, cx| diff.editor.read(cx).rhs_editor().clone());
 
         assert_state_with_diff(
             &editor,
@@ -2543,7 +2535,7 @@ mod tests {
         );
         cx.run_until_parked();
 
-        let editor = diff.read_with(cx, |diff, cx| diff.editor.read(cx).primary_editor().clone());
+        let editor = diff.read_with(cx, |diff, cx| diff.editor.read(cx).rhs_editor().clone());
 
         assert_state_with_diff(
             &editor,
@@ -2637,7 +2629,7 @@ mod tests {
             workspace.active_item_as::<ProjectDiff>(cx).unwrap()
         });
         cx.focus(&item);
-        let editor = item.read_with(cx, |item, cx| item.editor.read(cx).primary_editor().clone());
+        let editor = item.read_with(cx, |item, cx| item.editor.read(cx).rhs_editor().clone());
 
         fs.set_head_and_index_for_repo(
             Path::new(path!("/project/.git")),