terminal: Allow configuring conda manager (#40577)

Closes #40576
This PR makes Conda activation configurable and transparent by adding a
`terminal.detect_venv.on.conda_manager` setting (`"auto" | "conda" |
"mamba" | "micromamba"`, default `"auto"`), updating Python environment
activation to honor this preference (or the detected manager executable)
and fall back to `conda` when necessary.

The preference is passed via `ZED_CONDA_MANAGER` from the terminal
settings, and the activation command is built accordingly (with proper
quoting for paths). Changes span
`zed/crates/terminal/src/terminal_settings.rs` (new `CondaManager` and
setting), `zed/crates/project/src/terminals.rs` (inject env var),
`zed/crates/languages/src/python.rs` (activation logic), and
`zed/assets/settings/default.json` (document the setting). Default
behavior remains unchanged for most users while enabling explicit
selection of `mamba` or `micromamba`.

Release Notes:
- Added: terminal.detect_venv.on.conda_manager setting to choose the
Conda manager (auto, conda, mamba, micromamba). Default: auto.
- Changed: Python Conda environment activation now respects the
configured manager, otherwise uses the detected environment manager
executable, and falls back to conda.
- Reliability: Activation commands quote manager paths to handle spaces
across platforms.
- Compatibility: No breaking changes; non-Conda environments are
unaffected; remote terminals are supported.

---------

Co-authored-by: Lukas Wirth <me@lukaswirth.dev>
Co-authored-by: Lukas Wirth <lukas@zed.dev>
This commit is contained in:
Casper van Elteren
2025-11-07 12:35:06 +00:00
committed by GitHub
co-authored by Lukas Wirth Lukas Wirth
parent 082b80ec89
commit 9d52b6c538
8 changed files with 74 additions and 12 deletions
+29 -3
View File
@@ -21,9 +21,11 @@ use project::Fs;
use project::lsp_store::language_server_settings;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use settings::Settings;
use smol::lock::OnceCell;
use std::cmp::Ordering;
use std::env::consts;
use terminal::terminal_settings::TerminalSettings;
use util::command::new_smol_command;
use util::fs::{make_file_executable, remove_matching};
use util::rel_path::RelPath;
@@ -1171,7 +1173,7 @@ impl ToolchainLister for PythonToolchainProvider {
.context("Could not convert a venv into a toolchain")
}
fn activation_script(&self, toolchain: &Toolchain, shell: ShellKind) -> Vec<String> {
fn activation_script(&self, toolchain: &Toolchain, shell: ShellKind, cx: &App) -> Vec<String> {
let Ok(toolchain) =
serde_json::from_value::<PythonToolchainData>(toolchain.as_json.clone())
else {
@@ -1184,10 +1186,34 @@ impl ToolchainLister for PythonToolchainProvider {
match toolchain.environment.kind {
Some(PythonEnvironmentKind::Conda) => {
let settings = TerminalSettings::get_global(cx);
let conda_manager = settings
.detect_venv
.as_option()
.map(|venv| venv.conda_manager)
.unwrap_or(settings::CondaManager::Auto);
let manager = match conda_manager {
settings::CondaManager::Conda => "conda",
settings::CondaManager::Mamba => "mamba",
settings::CondaManager::Micromamba => "micromamba",
settings::CondaManager::Auto => {
// When auto, prefer the detected manager or fall back to conda
toolchain
.environment
.manager
.as_ref()
.and_then(|m| m.executable.file_name())
.and_then(|name| name.to_str())
.filter(|name| matches!(*name, "conda" | "mamba" | "micromamba"))
.unwrap_or("conda")
}
};
if let Some(name) = &toolchain.environment.name {
activation_script.push(format!("conda activate {name}"));
activation_script.push(format!("{manager} activate {name}"));
} else {
activation_script.push("conda activate".to_string());
activation_script.push(format!("{manager} activate base"));
}
}
Some(PythonEnvironmentKind::Venv | PythonEnvironmentKind::VirtualEnv) => {