Introduce reveal_in_finder function

Petros Amoiridis and Mikayla Maki created

And use this function in a new Reveal in Finder option of the project panel context menu.

Co-Authored-By: Mikayla Maki <mikayla.c.maki@gmail.com>

Change summary

crates/project_panel/src/project_panel.rs |  9 +++++++++
crates/util/src/lib.rs                    | 10 ++++++++++
2 files changed, 19 insertions(+)

Detailed changes

crates/project_panel/src/project_panel.rs 🔗

@@ -119,6 +119,7 @@ actions!(
         AddFile,
         Copy,
         CopyPath,
+        RevealInFinder,
         Cut,
         Paste,
         Delete,
@@ -147,6 +148,7 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(ProjectPanel::cancel);
     cx.add_action(ProjectPanel::copy);
     cx.add_action(ProjectPanel::copy_path);
+    cx.add_action(ProjectPanel::reveal_in_finder);
     cx.add_action(ProjectPanel::cut);
     cx.add_action(
         |this: &mut ProjectPanel, action: &Paste, cx: &mut ViewContext<ProjectPanel>| {
@@ -305,6 +307,7 @@ impl ProjectPanel {
             }
             menu_entries.push(ContextMenuItem::item("New File", AddFile));
             menu_entries.push(ContextMenuItem::item("New Folder", AddDirectory));
+            menu_entries.push(ContextMenuItem::item("Reveal in Finder", RevealInFinder));
             menu_entries.push(ContextMenuItem::Separator);
             menu_entries.push(ContextMenuItem::item("Copy", Copy));
             menu_entries.push(ContextMenuItem::item("Copy Path", CopyPath));
@@ -787,6 +790,12 @@ impl ProjectPanel {
         }
     }
 
+    fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
+        if let Some((_worktree, entry)) = self.selected_entry(cx) {
+            util::reveal_in_finder(&entry.path);
+        }
+    }
+
     fn move_entry(
         &mut self,
         &MoveProjectEntry {

crates/util/src/lib.rs 🔗

@@ -9,6 +9,7 @@ use rand::{seq::SliceRandom, Rng};
 use std::{
     cmp::Ordering,
     ops::AddAssign,
+    path::Path,
     pin::Pin,
     task::{Context, Poll},
 };
@@ -53,6 +54,15 @@ pub fn truncate_and_trailoff(s: &str, max_chars: usize) -> String {
     }
 }
 
+pub fn reveal_in_finder<P: AsRef<Path>>(path: P) {
+    let path_to_reveal = path.as_ref().to_string_lossy();
+    std::process::Command::new("open")
+        .arg("-R") // To reveal in Finder instead of opening the file
+        .arg(path_to_reveal.as_ref())
+        .spawn()
+        .log_err();
+}
+
 pub fn post_inc<T: From<u8> + AddAssign<T> + Copy>(value: &mut T) -> T {
     let prev = *value;
     *value += T::from(1);