From 3de72f83666ea787e0c32ddc84732467bc65d252 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 22 Dec 2023 10:23:27 +0100 Subject: [PATCH] Fix context menu in tab bar --- crates/collab_ui2/src/collab_panel.rs | 11 +++ .../src/collab_panel/channel_modal.rs | 6 +- crates/copilot_button2/src/copilot_button.rs | 10 ++- crates/language_tools2/src/lsp_log.rs | 1 + .../language_tools2/src/syntax_tree_view.rs | 1 + crates/project_panel2/src/project_panel.rs | 1 + crates/ui2/src/components/context_menu.rs | 13 +++- .../src/components/stories/context_menu.rs | 11 +-- crates/workspace2/src/dock.rs | 2 +- crates/workspace2/src/pane.rs | 74 +++++++++++++++---- 10 files changed, 100 insertions(+), 30 deletions(-) diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index ad11877fd3065f33fc558078eed541aa1f3602c3..3f0115e3fc8a1b40bb578f534ed518aa7b2fc3ae 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -993,6 +993,7 @@ impl CollabPanel { }; context_menu = context_menu.entry( expand_action_name, + None, cx.handler_for(&this, move |this, cx| { this.toggle_channel_collapsed(channel_id, cx) }), @@ -1002,18 +1003,21 @@ impl CollabPanel { context_menu = context_menu .entry( "Open Notes", + None, cx.handler_for(&this, move |this, cx| { this.open_channel_notes(channel_id, cx) }), ) .entry( "Open Chat", + None, cx.handler_for(&this, move |this, cx| { this.join_channel_chat(channel_id, cx) }), ) .entry( "Copy Channel Link", + None, cx.handler_for(&this, move |this, cx| { this.copy_channel_link(channel_id, cx) }), @@ -1024,14 +1028,17 @@ impl CollabPanel { .separator() .entry( "New Subchannel", + None, cx.handler_for(&this, move |this, cx| this.new_subchannel(channel_id, cx)), ) .entry( "Rename", + None, cx.handler_for(&this, move |this, cx| this.rename_channel(channel_id, cx)), ) .entry( "Move this channel", + None, cx.handler_for(&this, move |this, cx| { this.start_move_channel(channel_id, cx) }), @@ -1040,6 +1047,7 @@ impl CollabPanel { if let Some(channel_name) = clipboard_channel_name { context_menu = context_menu.separator().entry( format!("Move '#{}' here", channel_name), + None, cx.handler_for(&this, move |this, cx| { this.move_channel_on_clipboard(channel_id, cx) }), @@ -1050,14 +1058,17 @@ impl CollabPanel { .separator() .entry( "Invite Members", + None, cx.handler_for(&this, move |this, cx| this.invite_members(channel_id, cx)), ) .entry( "Manage Members", + None, cx.handler_for(&this, move |this, cx| this.manage_members(channel_id, cx)), ) .entry( "Delete", + None, cx.handler_for(&this, move |this, cx| this.remove_channel(channel_id, cx)), ); } diff --git a/crates/collab_ui2/src/collab_panel/channel_modal.rs b/crates/collab_ui2/src/collab_panel/channel_modal.rs index f373dbad1fbc2dbdbe6f022bac806c6cf2f22bf0..d68aa32e9b339159062d36a08cf402c610c7d781 100644 --- a/crates/collab_ui2/src/collab_panel/channel_modal.rs +++ b/crates/collab_ui2/src/collab_panel/channel_modal.rs @@ -532,7 +532,7 @@ impl ChannelModalDelegate { let user_id = user.id; let picker = cx.view().clone(); let context_menu = ContextMenu::build(cx, |mut menu, _cx| { - menu = menu.entry("Remove Member", { + menu = menu.entry("Remove Member", None, { let picker = picker.clone(); move |cx| { picker.update(cx, |picker, cx| { @@ -544,7 +544,7 @@ impl ChannelModalDelegate { let picker = picker.clone(); match role { ChannelRole::Admin => { - menu = menu.entry("Revoke Admin", move |cx| { + menu = menu.entry("Revoke Admin", None, move |cx| { picker.update(cx, |picker, cx| { picker .delegate @@ -553,7 +553,7 @@ impl ChannelModalDelegate { }); } ChannelRole::Member => { - menu = menu.entry("Make Admin", move |cx| { + menu = menu.entry("Make Admin", None, move |cx| { picker.update(cx, |picker, cx| { picker .delegate diff --git a/crates/copilot_button2/src/copilot_button.rs b/crates/copilot_button2/src/copilot_button.rs index 705bdc1bec52f99690287efb8cc351337148a8db..7cd2b09db80d3ef4627cbad23f253bc766c77c4b 100644 --- a/crates/copilot_button2/src/copilot_button.rs +++ b/crates/copilot_button2/src/copilot_button.rs @@ -133,8 +133,11 @@ impl CopilotButton { pub fn build_copilot_start_menu(&mut self, cx: &mut ViewContext) -> View { let fs = self.fs.clone(); ContextMenu::build(cx, |menu, cx| { - menu.entry("Sign In", initiate_sign_in) - .entry("Disable Copilot", move |cx| hide_copilot(fs.clone(), cx)) + menu.entry("Sign In", None, initiate_sign_in).entry( + "Disable Copilot", + None, + move |cx| hide_copilot(fs.clone(), cx), + ) }) } @@ -154,6 +157,7 @@ impl CopilotButton { if language_enabled { "Hide" } else { "Show" }, language.name() ), + None, move |cx| toggle_copilot_for_language(language.clone(), fs.clone(), cx), ); } @@ -169,6 +173,7 @@ impl CopilotButton { "{} Suggestions for This Path", if path_enabled { "Hide" } else { "Show" } ), + None, move |cx| { if let Some(workspace) = cx.window_handle().downcast::() { if let Ok(workspace) = workspace.root_view(cx) { @@ -194,6 +199,7 @@ impl CopilotButton { } else { "Show Suggestions for All Files" }, + None, move |cx| toggle_copilot_globally(fs.clone(), cx), ) .separator() diff --git a/crates/language_tools2/src/lsp_log.rs b/crates/language_tools2/src/lsp_log.rs index 597c9c5b543fb5976c8019981216396b83739d9d..973cd9c355713a30b03b79bc28802991db81f4da 100644 --- a/crates/language_tools2/src/lsp_log.rs +++ b/crates/language_tools2/src/lsp_log.rs @@ -763,6 +763,7 @@ impl Render for LspLogToolbarItemView { )) .entry( SERVER_LOGS, + None, cx.handler_for(&log_view, move |view, cx| { view.show_logs_for_server(row.server_id, cx); }), diff --git a/crates/language_tools2/src/syntax_tree_view.rs b/crates/language_tools2/src/syntax_tree_view.rs index dcdcb612b781e6d93e92650c111f9ea9e1ac9d1f..c9a621f967155097a97fc9017ed6b17ccba1f7ec 100644 --- a/crates/language_tools2/src/syntax_tree_view.rs +++ b/crates/language_tools2/src/syntax_tree_view.rs @@ -459,6 +459,7 @@ impl SyntaxTreeToolbarItemView { layer.language.name(), format_node_range(layer.node()) ), + None, cx.handler_for(&view, move |view, cx| { view.select_layer(layer_ix, cx); }), diff --git a/crates/project_panel2/src/project_panel.rs b/crates/project_panel2/src/project_panel.rs index 07a6e4be5ef0d8d545a4c971beeaf3183a6ad4b7..7f6ae63ee1c4a85590cebe4e22011f29d04aa819 100644 --- a/crates/project_panel2/src/project_panel.rs +++ b/crates/project_panel2/src/project_panel.rs @@ -400,6 +400,7 @@ impl ProjectPanel { if is_root { menu = menu.entry( "Remove from Project", + None, cx.handler_for(&this, move |this, cx| { this.project.update(cx, |project, cx| { project.remove_worktree(worktree_id, cx) diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index 97bb3865ef6dbefd95e4274fe77d37df630aee74..85021698330f0f0c09529cdc6e7d80b49901a5a4 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -76,13 +76,14 @@ impl ContextMenu { pub fn entry( mut self, label: impl Into, + action: Option>, handler: impl Fn(&mut WindowContext) + 'static, ) -> Self { self.items.push(ContextMenuItem::Entry { label: label.into(), handler: Rc::new(handler), icon: None, - action: None, + action, }); self } @@ -282,7 +283,10 @@ impl Render for ContextMenu { ListItem::new(ix) .inset(true) .selected(Some(ix) == self.selected_index) - .on_click(move |_, cx| handler(cx)) + .on_click(cx.listener(move |_, _, cx| { + handler(cx); + cx.emit(DismissEvent); + })) .child( h_stack() .w_full() @@ -303,7 +307,10 @@ impl Render for ContextMenu { ListItem::new(ix) .inset(true) .selected(Some(ix) == self.selected_index) - .on_click(move |_, cx| handler(cx)) + .on_click(cx.listener(move |_, _, cx| { + handler(cx); + cx.emit(DismissEvent); + })) .child(entry_render(cx)) .into_any_element() } diff --git a/crates/ui2/src/components/stories/context_menu.rs b/crates/ui2/src/components/stories/context_menu.rs index cae5939f2aa7f12f148adf75f0255a660f7e6f95..68d5f7bd33e3daf61a18e038a3a3b519e6309069 100644 --- a/crates/ui2/src/components/stories/context_menu.rs +++ b/crates/ui2/src/components/stories/context_menu.rs @@ -1,4 +1,4 @@ -use gpui::{actions, Action, AnchorCorner, Div, Render, View}; +use gpui::{actions, AnchorCorner, Div, Render, View}; use story::Story; use crate::prelude::*; @@ -10,12 +10,9 @@ fn build_menu(cx: &mut WindowContext, header: impl Into) -> View, mut save_intent: SaveIntent, - should_close: impl 'static + Fn(EntityId) -> bool, + should_close: impl Fn(EntityId) -> bool, ) -> Task> { // Find the items to close. let mut items_to_close = Vec::new(); @@ -1571,28 +1571,74 @@ impl Pane { } }; + let pane = cx.view().clone(); right_click_menu(ix).trigger(tab).menu(move |cx| { - ContextMenu::build(cx, |menu, _| { + let pane = pane.clone(); + ContextMenu::build(cx, move |menu, cx| { let menu = menu - .action("Close", CloseActiveItem { save_intent: None }.boxed_clone()) - .action("Close Others", CloseInactiveItems.boxed_clone()) + .entry( + "Close", + Some(Box::new(CloseActiveItem { save_intent: None })), + cx.handler_for(&pane, move |pane, cx| { + pane.close_item_by_id(item_id, SaveIntent::Close, cx) + .detach_and_log_err(cx); + }), + ) + .entry( + "Close Others", + Some(Box::new(CloseInactiveItems)), + cx.handler_for(&pane, move |pane, cx| { + pane.close_items(cx, SaveIntent::Close, |id| id != item_id) + .detach_and_log_err(cx); + }), + ) .separator() - .action("Close Left", CloseItemsToTheLeft.boxed_clone()) - .action("Close Right", CloseItemsToTheRight.boxed_clone()) + .entry( + "Close Left", + Some(Box::new(CloseItemsToTheLeft)), + cx.handler_for(&pane, move |pane, cx| { + pane.close_items_to_the_left_by_id(item_id, cx) + .detach_and_log_err(cx); + }), + ) + .entry( + "Close Right", + Some(Box::new(CloseItemsToTheRight)), + cx.handler_for(&pane, move |pane, cx| { + pane.close_items_to_the_right_by_id(item_id, cx) + .detach_and_log_err(cx); + }), + ) .separator() - .action("Close Clean", CloseCleanItems.boxed_clone()) - .action( + .entry( + "Close Clean", + Some(Box::new(CloseCleanItems)), + cx.handler_for(&pane, move |pane, cx| { + pane.close_clean_items(&CloseCleanItems, cx) + .map(|task| task.detach_and_log_err(cx)); + }), + ) + .entry( "Close All", - CloseAllItems { save_intent: None }.boxed_clone(), + Some(Box::new(CloseAllItems { save_intent: None })), + cx.handler_for(&pane, |pane, cx| { + pane.close_all_items(&CloseAllItems { save_intent: None }, cx) + .map(|task| task.detach_and_log_err(cx)); + }), ); if let Some(entry) = single_entry_to_resolve { - menu.separator().action( + let entry_id = entry.to_proto(); + menu.separator().entry( "Reveal In Project Panel", - RevealInProjectPanel { - entry_id: entry.to_proto(), - } - .boxed_clone(), + Some(Box::new(RevealInProjectPanel { entry_id })), + cx.handler_for(&pane, move |pane, cx| { + pane.project.update(cx, |_, cx| { + cx.emit(project::Event::RevealInProjectPanel( + ProjectEntryId::from_proto(entry_id), + )) + }); + }), ) } else { menu