diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 65bbe3e8f2..adc611125d 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -2233,6 +2233,43 @@ impl Editor { cx.notify(); } + pub fn sync_selections( + &mut self, + other: Entity, + cx: &mut Context, + ) -> gpui::Subscription { + let other_selections = other.read(cx).selections.disjoint.to_vec(); + self.selections.change_with(cx, |selections| { + selections.select_anchors(other_selections); + }); + + let other_subscription = + cx.subscribe(&other, |this, other, other_evt, cx| match other_evt { + EditorEvent::SelectionsChanged { local: true } => { + let other_selections = other.read(cx).selections.disjoint.to_vec(); + this.selections.change_with(cx, |selections| { + selections.select_anchors(other_selections); + }); + } + _ => {} + }); + + let this_subscription = + cx.subscribe_self::(move |this, this_evt, cx| match this_evt { + EditorEvent::SelectionsChanged { local: true } => { + let these_selections = this.selections.disjoint.to_vec(); + other.update(cx, |other_editor, cx| { + other_editor.selections.change_with(cx, |selections| { + selections.select_anchors(these_selections); + }) + }); + } + _ => {} + }); + + Subscription::join(other_subscription, this_subscription) + } + pub fn change_selections( &mut self, autoscroll: Option, diff --git a/crates/git_ui/src/commit_modal.rs b/crates/git_ui/src/commit_modal.rs index f029529065..e3b930f506 100644 --- a/crates/git_ui/src/commit_modal.rs +++ b/crates/git_ui/src/commit_modal.rs @@ -115,27 +115,9 @@ impl CommitModal { return; }; - let (can_open_commit_editor, conflict) = git_panel.update(cx, |git_panel, cx| { - let can_open_commit_editor = git_panel.can_open_commit_editor(); - let conflict = git_panel.has_unstaged_conflicts(); - if can_open_commit_editor { - git_panel.set_modal_open(true, cx); - } - (can_open_commit_editor, conflict) + git_panel.update(cx, |git_panel, cx| { + git_panel.set_modal_open(true, cx); }); - if !can_open_commit_editor { - let message = if conflict { - "There are still conflicts. You must stage these before committing." - } else { - "No changes to commit." - }; - let prompt = window.prompt(PromptLevel::Warning, message, None, &["Ok"], cx); - cx.spawn(|_, _| async move { - prompt.await.ok(); - }) - .detach(); - return; - } let dock = workspace.dock_at_position(git_panel.position(window, cx)); let is_open = dock.read(cx).is_open(); @@ -168,8 +150,16 @@ impl CommitModal { let commit_editor = git_panel.update(cx, |git_panel, cx| { git_panel.set_modal_open(true, cx); let buffer = git_panel.commit_message_buffer(cx).clone(); + let panel_editor = git_panel.commit_editor.clone(); let project = git_panel.project.clone(); - cx.new(|cx| commit_message_editor(buffer, None, project.clone(), false, window, cx)) + + cx.new(|cx| { + let mut editor = + commit_message_editor(buffer, None, project.clone(), false, window, cx); + editor.sync_selections(panel_editor, cx).detach(); + + editor + }) }); let commit_message = commit_editor.read(cx).text(cx); diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 07d4c49080..8ae7dfa633 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -8,6 +8,7 @@ use crate::{ use crate::{picker_prompt, project_diff, ProjectDiff}; use db::kvp::KEY_VALUE_STORE; use editor::commit_tooltip::CommitTooltip; + use editor::{ scroll::ScrollbarAutoHide, Editor, EditorElement, EditorMode, EditorSettings, MultiBuffer, ShowScrollbar, @@ -190,7 +191,7 @@ pub struct GitPanel { remote_operation_id: u32, pending_remote_operations: RemoteOperations, pub(crate) active_repository: Option>, - commit_editor: Entity, + pub(crate) commit_editor: Entity, conflicted_count: usize, conflicted_staged_count: usize, current_modifiers: Modifiers, @@ -1934,7 +1935,7 @@ impl GitPanel { }) } - pub fn can_open_commit_editor(&self) -> bool { + pub fn can_commit(&self) -> bool { (self.has_staged_changes() || self.has_tracked_changes()) && !self.has_unstaged_conflicts() } @@ -2013,7 +2014,6 @@ impl GitPanel { cx: &mut Context, ) -> Option { let active_repository = self.active_repository.clone()?; - let can_open_commit_editor = self.can_open_commit_editor(); let (can_commit, tooltip) = self.configure_commit_button(cx); let project = self.project.clone().read(cx); let panel_editor_style = panel_editor_style(true, window, cx); @@ -2108,7 +2108,6 @@ impl GitPanel { .icon_size(IconSize::Small) .style(ButtonStyle::Transparent) .width(expand_button_size.into()) - .disabled(!can_open_commit_editor) .on_click(cx.listener({ move |_, _, window, cx| { window.dispatch_action( diff --git a/crates/git_ui/src/project_diff.rs b/crates/git_ui/src/project_diff.rs index ea8e5d67ad..c7960e5c5c 100644 --- a/crates/git_ui/src/project_diff.rs +++ b/crates/git_ui/src/project_diff.rs @@ -257,14 +257,12 @@ impl ProjectDiff { } } } - let mut can_open_commit_editor = false; let mut stage_all = false; let mut unstage_all = false; self.workspace .read_with(cx, |workspace, cx| { if let Some(git_panel) = workspace.panel::(cx) { let git_panel = git_panel.read(cx); - can_open_commit_editor = git_panel.can_open_commit_editor(); stage_all = git_panel.can_stage_all(); unstage_all = git_panel.can_unstage_all(); } @@ -276,7 +274,6 @@ impl ProjectDiff { unstage: has_staged_hunks, prev_next, selection, - can_open_commit_editor, stage_all, unstage_all, }; @@ -773,7 +770,6 @@ struct ButtonStates { selection: bool, stage_all: bool, unstage_all: bool, - can_open_commit_editor: bool, } impl Render for ProjectDiffToolbar { @@ -917,7 +913,6 @@ impl Render for ProjectDiffToolbar { ) .child( Button::new("commit", "Commit") - .disabled(!button_states.can_open_commit_editor) .tooltip(Tooltip::for_action_title_in( "Commit", &ShowCommitEditor, diff --git a/crates/gpui/src/app/context.rs b/crates/gpui/src/app/context.rs index 1f813f463f..526a116b6c 100644 --- a/crates/gpui/src/app/context.rs +++ b/crates/gpui/src/app/context.rs @@ -90,6 +90,21 @@ impl<'a, T: 'static> Context<'a, T> { }) } + /// Subscribe to an event type from ourself + pub fn subscribe_self( + &mut self, + mut on_event: impl FnMut(&mut T, &Evt, &mut Context<'_, T>) + 'static, + ) -> Subscription + where + T: 'static + EventEmitter, + Evt: 'static, + { + let this = self.entity(); + self.app.subscribe(&this, move |this, evt, cx| { + this.update(cx, |this, cx| on_event(this, evt, cx)) + }) + } + /// Register a callback to be invoked when GPUI releases this entity. pub fn on_release(&self, on_release: impl FnOnce(&mut T, &mut App) + 'static) -> Subscription where diff --git a/crates/gpui/src/subscription.rs b/crates/gpui/src/subscription.rs index 8a22dd2bbe..d37eaccbb7 100644 --- a/crates/gpui/src/subscription.rs +++ b/crates/gpui/src/subscription.rs @@ -168,6 +168,23 @@ impl Subscription { pub fn detach(mut self) { self.unsubscribe.take(); } + + /// Joins two subscriptions into a single subscription. Detach will + /// detach both interior subscriptions. + pub fn join(mut subscription_a: Self, mut subscription_b: Self) -> Self { + let a_unsubscribe = subscription_a.unsubscribe.take(); + let b_unsubscribe = subscription_b.unsubscribe.take(); + Self { + unsubscribe: Some(Box::new(move || { + if let Some(self_unsubscribe) = a_unsubscribe { + self_unsubscribe(); + } + if let Some(other_unsubscribe) = b_unsubscribe { + other_unsubscribe(); + } + })), + } + } } impl Drop for Subscription {