Appropriately pick venv activation script (#33205)

Ragul R and Piotr Osiewicz created

when `terminal.detect_venv.activate_script` setting is default, pick the
appropriate activate script as per the `terminal.shell` settings
specified by the user. Previously when the activate_script setting is
default, zed always try to use the `activate` script, which only works
when the user shell is `bash or zsh`. But what if the user is using
`fish` shell in zed?

Release Notes:

- python: value of `activate_script` setting is now automatically
inferred based on the kind of shell the user is running with.

---------

Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>

Change summary

crates/project/src/terminals.rs          | 43 +++++++++++++++++++++++--
crates/terminal/src/terminal_settings.rs |  2 
2 files changed, 40 insertions(+), 5 deletions(-)

Detailed changes

crates/project/src/terminals.rs 🔗

@@ -16,7 +16,7 @@ use std::{
 use task::{DEFAULT_REMOTE_SHELL, Shell, ShellBuilder, SpawnInTerminal};
 use terminal::{
     TaskState, TaskStatus, Terminal, TerminalBuilder,
-    terminal_settings::{self, TerminalSettings, VenvSettings},
+    terminal_settings::{self, ActivateScript, TerminalSettings, VenvSettings},
 };
 use util::{
     ResultExt,
@@ -256,8 +256,11 @@ impl Project {
         let (spawn_task, shell) = match kind {
             TerminalKind::Shell(_) => {
                 if let Some(python_venv_directory) = &python_venv_directory {
-                    python_venv_activate_command =
-                        this.python_activate_command(python_venv_directory, &settings.detect_venv);
+                    python_venv_activate_command = this.python_activate_command(
+                        python_venv_directory,
+                        &settings.detect_venv,
+                        &settings.shell,
+                    );
                 }
 
                 match ssh_details {
@@ -510,10 +513,27 @@ impl Project {
             })
     }
 
+    fn activate_script_kind(shell: Option<&str>) -> ActivateScript {
+        let shell_env = std::env::var("SHELL").ok();
+        let shell_path = shell.or_else(|| shell_env.as_deref());
+        let shell = std::path::Path::new(shell_path.unwrap_or(""))
+            .file_name()
+            .and_then(|name| name.to_str())
+            .unwrap_or("");
+        match shell {
+            "fish" => ActivateScript::Fish,
+            "tcsh" => ActivateScript::Csh,
+            "nu" => ActivateScript::Nushell,
+            "powershell" | "pwsh" => ActivateScript::PowerShell,
+            _ => ActivateScript::Default,
+        }
+    }
+
     fn python_activate_command(
         &self,
         venv_base_directory: &Path,
         venv_settings: &VenvSettings,
+        shell: &Shell,
     ) -> Option<String> {
         let venv_settings = venv_settings.as_option()?;
         let activate_keyword = match venv_settings.activate_script {
@@ -526,7 +546,22 @@ impl Project {
             terminal_settings::ActivateScript::Pyenv => "pyenv",
             _ => "source",
         };
-        let activate_script_name = match venv_settings.activate_script {
+        let script_kind =
+            if venv_settings.activate_script == terminal_settings::ActivateScript::Default {
+                match shell {
+                    Shell::Program(program) => Self::activate_script_kind(Some(program)),
+                    Shell::WithArguments {
+                        program,
+                        args: _,
+                        title_override: _,
+                    } => Self::activate_script_kind(Some(program)),
+                    Shell::System => Self::activate_script_kind(None),
+                }
+            } else {
+                venv_settings.activate_script
+            };
+
+        let activate_script_name = match script_kind {
             terminal_settings::ActivateScript::Default
             | terminal_settings::ActivateScript::Pyenv => "activate",
             terminal_settings::ActivateScript::Csh => "activate.csh",

crates/terminal/src/terminal_settings.rs 🔗

@@ -123,7 +123,7 @@ impl VenvSettings {
     }
 }
 
-#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
 #[serde(rename_all = "snake_case")]
 pub enum ActivateScript {
     #[default]