Merge pull request #2161 from zed-industries/community/3-reveal-in-finder

Petros Amoiridis created

Introduce Reveal in Finder

Change summary

crates/gpui/src/platform.rs               |  1 
crates/gpui/src/platform/mac/platform.rs  | 13 +++++++++
crates/gpui/src/platform/test.rs          |  2 +
crates/project_panel/src/project_panel.rs | 10 +++++++
crates/terminal/src/terminal.rs           | 34 ++----------------------
crates/workspace/src/notifications.rs     | 11 +------
6 files changed, 31 insertions(+), 40 deletions(-)

Detailed changes

crates/gpui/src/platform.rs 🔗

@@ -65,6 +65,7 @@ pub trait Platform: Send + Sync {
     fn write_to_clipboard(&self, item: ClipboardItem);
     fn read_from_clipboard(&self) -> Option<ClipboardItem>;
     fn open_url(&self, url: &str);
+    fn reveal_path(&self, path: &Path);
 
     fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Result<()>;
     fn read_credentials(&self, url: &str) -> Result<Option<(String, Vec<u8>)>>;

crates/gpui/src/platform/mac/platform.rs 🔗

@@ -599,6 +599,19 @@ impl platform::Platform for MacPlatform {
         }
     }
 
+    fn reveal_path(&self, path: &Path) {
+        unsafe {
+            let full_path = ns_string(path.to_str().unwrap_or(""));
+            let root_full_path = ns_string("");
+            let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace];
+            msg_send![
+                workspace,
+                selectFile: full_path
+                inFileViewerRootedAtPath: root_full_path
+            ]
+        }
+    }
+
     fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Result<()> {
         let url = CFString::from(url);
         let username = CFString::from(username);

crates/gpui/src/platform/test.rs 🔗

@@ -173,6 +173,8 @@ impl super::Platform for Platform {
 
     fn open_url(&self, _: &str) {}
 
+    fn reveal_path(&self, _: &Path) {}
+
     fn write_credentials(&self, _: &str, _: &str, _: &[u8]) -> Result<()> {
         Ok(())
     }

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,13 @@ impl ProjectPanel {
         }
     }
 
+    fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
+        if let Some((worktree, entry)) = self.selected_entry(cx) {
+            cx.platform()
+                .reveal_path(&worktree.abs_path().join(&entry.path));
+        }
+    }
+
     fn move_entry(
         &mut self,
         &MoveProjectEntry {

crates/terminal/src/terminal.rs 🔗

@@ -32,17 +32,14 @@ use mappings::mouse::{
 
 use procinfo::LocalProcessInfo;
 use settings::{AlternateScroll, Settings, Shell, TerminalBlink};
-use util::ResultExt;
 
 use std::{
     cmp::min,
     collections::{HashMap, VecDeque},
     fmt::Display,
-    io,
     ops::{Deref, Index, RangeInclusive, Sub},
-    os::unix::{prelude::AsRawFd, process::CommandExt},
+    os::unix::prelude::AsRawFd,
     path::PathBuf,
-    process::Command,
     sync::Arc,
     time::{Duration, Instant},
 };
@@ -736,7 +733,7 @@ impl Terminal {
 
                 if let Some((url, url_match)) = found_url {
                     if *open {
-                        open_uri(&url).log_err();
+                        cx.platform().open_url(url.as_str());
                     } else {
                         self.update_hyperlink(prev_hyperlink, url, url_match);
                     }
@@ -1077,7 +1074,7 @@ impl Terminal {
             if self.selection_phase == SelectionPhase::Ended {
                 let mouse_cell_index = content_index_for_mouse(position, &self.last_content);
                 if let Some(link) = self.last_content.cells[mouse_cell_index].hyperlink() {
-                    open_uri(link.uri()).log_err();
+                    cx.platform().open_url(link.uri());
                 } else {
                     self.events
                         .push_back(InternalEvent::FindHyperlink(position, true));
@@ -1236,31 +1233,6 @@ fn content_index_for_mouse<'a>(pos: Vector2F, content: &'a TerminalContent) -> u
     line * content.size.columns() + col
 }
 
-fn open_uri(uri: &str) -> Result<(), std::io::Error> {
-    let mut command = Command::new("open");
-    command.arg(uri);
-
-    unsafe {
-        command
-            .pre_exec(|| {
-                match libc::fork() {
-                    -1 => return Err(io::Error::last_os_error()),
-                    0 => (),
-                    _ => libc::_exit(0),
-                }
-
-                if libc::setsid() == -1 {
-                    return Err(io::Error::last_os_error());
-                }
-
-                Ok(())
-            })
-            .spawn()?
-            .wait()
-            .map(|_| ())
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use alacritty_terminal::{

crates/workspace/src/notifications.rs 🔗

@@ -121,7 +121,6 @@ impl Workspace {
 }
 
 pub mod simple_message_notification {
-    use std::process::Command;
 
     use gpui::{
         actions,
@@ -147,14 +146,8 @@ pub mod simple_message_notification {
     pub fn init(cx: &mut MutableAppContext) {
         cx.add_action(MessageNotification::dismiss);
         cx.add_action(
-            |_workspace: &mut Workspace, open_action: &OsOpen, _cx: &mut ViewContext<Workspace>| {
-                #[cfg(target_os = "macos")]
-                {
-                    let mut command = Command::new("open");
-                    command.arg(open_action.0.clone());
-
-                    command.spawn().ok();
-                }
+            |_workspace: &mut Workspace, open_action: &OsOpen, cx: &mut ViewContext<Workspace>| {
+                cx.platform().open_url(open_action.0.as_str());
             },
         )
     }