Revert "Revert "python: Enable subroot detection for pylsp and pyright (#27364)" (#29658)" (#30810)

Ben Kunkle created

Revert "Revert "python: Enable subroot detection for pylsp and pyright
(#27364)" (#29658)"

This reverts commit 59708ef56c569737db3876e6073b9657c6d25c03.

Closes #29699

Release Notes:

- N/A

Change summary

crates/languages/src/lib.rs    |  9 ++++++++-
crates/languages/src/python.rs | 34 +++++++++++++++++++++++++++++++++-
2 files changed, 41 insertions(+), 2 deletions(-)

Detailed changes

crates/languages/src/lib.rs 🔗

@@ -2,6 +2,7 @@ use anyhow::Context as _;
 use gpui::{App, UpdateGlobal};
 use json::json_task_context;
 use node_runtime::NodeRuntime;
+use python::PyprojectTomlManifestProvider;
 use rust::CargoManifestProvider;
 use rust_embed::RustEmbed;
 use settings::SettingsStore;
@@ -302,7 +303,13 @@ pub fn init(languages: Arc<LanguageRegistry>, node: NodeRuntime, cx: &mut App) {
         anyhow::Ok(())
     })
     .detach();
-    project::ManifestProviders::global(cx).register(Arc::from(CargoManifestProvider));
+    let manifest_providers: [Arc<dyn ManifestProvider>; 2] = [
+        Arc::from(CargoManifestProvider),
+        Arc::from(PyprojectTomlManifestProvider),
+    ];
+    for provider in manifest_providers {
+        project::ManifestProviders::global(cx).register(provider);
+    }
 }
 
 #[derive(Default)]

crates/languages/src/python.rs 🔗

@@ -4,13 +4,13 @@ use async_trait::async_trait;
 use collections::HashMap;
 use gpui::{App, Task};
 use gpui::{AsyncApp, SharedString};
-use language::LanguageName;
 use language::LanguageToolchainStore;
 use language::Toolchain;
 use language::ToolchainList;
 use language::ToolchainLister;
 use language::language_settings::language_settings;
 use language::{ContextProvider, LspAdapter, LspAdapterDelegate};
+use language::{LanguageName, ManifestName, ManifestProvider, ManifestQuery};
 use lsp::LanguageServerBinary;
 use lsp::LanguageServerName;
 use node_runtime::NodeRuntime;
@@ -38,6 +38,32 @@ use std::{
 use task::{TaskTemplate, TaskTemplates, VariableName};
 use util::ResultExt;
 
+pub(crate) struct PyprojectTomlManifestProvider;
+
+impl ManifestProvider for PyprojectTomlManifestProvider {
+    fn name(&self) -> ManifestName {
+        SharedString::new_static("pyproject.toml").into()
+    }
+
+    fn search(
+        &self,
+        ManifestQuery {
+            path,
+            depth,
+            delegate,
+        }: ManifestQuery,
+    ) -> Option<Arc<Path>> {
+        for path in path.ancestors().take(depth) {
+            let p = path.join("pyproject.toml");
+            if delegate.exists(&p, Some(false)) {
+                return Some(path.into());
+            }
+        }
+
+        None
+    }
+}
+
 const SERVER_PATH: &str = "node_modules/pyright/langserver.index.js";
 const NODE_MODULE_RELATIVE_SERVER_PATH: &str = "pyright/langserver.index.js";
 
@@ -301,6 +327,9 @@ impl LspAdapter for PythonLspAdapter {
             user_settings
         })
     }
+    fn manifest_name(&self) -> Option<ManifestName> {
+        Some(SharedString::new_static("pyproject.toml").into())
+    }
 }
 
 async fn get_cached_server_binary(
@@ -1142,6 +1171,9 @@ impl LspAdapter for PyLspAdapter {
             user_settings
         })
     }
+    fn manifest_name(&self) -> Option<ManifestName> {
+        Some(SharedString::new_static("pyproject.toml").into())
+    }
 }
 
 #[cfg(test)]