From d80f9dda75528449d27ea7eff5ea170e617689d6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 3 Sep 2025 16:11:36 +0200 Subject: [PATCH] languages: Fix python tasks failing when binary contains whitespaces (#37454) Fixes https://github.com/zed-industries/zed/issues/33459 Release Notes: - Fixed python tasks failing when the python binary path contains whitespaces --- crates/languages/src/python.rs | 39 ++++++++----------- .../project/src/debugger/locators/python.rs | 16 ++------ 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs index 5bdc4aa0d94a7355c60ab8912d9a328a657ad77f..bd3a7b34cf873328e480012ca96fcbe9fc3eff95 100644 --- a/crates/languages/src/python.rs +++ b/crates/languages/src/python.rs @@ -409,9 +409,6 @@ const PYTHON_TEST_TARGET_TASK_VARIABLE: VariableName = const PYTHON_ACTIVE_TOOLCHAIN_PATH: VariableName = VariableName::Custom(Cow::Borrowed("PYTHON_ACTIVE_ZED_TOOLCHAIN")); -const PYTHON_ACTIVE_TOOLCHAIN_PATH_RAW: VariableName = - VariableName::Custom(Cow::Borrowed("PYTHON_ACTIVE_ZED_TOOLCHAIN_RAW")); - const PYTHON_MODULE_NAME_TASK_VARIABLE: VariableName = VariableName::Custom(Cow::Borrowed("PYTHON_MODULE_NAME")); @@ -435,7 +432,7 @@ impl ContextProvider for PythonContextProvider { let worktree_id = location_file.as_ref().map(|f| f.worktree_id(cx)); cx.spawn(async move |cx| { - let raw_toolchain = if let Some(worktree_id) = worktree_id { + let active_toolchain = if let Some(worktree_id) = worktree_id { let file_path = location_file .as_ref() .and_then(|f| f.path().parent()) @@ -453,15 +450,13 @@ impl ContextProvider for PythonContextProvider { String::from("python3") }; - let active_toolchain = format!("\"{raw_toolchain}\""); let toolchain = (PYTHON_ACTIVE_TOOLCHAIN_PATH, active_toolchain); - let raw_toolchain_var = (PYTHON_ACTIVE_TOOLCHAIN_PATH_RAW, raw_toolchain); Ok(task::TaskVariables::from_iter( test_target .into_iter() .chain(module_target.into_iter()) - .chain([toolchain, raw_toolchain_var]), + .chain([toolchain]), )) }) } @@ -478,31 +473,31 @@ impl ContextProvider for PythonContextProvider { // Execute a selection TaskTemplate { label: "execute selection".to_owned(), - command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value(), + command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value_with_whitespace(), args: vec![ "-c".to_owned(), VariableName::SelectedText.template_value_with_whitespace(), ], - cwd: Some("$ZED_WORKTREE_ROOT".into()), + cwd: Some(VariableName::WorktreeRoot.template_value()), ..TaskTemplate::default() }, // Execute an entire file TaskTemplate { label: format!("run '{}'", VariableName::File.template_value()), - command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value(), + command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value_with_whitespace(), args: vec![VariableName::File.template_value_with_whitespace()], - cwd: Some("$ZED_WORKTREE_ROOT".into()), + cwd: Some(VariableName::WorktreeRoot.template_value()), ..TaskTemplate::default() }, // Execute a file as module TaskTemplate { label: format!("run module '{}'", VariableName::File.template_value()), - command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value(), + command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value_with_whitespace(), args: vec![ "-m".to_owned(), - PYTHON_MODULE_NAME_TASK_VARIABLE.template_value(), + PYTHON_MODULE_NAME_TASK_VARIABLE.template_value_with_whitespace(), ], - cwd: Some("$ZED_WORKTREE_ROOT".into()), + cwd: Some(VariableName::WorktreeRoot.template_value()), tags: vec!["python-module-main-method".to_owned()], ..TaskTemplate::default() }, @@ -514,19 +509,19 @@ impl ContextProvider for PythonContextProvider { // Run tests for an entire file TaskTemplate { label: format!("unittest '{}'", VariableName::File.template_value()), - command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value(), + command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value_with_whitespace(), args: vec![ "-m".to_owned(), "unittest".to_owned(), VariableName::File.template_value_with_whitespace(), ], - cwd: Some("$ZED_WORKTREE_ROOT".into()), + cwd: Some(VariableName::WorktreeRoot.template_value()), ..TaskTemplate::default() }, // Run test(s) for a specific target within a file TaskTemplate { label: "unittest $ZED_CUSTOM_PYTHON_TEST_TARGET".to_owned(), - command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value(), + command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value_with_whitespace(), args: vec![ "-m".to_owned(), "unittest".to_owned(), @@ -536,7 +531,7 @@ impl ContextProvider for PythonContextProvider { "python-unittest-class".to_owned(), "python-unittest-method".to_owned(), ], - cwd: Some("$ZED_WORKTREE_ROOT".into()), + cwd: Some(VariableName::WorktreeRoot.template_value()), ..TaskTemplate::default() }, ] @@ -546,25 +541,25 @@ impl ContextProvider for PythonContextProvider { // Run tests for an entire file TaskTemplate { label: format!("pytest '{}'", VariableName::File.template_value()), - command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value(), + command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value_with_whitespace(), args: vec![ "-m".to_owned(), "pytest".to_owned(), VariableName::File.template_value_with_whitespace(), ], - cwd: Some("$ZED_WORKTREE_ROOT".into()), + cwd: Some(VariableName::WorktreeRoot.template_value()), ..TaskTemplate::default() }, // Run test(s) for a specific target within a file TaskTemplate { label: "pytest $ZED_CUSTOM_PYTHON_TEST_TARGET".to_owned(), - command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value(), + command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value_with_whitespace(), args: vec![ "-m".to_owned(), "pytest".to_owned(), PYTHON_TEST_TARGET_TASK_VARIABLE.template_value_with_whitespace(), ], - cwd: Some("$ZED_WORKTREE_ROOT".into()), + cwd: Some(VariableName::WorktreeRoot.template_value()), tags: vec![ "python-pytest-class".to_owned(), "python-pytest-method".to_owned(), diff --git a/crates/project/src/debugger/locators/python.rs b/crates/project/src/debugger/locators/python.rs index 71efbb75b91c819fcfdb857769877452f9e5a730..06f7ab2e796c8139f2f8723b95f7f4503250a0c3 100644 --- a/crates/project/src/debugger/locators/python.rs +++ b/crates/project/src/debugger/locators/python.rs @@ -25,7 +25,7 @@ impl DapLocator for PythonLocator { if adapter.0.as_ref() != "Debugpy" { return None; } - let valid_program = build_config.command.starts_with("$ZED_") + let valid_program = build_config.command.starts_with("\"$ZED_") || Path::new(&build_config.command) .file_name() .is_some_and(|name| name.to_str().is_some_and(|path| path.starts_with("python"))); @@ -33,13 +33,7 @@ impl DapLocator for PythonLocator { // We cannot debug selections. return None; } - let command = if build_config.command - == VariableName::Custom("PYTHON_ACTIVE_ZED_TOOLCHAIN".into()).template_value() - { - VariableName::Custom("PYTHON_ACTIVE_ZED_TOOLCHAIN_RAW".into()).template_value() - } else { - build_config.command.clone() - }; + let command = build_config.command.clone(); let module_specifier_position = build_config .args .iter() @@ -57,10 +51,8 @@ impl DapLocator for PythonLocator { let program_position = mod_name .is_none() .then(|| { - build_config - .args - .iter() - .position(|arg| *arg == "\"$ZED_FILE\"") + let zed_file = VariableName::File.template_value_with_whitespace(); + build_config.args.iter().position(|arg| *arg == zed_file) }) .flatten(); let args = if let Some(position) = program_position {