@@ -381,67 +381,59 @@ impl ProjectPanel {
let is_local = project.is_local();
let is_read_only = project.is_read_only();
- let context_menu = ContextMenu::build(cx, |mut menu, cx| {
- if is_read_only {
- menu = menu.action("Copy Relative Path", Box::new(CopyRelativePath));
- if is_dir {
- menu = menu.action("Search Inside", Box::new(NewSearchInDirectory))
- }
-
- return menu;
- }
-
- if is_local {
- menu = menu.action(
- "Add Folder to Project",
- Box::new(workspace::AddFolderToProject),
- );
- 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)
- });
- }),
- );
- }
- }
-
- menu = menu
- .action("New File", Box::new(NewFile))
- .action("New Folder", Box::new(NewDirectory))
- .separator()
- .action("Cut", Box::new(Cut))
- .action("Copy", Box::new(Copy));
-
- if let Some(clipboard_entry) = self.clipboard_entry {
- if clipboard_entry.worktree_id() == worktree_id {
- menu = menu.action("Paste", Box::new(Paste));
- }
- }
-
- menu = menu
- .separator()
- .action("Copy Path", Box::new(CopyPath))
- .action("Copy Relative Path", Box::new(CopyRelativePath))
- .separator()
- .action("Reveal in Finder", Box::new(RevealInFinder));
-
- if is_dir {
- menu = menu
- .action("Open in Terminal", Box::new(OpenInTerminal))
- .action("Search Inside", Box::new(NewSearchInDirectory))
- }
-
- menu = menu.separator().action("Rename", Box::new(Rename));
-
- if !is_root {
- menu = menu.action("Delete", Box::new(Delete));
- }
-
- menu
+ let context_menu = ContextMenu::build(cx, |menu, cx| {
+ menu.context(self.focus_handle.clone()).then_if_else(
+ is_read_only,
+ |menu| {
+ menu.action("Copy Relative Path", Box::new(CopyRelativePath))
+ .then_if(is_dir, |menu| {
+ menu.action("Search Inside", Box::new(NewSearchInDirectory))
+ })
+ },
+ |menu| {
+ menu.then_if(is_local, |menu| {
+ menu.action(
+ "Add Folder to Project",
+ Box::new(workspace::AddFolderToProject),
+ )
+ .then_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)
+ });
+ }),
+ )
+ })
+ })
+ .action("New File", Box::new(NewFile))
+ .action("New Folder", Box::new(NewDirectory))
+ .separator()
+ .action("Cut", Box::new(Cut))
+ .action("Copy", Box::new(Copy))
+ .if_some(self.clipboard_entry, |menu, entry| {
+ menu.then_if(entry.worktree_id() == worktree_id, |menu| {
+ menu.action("Paste", Box::new(Paste))
+ })
+ })
+ .separator()
+ .action("Copy Path", Box::new(CopyPath))
+ .action("Copy Relative Path", Box::new(CopyRelativePath))
+ .separator()
+ .action("Reveal in Finder", Box::new(RevealInFinder))
+ .then_if(is_dir, |menu| {
+ menu
+ .action("Open in Terminal", Box::new(OpenInTerminal))
+ .action("Search Inside", Box::new(NewSearchInDirectory))
+ })
+ .separator().action("Rename", Box::new(Rename))
+ .then_if(!is_root, |menu| {
+ menu.action("Delete", Box::new(Delete))
+ })
+ },
+ )
});
cx.focus_view(&context_menu);
@@ -27,6 +27,7 @@ enum ContextMenuItem {
pub struct ContextMenu {
items: Vec<ContextMenuItem>,
focus_handle: FocusHandle,
+ action_context: Option<FocusHandle>,
selected_index: Option<usize>,
delayed: bool,
clicked: bool,
@@ -56,6 +57,7 @@ impl ContextMenu {
Self {
items: Default::default(),
focus_handle,
+ action_context: None,
selected_index: None,
delayed: false,
clicked: false,
@@ -66,6 +68,39 @@ impl ContextMenu {
})
}
+ pub fn if_some<T>(self, condition: Option<T>, f: impl FnOnce(Self, T) -> Self) -> Self {
+ if let Some(t) = condition {
+ f(self, t)
+ } else {
+ self
+ }
+ }
+
+ pub fn then_if_else(self, condition: bool, then: impl FnOnce(Self) -> Self, otherwise: impl FnOnce(Self) -> Self) -> Self {
+ if condition {
+ then(self)
+ } else {
+ otherwise(self)
+ }
+ }
+
+ pub fn then_if(self, condition: bool, f: impl FnOnce(Self) -> Self) -> Self {
+ if condition {
+ f(self)
+ } else {
+ self
+ }
+ }
+
+ pub fn map(self, f: impl FnOnce(Self) -> Self) -> Self {
+ f(self)
+ }
+
+ pub fn context(mut self, focus: FocusHandle) -> Self {
+ self.action_context = Some(focus);
+ self
+ }
+
pub fn header(mut self, title: impl Into<SharedString>) -> Self {
self.items.push(ContextMenuItem::Header(title.into()));
self
@@ -305,7 +340,14 @@ impl Render for ContextMenu {
.child(label_element)
.debug_selector(|| format!("MENU_ITEM-{}", label))
.children(action.as_ref().and_then(|action| {
- KeyBinding::for_action(&**action, cx)
+ self.action_context
+ .as_ref()
+ .map(|focus| {
+ KeyBinding::for_action_in(&**action, focus, cx)
+ })
+ .unwrap_or_else(|| {
+ KeyBinding::for_action(&**action, cx)
+ })
.map(|binding| div().ml_1().child(binding))
})),
)