diff --git a/crates/debugger_ui/src/session/running.rs b/crates/debugger_ui/src/session/running.rs index d3d3d5637e..d948ba3009 100644 --- a/crates/debugger_ui/src/session/running.rs +++ b/crates/debugger_ui/src/session/running.rs @@ -768,7 +768,7 @@ impl RunningState { DropdownMenu::new( ("thread-list", self.session_id.0), selected_thread_name, - ContextMenu::build(window, cx, move |mut this, _, _| { + ContextMenu::build_eager(window, cx, move |mut this, _, _| { for (thread, _) in threads { let state = state.clone(); let thread_id = thread.id; diff --git a/crates/language_tools/src/lsp_log.rs b/crates/language_tools/src/lsp_log.rs index 5e1790bd9f..b90e925fed 100644 --- a/crates/language_tools/src/lsp_log.rs +++ b/crates/language_tools/src/lsp_log.rs @@ -1421,18 +1421,21 @@ impl Render for LspLogToolbarItemView { }) })?; - ContextMenu::build(window, cx, |mut menu, _, _| { - let log_view = log_view.clone(); + ContextMenu::build( + window, + cx, + |mut menu, window, cx| { + let log_view = log_view.clone(); - for (option, label) in [ - (TraceValue::Off, "Off"), - (TraceValue::Messages, "Messages"), - (TraceValue::Verbose, "Verbose"), - ] { - menu = menu.entry(label, None, { - let log_view = log_view.clone(); - move |_, cx| { - log_view.update(cx, |this, cx| { + for (option, label) in [ + (TraceValue::Off, "Off"), + (TraceValue::Messages, "Messages"), + (TraceValue::Verbose, "Verbose"), + ] { + menu = menu.entry(label, None, { + let log_view = log_view.clone(); + move |_, cx| { + log_view.update(cx, |this, cx| { if let Some(id) = this.current_server_id { @@ -1441,15 +1444,16 @@ impl Render for LspLogToolbarItemView { ); } }); + } + }); + if option == trace_level { + menu.select_last(window, cx); } - }); - if option == trace_level { - menu.select_last(); } - } - menu - }) + menu + }, + ) .into() } }), @@ -1480,19 +1484,22 @@ impl Render for LspLogToolbarItemView { }) })?; - ContextMenu::build(window, cx, |mut menu, _, _| { - let log_view = log_view.clone(); + ContextMenu::build( + window, + cx, + |mut menu, window, cx| { + let log_view = log_view.clone(); - for (option, label) in [ - (MessageType::LOG, "Log"), - (MessageType::INFO, "Info"), - (MessageType::WARNING, "Warning"), - (MessageType::ERROR, "Error"), - ] { - menu = menu.entry(label, None, { - let log_view = log_view.clone(); - move |window, cx| { - log_view.update(cx, |this, cx| { + for (option, label) in [ + (MessageType::LOG, "Log"), + (MessageType::INFO, "Info"), + (MessageType::WARNING, "Warning"), + (MessageType::ERROR, "Error"), + ] { + menu = menu.entry(label, None, { + let log_view = log_view.clone(); + move |window, cx| { + log_view.update(cx, |this, cx| { if let Some(id) = this.current_server_id { @@ -1501,15 +1508,16 @@ impl Render for LspLogToolbarItemView { ); } }); + } + }); + if option == log_level { + menu.select_last(window, cx); } - }); - if option == log_level { - menu.select_last(); } - } - menu - }) + menu + }, + ) .into() } }), diff --git a/crates/ui/src/components/context_menu.rs b/crates/ui/src/components/context_menu.rs index 4cf73133e2..5904a4d558 100644 --- a/crates/ui/src/components/context_menu.rs +++ b/crates/ui/src/components/context_menu.rs @@ -135,6 +135,7 @@ pub struct ContextMenu { clicked: bool, _on_blur_subscription: Subscription, keep_open_on_confirm: bool, + eager: bool, documentation_aside: Option<(usize, Rc AnyElement>)>, } @@ -173,6 +174,7 @@ impl ContextMenu { clicked: false, _on_blur_subscription, keep_open_on_confirm: false, + eager: false, documentation_aside: None, }, window, @@ -212,6 +214,40 @@ impl ContextMenu { clicked: false, _on_blur_subscription, keep_open_on_confirm: true, + eager: false, + documentation_aside: None, + }, + window, + cx, + ) + }) + } + + pub fn build_eager( + window: &mut Window, + cx: &mut App, + f: impl FnOnce(Self, &mut Window, &mut Context) -> Self, + ) -> Entity { + cx.new(|cx| { + let focus_handle = cx.focus_handle(); + let _on_blur_subscription = cx.on_blur( + &focus_handle, + window, + |this: &mut ContextMenu, window, cx| this.cancel(&menu::Cancel, window, cx), + ); + window.refresh(); + f( + Self { + builder: None, + items: Default::default(), + focus_handle, + action_context: None, + selected_index: None, + delayed: false, + clicked: false, + _on_blur_subscription, + keep_open_on_confirm: false, + eager: true, documentation_aside: None, }, window, @@ -249,6 +285,7 @@ impl ContextMenu { |this: &mut ContextMenu, window, cx| this.cancel(&menu::Cancel, window, cx), ), keep_open_on_confirm: false, + eager: false, documentation_aside: None, }, window, @@ -435,7 +472,10 @@ impl ContextMenu { .. }) | ContextMenuItem::CustomEntry { handler, .. }, - ) = self.selected_index.and_then(|ix| self.items.get(ix)) + ) = self + .selected_index + .and_then(|ix| self.items.get(ix)) + .filter(|_| !self.eager) { (handler)(context, window, cx) } @@ -452,24 +492,24 @@ impl ContextMenu { cx.emit(DismissEvent); } - fn select_first(&mut self, _: &SelectFirst, _: &mut Window, cx: &mut Context) { + fn select_first(&mut self, _: &SelectFirst, window: &mut Window, cx: &mut Context) { if let Some(ix) = self.items.iter().position(|item| item.is_selectable()) { - self.select_index(ix); + self.select_index(ix, window, cx); } cx.notify(); } - pub fn select_last(&mut self) -> Option { + pub fn select_last(&mut self, window: &mut Window, cx: &mut Context) -> Option { for (ix, item) in self.items.iter().enumerate().rev() { if item.is_selectable() { - return self.select_index(ix); + return self.select_index(ix, window, cx); } } None } - fn handle_select_last(&mut self, _: &SelectLast, _: &mut Window, cx: &mut Context) { - if self.select_last().is_some() { + fn handle_select_last(&mut self, _: &SelectLast, window: &mut Window, cx: &mut Context) { + if self.select_last(window, cx).is_some() { cx.notify(); } } @@ -482,7 +522,7 @@ impl ContextMenu { } else { for (ix, item) in self.items.iter().enumerate().skip(next_index) { if item.is_selectable() { - self.select_index(ix); + self.select_index(ix, window, cx); cx.notify(); break; } @@ -505,7 +545,7 @@ impl ContextMenu { } else { for (ix, item) in self.items.iter().enumerate().take(ix).rev() { if item.is_selectable() { - self.select_index(ix); + self.select_index(ix, window, cx); cx.notify(); break; } @@ -516,7 +556,13 @@ impl ContextMenu { } } - fn select_index(&mut self, ix: usize) -> Option { + fn select_index( + &mut self, + ix: usize, + window: &mut Window, + cx: &mut Context, + ) -> Option { + let context = self.action_context.as_ref(); self.documentation_aside = None; let item = self.items.get(ix)?; if item.is_selectable() { @@ -525,6 +571,9 @@ impl ContextMenu { if let Some(callback) = &entry.documentation_aside { self.documentation_aside = Some((ix, callback.clone())); } + if self.eager && !entry.disabled { + (entry.handler)(context, window, cx) + } } } Some(ix) @@ -553,7 +602,7 @@ impl ContextMenu { false } }) { - self.select_index(ix); + self.select_index(ix, window, cx); self.delayed = true; cx.notify(); let action = dispatched.boxed_clone();