@@ -8,13 +8,12 @@ use anyhow::{Context as _, Result, anyhow};
use buffer_diff::{BufferDiff, DiffHunkSecondaryStatus};
use collections::{HashMap, HashSet};
use editor::{
- Addon, Editor, EditorEvent, SelectionEffects, SplitDiffFeatureFlag, SplittableEditor,
- ToggleSplitDiff,
+ Addon, Editor, EditorEvent, SelectionEffects, SplittableEditor,
actions::{GoToHunk, GoToPreviousHunk, SendReviewToAgent},
multibuffer_context_lines,
scroll::Autoscroll,
};
-use feature_flags::FeatureFlagAppExt as _;
+
use git::{
Commit, StageAll, StageAndNext, ToggleStaged, UnstageAll, UnstageAndNext,
repository::{Branch, RepoPath, Upstream, UpstreamTracking, UpstreamTrackingStatus},
@@ -480,7 +479,6 @@ impl ProjectDiff {
}
fn button_states(&self, cx: &App) -> ButtonStates {
- let is_split = self.editor.read(cx).is_split();
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();
@@ -541,7 +539,6 @@ impl ProjectDiff {
selection,
stage_all,
unstage_all,
- is_split,
}
}
@@ -987,6 +984,8 @@ impl Item for ProjectDiff {
Some(self_handle.clone().into())
} else if type_id == TypeId::of::<Editor>() {
Some(self.editor.read(cx).rhs_editor().clone().into())
+ } else if type_id == TypeId::of::<SplittableEditor>() {
+ Some(self.editor.clone().into())
} else {
None
}
@@ -1293,7 +1292,6 @@ struct ButtonStates {
selection: bool,
stage_all: bool,
unstage_all: bool,
- is_split: bool,
}
impl Render for ProjectDiffToolbar {
@@ -1433,31 +1431,6 @@ impl Render for ProjectDiffToolbar {
)
},
)
- .map(|this| {
- if !cx.has_flag::<SplitDiffFeatureFlag>() {
- return this;
- }
- this.child(
- Button::new(
- "toggle-split",
- if button_states.is_split {
- "Stacked View"
- } else {
- "Split View"
- },
- )
- .tooltip(Tooltip::for_action_title_in(
- "Toggle Split View",
- &ToggleSplitDiff,
- &focus_handle,
- ))
- .on_click(cx.listener(
- |this, _, window, cx| {
- this.dispatch_action(&ToggleSplitDiff, window, cx);
- },
- )),
- )
- })
.child(
Button::new("commit", "Commit")
.tooltip(Tooltip::for_action_title_in(
@@ -13,14 +13,16 @@ use crate::{
use any_vec::AnyVec;
use collections::HashMap;
use editor::{
- DisplayPoint, Editor, EditorSettings, MultiBufferOffset,
+ DisplayPoint, Editor, EditorSettings, MultiBufferOffset, SplitDiffFeatureFlag,
+ SplittableEditor, ToggleSplitDiff,
actions::{Backtab, FoldAll, Tab, ToggleFoldAll, UnfoldAll},
};
+use feature_flags::FeatureFlagAppExt as _;
use futures::channel::oneshot;
use gpui::{
Action, App, ClickEvent, Context, Entity, EventEmitter, Focusable, InteractiveElement as _,
IntoElement, KeyContext, ParentElement as _, Render, ScrollHandle, Styled, Subscription, Task,
- Window, actions, div,
+ WeakEntity, Window, actions, div,
};
use language::{Language, LanguageRegistry};
use project::{
@@ -132,6 +134,8 @@ pub struct BufferSearchBar {
editor_needed_width: Pixels,
regex_language: Option<Arc<Language>>,
is_collapsed: bool,
+ splittable_editor: Option<WeakEntity<SplittableEditor>>,
+ _splittable_editor_subscription: Option<Subscription>,
}
impl EventEmitter<Event> for BufferSearchBar {}
@@ -140,32 +144,99 @@ impl Render for BufferSearchBar {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let focus_handle = self.focus_handle(cx);
+ let has_splittable_editor =
+ self.splittable_editor.is_some() && cx.has_flag::<SplitDiffFeatureFlag>();
+ let split_buttons = if has_splittable_editor {
+ self.splittable_editor
+ .as_ref()
+ .and_then(|weak| weak.upgrade())
+ .map(|splittable_editor| {
+ let is_split = splittable_editor.read(cx).is_split();
+ let focus_handle = splittable_editor.focus_handle(cx);
+ h_flex()
+ .gap_0p5()
+ .child(
+ IconButton::new("diff-stacked", IconName::DiffStacked)
+ .shape(IconButtonShape::Square)
+ .toggle_state(!is_split)
+ .tooltip(|_, cx| {
+ Tooltip::for_action("Stacked", &ToggleSplitDiff, cx)
+ })
+ .when(is_split, |button| {
+ let focus_handle = focus_handle.clone();
+ button.on_click(move |_, window, cx| {
+ focus_handle.focus(window, cx);
+ window.dispatch_action(ToggleSplitDiff.boxed_clone(), cx);
+ })
+ }),
+ )
+ .child(
+ IconButton::new("diff-split", IconName::DiffSplit)
+ .shape(IconButtonShape::Square)
+ .toggle_state(is_split)
+ .tooltip(|_, cx| {
+ Tooltip::for_action("Side by Side", &ToggleSplitDiff, cx)
+ })
+ .when(!is_split, |button| {
+ button.on_click({
+ let focus_handle = focus_handle.clone();
+ move |_, window, cx| {
+ focus_handle.focus(window, cx);
+ window
+ .dispatch_action(ToggleSplitDiff.boxed_clone(), cx);
+ }
+ })
+ }),
+ )
+ })
+ } else {
+ None
+ };
+
let collapse_expand_button = if self.needs_expand_collapse_option(cx) {
let query_editor_focus = self.query_editor.focus_handle(cx);
let (icon, label, tooltip_label) = if self.is_collapsed {
- (
- IconName::ChevronUpDown,
- "Expand All",
- "Expand All Search Results",
- )
+ (IconName::ChevronUpDown, "Expand All", "Expand All Files")
} else {
(
IconName::ChevronDownUp,
"Collapse All",
- "Collapse All Search Results",
+ "Collapse All Files",
)
};
if self.dismissed {
- let button = Button::new("multibuffer-collapse-expand-empty", label)
+ if has_splittable_editor {
+ return h_flex()
+ .gap_1()
+ .child(
+ IconButton::new("multibuffer-collapse-expand-empty", icon)
+ .shape(IconButtonShape::Square)
+ .tooltip(move |_, cx| {
+ Tooltip::for_action_in(
+ tooltip_label,
+ &ToggleFoldAll,
+ &query_editor_focus,
+ cx,
+ )
+ })
+ .on_click(|_event, window, cx| {
+ window.dispatch_action(ToggleFoldAll.boxed_clone(), cx)
+ }),
+ )
+ .children(split_buttons)
+ .into_any_element();
+ }
+
+ return Button::new("multibuffer-collapse-expand-empty", label)
.icon_position(IconPosition::Start)
.icon(icon)
.tooltip(move |_, cx| {
Tooltip::for_action_in(
tooltip_label,
&ToggleFoldAll,
- &query_editor_focus.clone(),
+ &query_editor_focus,
cx,
)
})
@@ -173,24 +244,27 @@ impl Render for BufferSearchBar {
window.dispatch_action(ToggleFoldAll.boxed_clone(), cx)
})
.into_any_element();
-
- return button;
}
Some(
- IconButton::new("multibuffer-collapse-expand", icon)
- .shape(IconButtonShape::Square)
- .tooltip(move |_, cx| {
- Tooltip::for_action_in(
- tooltip_label,
- &ToggleFoldAll,
- &query_editor_focus,
- cx,
- )
- })
- .on_click(|_event, window, cx| {
- window.dispatch_action(ToggleFoldAll.boxed_clone(), cx)
- })
+ h_flex()
+ .gap_1()
+ .child(
+ IconButton::new("multibuffer-collapse-expand", icon)
+ .shape(IconButtonShape::Square)
+ .tooltip(move |_, cx| {
+ Tooltip::for_action_in(
+ tooltip_label,
+ &ToggleFoldAll,
+ &query_editor_focus,
+ cx,
+ )
+ })
+ .on_click(|_event, window, cx| {
+ window.dispatch_action(ToggleFoldAll.boxed_clone(), cx)
+ }),
+ )
+ .children(split_buttons)
.into_any_element(),
)
} else {
@@ -558,9 +632,20 @@ impl ToolbarItemView for BufferSearchBar {
cx.notify();
self.active_searchable_item_subscriptions.take();
self.active_searchable_item.take();
+ self.splittable_editor = None;
+ self._splittable_editor_subscription = None;
self.pending_search.take();
+ if let Some(splittable_editor) = item
+ .and_then(|item| item.act_as_type(TypeId::of::<SplittableEditor>(), cx))
+ .and_then(|entity| entity.downcast::<SplittableEditor>().ok())
+ {
+ self._splittable_editor_subscription =
+ Some(cx.observe(&splittable_editor, |_, _, cx| cx.notify()));
+ self.splittable_editor = Some(splittable_editor.downgrade());
+ }
+
if let Some(searchable_item_handle) =
item.and_then(|item| item.to_searchable_item_handle(cx))
{
@@ -818,6 +903,8 @@ impl BufferSearchBar {
editor_needed_width: px(0.),
regex_language: None,
is_collapsed: false,
+ splittable_editor: None,
+ _splittable_editor_subscription: None,
}
}