windows: Detect when python3 is not usable and notify the user (#40070)
Fixes #39998 Debugpy and pylsp are installed in a Zed-global venv with pip. We need a Python interpreter to create this venv when it doesn't exist and one of these tools needs to be installed, and sometimes we attempt to use `python3` from `$PATH`. This can cause issues on Windows, where out of the box `python3` is a sort of shim that opens the Microsoft Store app. This PR changes the debugpy installation path to create the Zed-global venv using the Python interpreter from a venv in the project, and only use python3 from `$PATH` if that fails. That matches how pylsp installation already works. It also tightens up how we search for a global Python installation by doing a basic sanity check (`python3 -c 'print(1 + 2)`) before accepting it, which should catch the Windows shim. Release Notes: - windows: improved the behavior of Zed in situations where no global Python installation exists.
This commit is contained in:
@@ -23,6 +23,7 @@ use serde_json::{Value, json};
|
||||
use smol::lock::OnceCell;
|
||||
use std::cmp::Ordering;
|
||||
use std::env::consts;
|
||||
use util::command::new_smol_command;
|
||||
use util::fs::{make_file_executable, remove_matching};
|
||||
use util::rel_path::RelPath;
|
||||
|
||||
@@ -1332,7 +1333,13 @@ impl PyLspAdapter {
|
||||
async fn ensure_venv(delegate: &dyn LspAdapterDelegate) -> Result<Arc<Path>> {
|
||||
let python_path = Self::find_base_python(delegate)
|
||||
.await
|
||||
.context("Could not find Python installation for PyLSP")?;
|
||||
.with_context(|| {
|
||||
let mut message = "Could not find Python installation for PyLSP".to_owned();
|
||||
if cfg!(windows){
|
||||
message.push_str(". Install Python from the Microsoft Store, or manually from https://www.python.org/downloads/windows.")
|
||||
}
|
||||
message
|
||||
})?;
|
||||
let work_dir = delegate
|
||||
.language_server_download_dir(&Self::SERVER_NAME)
|
||||
.await
|
||||
@@ -1355,9 +1362,24 @@ impl PyLspAdapter {
|
||||
// Find "baseline", user python version from which we'll create our own venv.
|
||||
async fn find_base_python(delegate: &dyn LspAdapterDelegate) -> Option<PathBuf> {
|
||||
for path in ["python3", "python"] {
|
||||
if let Some(path) = delegate.which(path.as_ref()).await {
|
||||
return Some(path);
|
||||
let Some(path) = delegate.which(path.as_ref()).await else {
|
||||
continue;
|
||||
};
|
||||
// Try to detect situations where `python3` exists but is not a real Python interpreter.
|
||||
// Notably, on fresh Windows installs, `python3` is a shim that opens the Microsoft Store app
|
||||
// when run with no arguments, and just fails otherwise.
|
||||
let Some(output) = new_smol_command(&path)
|
||||
.args(["-c", "print(1 + 2)"])
|
||||
.output()
|
||||
.await
|
||||
.ok()
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
if output.stdout.trim_ascii() != b"3" {
|
||||
continue;
|
||||
}
|
||||
return Some(path);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user