Detailed changes
@@ -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)),
);
}
@@ -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
@@ -133,8 +133,11 @@ impl CopilotButton {
pub fn build_copilot_start_menu(&mut self, cx: &mut ViewContext<Self>) -> View<ContextMenu> {
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::<Workspace>() {
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()
@@ -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);
}),
@@ -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);
}),
@@ -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)
@@ -76,13 +76,14 @@ impl ContextMenu {
pub fn entry(
mut self,
label: impl Into<SharedString>,
+ action: Option<Box<dyn Action>>,
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()
}
@@ -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<SharedString>) -> View<C
ContextMenu::build(cx, |menu, _| {
menu.header(header)
.separator()
- .entry("Print current time", |cx| {
- println!("dispatching PrintCurrentTime action");
- cx.dispatch_action(PrintCurrentDate.boxed_clone())
- })
- .entry("Print best foot", |cx| {
- cx.dispatch_action(PrintBestFood.boxed_clone())
+ .action("Print current time", Box::new(PrintCurrentDate))
+ .entry("Print best food", Some(Box::new(PrintBestFood)), |cx| {
+ cx.dispatch_action(Box::new(PrintBestFood))
})
})
}
@@ -625,7 +625,7 @@ impl Render for PanelButtons {
&& panel.position_is_valid(position, cx)
{
let panel = panel.clone();
- menu = menu.entry(position.to_label(), move |cx| {
+ menu = menu.entry(position.to_label(), None, move |cx| {
panel.set_position(position, cx);
})
}
@@ -990,7 +990,7 @@ impl Pane {
&mut self,
cx: &mut ViewContext<Pane>,
mut save_intent: SaveIntent,
- should_close: impl 'static + Fn(EntityId) -> bool,
+ should_close: impl Fn(EntityId) -> bool,
) -> Task<Result<()>> {
// 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