diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 617870fcb4..65415c6690 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -122,6 +122,7 @@ actions!( CopyPath, CopyRelativePath, RevealInFinder, + OpenInTerminal, Cut, Paste, Delete, @@ -156,6 +157,7 @@ pub fn init(assets: impl AssetSource, cx: &mut AppContext) { cx.add_action(ProjectPanel::copy_path); cx.add_action(ProjectPanel::copy_relative_path); cx.add_action(ProjectPanel::reveal_in_finder); + cx.add_action(ProjectPanel::open_in_terminal); cx.add_action(ProjectPanel::new_search_in_directory); cx.add_action( |this: &mut ProjectPanel, action: &Paste, cx: &mut ViewContext| { @@ -423,24 +425,30 @@ impl ProjectPanel { menu_entries.push(ContextMenuItem::Separator); menu_entries.push(ContextMenuItem::action("Cut", Cut)); menu_entries.push(ContextMenuItem::action("Copy", Copy)); + if let Some(clipboard_entry) = self.clipboard_entry { + if clipboard_entry.worktree_id() == worktree.id() { + menu_entries.push(ContextMenuItem::action("Paste", Paste)); + } + } menu_entries.push(ContextMenuItem::Separator); menu_entries.push(ContextMenuItem::action("Copy Path", CopyPath)); menu_entries.push(ContextMenuItem::action( "Copy Relative Path", CopyRelativePath, )); + + if entry.is_dir() { + menu_entries.push(ContextMenuItem::Separator); + } menu_entries.push(ContextMenuItem::action("Reveal in Finder", RevealInFinder)); if entry.is_dir() { + menu_entries.push(ContextMenuItem::action("Open in Terminal", OpenInTerminal)); menu_entries.push(ContextMenuItem::action( "Search Inside", NewSearchInDirectory, )); } - if let Some(clipboard_entry) = self.clipboard_entry { - if clipboard_entry.worktree_id() == worktree.id() { - menu_entries.push(ContextMenuItem::action("Paste", Paste)); - } - } + menu_entries.push(ContextMenuItem::Separator); menu_entries.push(ContextMenuItem::action("Rename", Rename)); if !is_root { @@ -965,6 +973,26 @@ impl ProjectPanel { } } + fn open_in_terminal(&mut self, _: &OpenInTerminal, cx: &mut ViewContext) { + if let Some((worktree, entry)) = self.selected_entry(cx) { + let window = cx.window(); + let view_id = cx.view_id(); + let path = worktree.abs_path().join(&entry.path); + + cx.app_context() + .spawn(|mut cx| async move { + window.dispatch_action( + view_id, + &workspace::OpenTerminal { + working_directory: path, + }, + &mut cx, + ); + }) + .detach(); + } + } + pub fn new_search_in_directory( &mut self, _: &NewSearchInDirectory, diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index 39d2f14f08..0bfa84e754 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{path::PathBuf, sync::Arc}; use crate::TerminalView; use db::kvp::KEY_VALUE_STORE; @@ -23,6 +23,7 @@ actions!(terminal_panel, [ToggleFocus]); pub fn init(cx: &mut AppContext) { cx.add_action(TerminalPanel::new_terminal); + cx.add_action(TerminalPanel::open_terminal); } #[derive(Debug)] @@ -79,7 +80,7 @@ impl TerminalPanel { cx.window_context().defer(move |cx| { if let Some(this) = this.upgrade(cx) { this.update(cx, |this, cx| { - this.add_terminal(cx); + this.add_terminal(None, cx); }); } }) @@ -230,6 +231,21 @@ impl TerminalPanel { } } + pub fn open_terminal( + workspace: &mut Workspace, + action: &workspace::OpenTerminal, + cx: &mut ViewContext, + ) { + let Some(this) = workspace.focus_panel::(cx) else { + return; + }; + + this.update(cx, |this, cx| { + this.add_terminal(Some(action.working_directory.clone()), cx) + }) + } + + ///Create a new Terminal in the current working directory or the user's home directory fn new_terminal( workspace: &mut Workspace, _: &workspace::NewTerminal, @@ -239,19 +255,23 @@ impl TerminalPanel { return; }; - this.update(cx, |this, cx| this.add_terminal(cx)) + this.update(cx, |this, cx| this.add_terminal(None, cx)) } - fn add_terminal(&mut self, cx: &mut ViewContext) { + fn add_terminal(&mut self, working_directory: Option, cx: &mut ViewContext) { let workspace = self.workspace.clone(); cx.spawn(|this, mut cx| async move { let pane = this.read_with(&cx, |this, _| this.pane.clone())?; workspace.update(&mut cx, |workspace, cx| { - let working_directory_strategy = settings::get::(cx) - .working_directory - .clone(); - let working_directory = - crate::get_working_directory(workspace, cx, working_directory_strategy); + let working_directory = if let Some(working_directory) = working_directory { + Some(working_directory) + } else { + let working_directory_strategy = settings::get::(cx) + .working_directory + .clone(); + crate::get_working_directory(workspace, cx, working_directory_strategy) + }; + let window = cx.window(); if let Some(terminal) = workspace.project().update(cx, |project, cx| { project @@ -389,7 +409,7 @@ impl Panel for TerminalPanel { fn set_active(&mut self, active: bool, cx: &mut ViewContext) { if active && self.pane.read(cx).items_len() == 0 { - self.add_terminal(cx) + self.add_terminal(None, cx) } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 7d0f6db917..999d968575 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -203,7 +203,15 @@ impl Clone for Toast { } } -impl_actions!(workspace, [ActivatePane, ActivatePaneInDirection, Toast]); +#[derive(Clone, Deserialize, PartialEq)] +pub struct OpenTerminal { + pub working_directory: PathBuf, +} + +impl_actions!( + workspace, + [ActivatePane, ActivatePaneInDirection, Toast, OpenTerminal] +); pub type WorkspaceId = i64;