From a789476c95173dfc6a2d4f741fe338ec70b59015 Mon Sep 17 00:00:00 2001 From: Petros Amoiridis Date: Fri, 10 Feb 2023 21:11:05 +0200 Subject: [PATCH 1/5] Introduce reveal_in_finder function And use this function in a new Reveal in Finder option of the project panel context menu. Co-Authored-By: Mikayla Maki --- crates/project_panel/src/project_panel.rs | 9 +++++++++ crates/util/src/lib.rs | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index e59353aae4..a5ca4077f7 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/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| { @@ -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) { + if let Some((_worktree, entry)) = self.selected_entry(cx) { + util::reveal_in_finder(&entry.path); + } + } + fn move_entry( &mut self, &MoveProjectEntry { diff --git a/crates/util/src/lib.rs b/crates/util/src/lib.rs index ea8fdee2a8..698d888e15 100644 --- a/crates/util/src/lib.rs +++ b/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>(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 + AddAssign + Copy>(value: &mut T) -> T { let prev = *value; *value += T::from(1); From 5d23aaacc89fec002ac8b1a0be109bbc2c47385f Mon Sep 17 00:00:00 2001 From: Petros Amoiridis Date: Fri, 10 Feb 2023 21:11:54 +0200 Subject: [PATCH 2/5] Introduce an open function And refactor some of the older code to simplify it Co-Authored-By: Mikayla Maki --- crates/terminal/src/terminal.rs | 34 +++------------------------ crates/util/src/lib.rs | 8 +++++++ crates/workspace/src/notifications.rs | 6 +---- 3 files changed, 12 insertions(+), 36 deletions(-) diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index dd5c5fb3b0..a4f913ec77 100644 --- a/crates/terminal/src/terminal.rs +++ b/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}, }; @@ -734,7 +731,7 @@ impl Terminal { if let Some((url, url_match)) = found_url { if *open { - open_uri(&url).log_err(); + util::open(&url); } else { self.update_hyperlink(prev_hyperlink, url, url_match); } @@ -1075,7 +1072,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(); + util::open(link.uri()); } else { self.events .push_back(InternalEvent::FindHyperlink(position, true)); @@ -1234,31 +1231,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::{ diff --git a/crates/util/src/lib.rs b/crates/util/src/lib.rs index 698d888e15..5b12502389 100644 --- a/crates/util/src/lib.rs +++ b/crates/util/src/lib.rs @@ -54,6 +54,14 @@ pub fn truncate_and_trailoff(s: &str, max_chars: usize) -> String { } } +pub fn open>(path: P) { + let path_to_open = path.as_ref().to_string_lossy(); + std::process::Command::new("open") + .arg(path_to_open.as_ref()) + .spawn() + .log_err(); +} + pub fn reveal_in_finder>(path: P) { let path_to_reveal = path.as_ref().to_string_lossy(); std::process::Command::new("open") diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index 72dec114d9..76ee5b1c40 100644 --- a/crates/workspace/src/notifications.rs +++ b/crates/workspace/src/notifications.rs @@ -121,7 +121,6 @@ impl Workspace { } pub mod simple_message_notification { - use std::process::Command; use gpui::{ actions, @@ -150,10 +149,7 @@ pub mod simple_message_notification { |_workspace: &mut Workspace, open_action: &OsOpen, _cx: &mut ViewContext| { #[cfg(target_os = "macos")] { - let mut command = Command::new("open"); - command.arg(open_action.0.clone()); - - command.spawn().ok(); + util::open(&open_action.0); } }, ) From 91437906022975fd6bfd072ee9811168d2e7cacf Mon Sep 17 00:00:00 2001 From: Petros Amoiridis Date: Sat, 11 Feb 2023 11:12:46 +0200 Subject: [PATCH 3/5] Include code only on macOS Co-Authored-By: Mikayla Maki --- crates/util/src/lib.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/crates/util/src/lib.rs b/crates/util/src/lib.rs index 5b12502389..c3376f2e78 100644 --- a/crates/util/src/lib.rs +++ b/crates/util/src/lib.rs @@ -56,19 +56,25 @@ pub fn truncate_and_trailoff(s: &str, max_chars: usize) -> String { pub fn open>(path: P) { let path_to_open = path.as_ref().to_string_lossy(); - std::process::Command::new("open") - .arg(path_to_open.as_ref()) - .spawn() - .log_err(); + #[cfg(target_os = "macos")] + { + std::process::Command::new("open") + .arg(path_to_open.as_ref()) + .spawn() + .log_err(); + } } pub fn reveal_in_finder>(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(); + #[cfg(target_os = "macos")] + { + 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 + AddAssign + Copy>(value: &mut T) -> T { From 015b8db1c307fcfe735fa77455ce5affaac1645f Mon Sep 17 00:00:00 2001 From: Petros Amoiridis Date: Tue, 14 Feb 2023 15:14:15 +0200 Subject: [PATCH 4/5] Introduce reveal_path in Platform And implement it for MacPlatform, and instead of using an external process to run `open`, use the NSWorkspace selectFile instance method. --- 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 | 5 +++-- crates/util/src/lib.rs | 12 ------------ 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 57e8f89539..4753450110 100644 --- a/crates/gpui/src/platform.rs +++ b/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; 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)>>; diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 5d13227585..ec15af3bd8 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/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); diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index aa73aebc90..d0cabd8bc1 100644 --- a/crates/gpui/src/platform/test.rs +++ b/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(()) } diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index a5ca4077f7..f2330dfd4f 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -791,8 +791,9 @@ impl ProjectPanel { } fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext) { - if let Some((_worktree, entry)) = self.selected_entry(cx) { - util::reveal_in_finder(&entry.path); + if let Some((worktree, entry)) = self.selected_entry(cx) { + cx.platform() + .reveal_path(&worktree.abs_path().join(&entry.path)); } } diff --git a/crates/util/src/lib.rs b/crates/util/src/lib.rs index c3376f2e78..65af53f8c5 100644 --- a/crates/util/src/lib.rs +++ b/crates/util/src/lib.rs @@ -65,18 +65,6 @@ pub fn open>(path: P) { } } -pub fn reveal_in_finder>(path: P) { - let path_to_reveal = path.as_ref().to_string_lossy(); - #[cfg(target_os = "macos")] - { - 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 + AddAssign + Copy>(value: &mut T) -> T { let prev = *value; *value += T::from(1); From 7a667f390bbc9a1fb15b255eebf0e4764f4f749c Mon Sep 17 00:00:00 2001 From: Petros Amoiridis Date: Wed, 15 Feb 2023 15:58:57 +0200 Subject: [PATCH 5/5] Use open_url from the platform module And remove the open function from the `util` crate. --- crates/terminal/src/terminal.rs | 4 ++-- crates/util/src/lib.rs | 12 ------------ crates/workspace/src/notifications.rs | 7 ++----- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index a4f913ec77..e92d437297 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -731,7 +731,7 @@ impl Terminal { if let Some((url, url_match)) = found_url { if *open { - util::open(&url); + cx.platform().open_url(url.as_str()); } else { self.update_hyperlink(prev_hyperlink, url, url_match); } @@ -1072,7 +1072,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() { - util::open(link.uri()); + cx.platform().open_url(link.uri()); } else { self.events .push_back(InternalEvent::FindHyperlink(position, true)); diff --git a/crates/util/src/lib.rs b/crates/util/src/lib.rs index 65af53f8c5..ea8fdee2a8 100644 --- a/crates/util/src/lib.rs +++ b/crates/util/src/lib.rs @@ -9,7 +9,6 @@ use rand::{seq::SliceRandom, Rng}; use std::{ cmp::Ordering, ops::AddAssign, - path::Path, pin::Pin, task::{Context, Poll}, }; @@ -54,17 +53,6 @@ pub fn truncate_and_trailoff(s: &str, max_chars: usize) -> String { } } -pub fn open>(path: P) { - let path_to_open = path.as_ref().to_string_lossy(); - #[cfg(target_os = "macos")] - { - std::process::Command::new("open") - .arg(path_to_open.as_ref()) - .spawn() - .log_err(); - } -} - pub fn post_inc + AddAssign + Copy>(value: &mut T) -> T { let prev = *value; *value += T::from(1); diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index 76ee5b1c40..141a345382 100644 --- a/crates/workspace/src/notifications.rs +++ b/crates/workspace/src/notifications.rs @@ -146,11 +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| { - #[cfg(target_os = "macos")] - { - util::open(&open_action.0); - } + |_workspace: &mut Workspace, open_action: &OsOpen, cx: &mut ViewContext| { + cx.platform().open_url(open_action.0.as_str()); }, ) }