Allow toggling other modals from the command palette

Max Brunsfeld created

Change summary

crates/command_palette/src/command_palette.rs | 31 +++++++++++++++-----
crates/picker/src/picker.rs                   |  6 +++
2 files changed, 28 insertions(+), 9 deletions(-)

Detailed changes

crates/command_palette/src/command_palette.rs 🔗

@@ -27,6 +27,11 @@ pub struct CommandPalette {
 
 pub enum Event {
     Dismissed,
+    Confirmed {
+        window_id: usize,
+        focused_view_id: usize,
+        action: Box<dyn Action>,
+    },
 }
 
 struct Command {
@@ -81,8 +86,18 @@ impl CommandPalette {
         cx: &mut ViewContext<Workspace>,
     ) {
         match event {
-            Event::Dismissed => {
+            Event::Dismissed => workspace.dismiss_modal(cx),
+            Event::Confirmed {
+                window_id,
+                focused_view_id,
+                action,
+            } => {
+                let window_id = *window_id;
+                let focused_view_id = *focused_view_id;
+                let action = (*action).boxed_clone();
                 workspace.dismiss_modal(cx);
+                cx.as_mut()
+                    .defer(move |cx| cx.dispatch_action_at(window_id, focused_view_id, &*action))
             }
         }
     }
@@ -174,15 +189,15 @@ impl PickerDelegate for CommandPalette {
 
     fn confirm(&mut self, cx: &mut ViewContext<Self>) {
         if !self.matches.is_empty() {
-            let window_id = cx.window_id();
             let action_ix = self.matches[self.selected_ix].candidate_id;
-            cx.dispatch_action_at(
-                window_id,
-                self.focused_view_id,
-                self.actions[action_ix].action.as_ref(),
-            )
+            cx.emit(Event::Confirmed {
+                window_id: cx.window_id(),
+                focused_view_id: self.focused_view_id,
+                action: self.actions.remove(action_ix).action,
+            });
+        } else {
+            cx.emit(Event::Dismissed);
         }
-        cx.emit(Event::Dismissed);
     }
 
     fn render_match(&self, ix: usize, selected: bool, cx: &gpui::AppContext) -> gpui::ElementBox {

crates/picker/src/picker.rs 🔗

@@ -20,6 +20,7 @@ pub struct Picker<D: PickerDelegate> {
     list_state: UniformListState,
     update_task: Option<Task<()>>,
     max_size: Vector2F,
+    confirmed: bool,
 }
 
 pub trait PickerDelegate: View {
@@ -138,6 +139,7 @@ impl<D: PickerDelegate> Picker<D> {
             update_task: None,
             delegate,
             max_size: vec2f(500., 420.),
+            confirmed: false,
         };
         cx.defer(|this, cx| this.update_matches(cx));
         this
@@ -156,7 +158,7 @@ impl<D: PickerDelegate> Picker<D> {
     ) {
         match event {
             editor::Event::BufferEdited { .. } => self.update_matches(cx),
-            editor::Event::Blurred => {
+            editor::Event::Blurred if !self.confirmed => {
                 if let Some(delegate) = self.delegate.upgrade(cx) {
                     delegate.update(cx, |delegate, cx| {
                         delegate.dismiss(cx);
@@ -204,6 +206,7 @@ impl<D: PickerDelegate> Picker<D> {
     pub fn select_index(&mut self, action: &SelectIndex, cx: &mut ViewContext<Self>) {
         if let Some(delegate) = self.delegate.upgrade(cx) {
             let index = action.0;
+            self.confirmed = true;
             delegate.update(cx, |delegate, cx| {
                 delegate.set_selected_index(index, cx);
                 delegate.confirm(cx);
@@ -256,6 +259,7 @@ impl<D: PickerDelegate> Picker<D> {
 
     fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
         if let Some(delegate) = self.delegate.upgrade(cx) {
+            self.confirmed = true;
             delegate.update(cx, |delegate, cx| delegate.confirm(cx));
         }
     }