Allow for venv activation script to use `pyenv` (#33119)

Taylor Beever created

Release Notes:

- Allows for configuration and use of `pyenv` as a virtual environment provider

Change summary

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

Detailed changes

crates/project/src/terminals.rs 🔗

@@ -523,36 +523,47 @@ impl Project {
             },
             terminal_settings::ActivateScript::Nushell => "overlay use",
             terminal_settings::ActivateScript::PowerShell => ".",
+            terminal_settings::ActivateScript::Pyenv => "pyenv",
             _ => "source",
         };
         let activate_script_name = match venv_settings.activate_script {
-            terminal_settings::ActivateScript::Default => "activate",
+            terminal_settings::ActivateScript::Default
+            | terminal_settings::ActivateScript::Pyenv => "activate",
             terminal_settings::ActivateScript::Csh => "activate.csh",
             terminal_settings::ActivateScript::Fish => "activate.fish",
             terminal_settings::ActivateScript::Nushell => "activate.nu",
             terminal_settings::ActivateScript::PowerShell => "activate.ps1",
         };
-        let path = venv_base_directory
-            .join(match std::env::consts::OS {
-                "windows" => "Scripts",
-                _ => "bin",
-            })
-            .join(activate_script_name)
-            .to_string_lossy()
-            .to_string();
-        let quoted = shlex::try_quote(&path).ok()?;
+
         let line_ending = match std::env::consts::OS {
             "windows" => "\r",
             _ => "\n",
         };
-        smol::block_on(self.fs.metadata(path.as_ref()))
-            .ok()
-            .flatten()?;
 
-        Some(format!(
-            "{} {} ; clear{}",
-            activate_keyword, quoted, line_ending
-        ))
+        if venv_settings.venv_name.is_empty() {
+            let path = venv_base_directory
+                .join(match std::env::consts::OS {
+                    "windows" => "Scripts",
+                    _ => "bin",
+                })
+                .join(activate_script_name)
+                .to_string_lossy()
+                .to_string();
+            let quoted = shlex::try_quote(&path).ok()?;
+            smol::block_on(self.fs.metadata(path.as_ref()))
+                .ok()
+                .flatten()?;
+
+            Some(format!(
+                "{} {} ; clear{}",
+                activate_keyword, quoted, line_ending
+            ))
+        } else {
+            Some(format!(
+                "{activate_keyword} {activate_script_name} {name}; clear{line_ending}",
+                name = venv_settings.venv_name
+            ))
+        }
     }
 
     fn activate_python_virtual_environment(

crates/terminal/src/terminal_settings.rs 🔗

@@ -95,12 +95,14 @@ pub enum VenvSettings {
         /// to the current working directory. We recommend overriding this
         /// in your project's settings, rather than globally.
         activate_script: Option<ActivateScript>,
+        venv_name: Option<String>,
         directories: Option<Vec<PathBuf>>,
     },
 }
 
 pub struct VenvSettingsContent<'a> {
     pub activate_script: ActivateScript,
+    pub venv_name: &'a str,
     pub directories: &'a [PathBuf],
 }
 
@@ -110,9 +112,11 @@ impl VenvSettings {
             VenvSettings::Off => None,
             VenvSettings::On {
                 activate_script,
+                venv_name,
                 directories,
             } => Some(VenvSettingsContent {
                 activate_script: activate_script.unwrap_or(ActivateScript::Default),
+                venv_name: venv_name.as_deref().unwrap_or(""),
                 directories: directories.as_deref().unwrap_or(&[]),
             }),
         }
@@ -128,6 +132,7 @@ pub enum ActivateScript {
     Fish,
     Nushell,
     PowerShell,
+    Pyenv,
 }
 
 #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]