project: Track manifest locations per unique manifest locator (#27194)

This pull request paves way for exposing manifest tracking to
extensions.
- Project tree was renamed to manifest tree to better reflect it's
intent (and avoid confusion).
- Language server adapters now provide a name of their *manifest
locator*. If multiple language servers refer to the same locator, the
locating code will run just once for a given path.

Release Notes:

- N/A *or* Added/Fixed/Improved ...

---------

Co-authored-by: Anthony <anthony@zed.dev>
This commit is contained in:
Piotr Osiewicz 2025-03-21 15:22:36 +01:00 committed by GitHub
parent 6bced3a834
commit 05aa8880a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 241 additions and 154 deletions

View file

@ -2,6 +2,7 @@ use anyhow::Context as _;
use gpui::{App, UpdateGlobal};
use json::json_task_context;
use node_runtime::NodeRuntime;
use rust::CargoManifestProvider;
use rust_embed::RustEmbed;
use settings::SettingsStore;
use smol::stream::StreamExt;
@ -301,6 +302,7 @@ pub fn init(languages: Arc<LanguageRegistry>, node: NodeRuntime, cx: &mut App) {
anyhow::Ok(())
})
.detach();
project::ManifestProviders::global(cx).register(Arc::from(CargoManifestProvider));
}
#[derive(Default)]

View file

@ -3,7 +3,7 @@ use async_compression::futures::bufread::GzipDecoder;
use async_trait::async_trait;
use collections::HashMap;
use futures::{io::BufReader, StreamExt};
use gpui::{App, AsyncApp, Task};
use gpui::{App, AsyncApp, SharedString, Task};
use http_client::github::AssetKind;
use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
pub use language::*;
@ -68,20 +68,23 @@ impl RustLspAdapter {
}
}
#[async_trait(?Send)]
impl LspAdapter for RustLspAdapter {
fn name(&self) -> LanguageServerName {
Self::SERVER_NAME.clone()
pub(crate) struct CargoManifestProvider;
impl ManifestProvider for CargoManifestProvider {
fn name(&self) -> ManifestName {
SharedString::new_static("Cargo.toml").into()
}
fn find_project_root(
fn search(
&self,
path: &Path,
ancestor_depth: usize,
delegate: &Arc<dyn LspAdapterDelegate>,
ManifestQuery {
path,
depth,
delegate,
}: ManifestQuery,
) -> Option<Arc<Path>> {
let mut outermost_cargo_toml = None;
for path in path.ancestors().take(ancestor_depth) {
for path in path.ancestors().take(depth) {
let p = path.join("Cargo.toml");
if delegate.exists(&p, Some(false)) {
outermost_cargo_toml = Some(Arc::from(path));
@ -90,6 +93,17 @@ impl LspAdapter for RustLspAdapter {
outermost_cargo_toml
}
}
#[async_trait(?Send)]
impl LspAdapter for RustLspAdapter {
fn name(&self) -> LanguageServerName {
Self::SERVER_NAME.clone()
}
fn manifest_name(&self) -> Option<ManifestName> {
Some(SharedString::new_static("Cargo.toml").into())
}
async fn check_if_user_installed(
&self,