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

@ -11,6 +11,7 @@ mod diagnostic_set;
mod highlight_map;
mod language_registry;
pub mod language_settings;
mod manifest;
mod outline;
pub mod proto;
mod syntax_map;
@ -33,6 +34,7 @@ pub use highlight_map::HighlightMap;
use http_client::HttpClient;
pub use language_registry::{LanguageName, LoadedLanguage};
use lsp::{CodeActionKind, InitializeParams, LanguageServerBinary, LanguageServerBinaryOptions};
pub use manifest::{ManifestName, ManifestProvider, ManifestQuery};
use parking_lot::Mutex;
use regex::Regex;
use schemars::{
@ -163,6 +165,7 @@ pub struct CachedLspAdapter {
pub adapter: Arc<dyn LspAdapter>,
pub reinstall_attempt_count: AtomicU64,
cached_binary: futures::lock::Mutex<Option<LanguageServerBinary>>,
manifest_name: OnceLock<Option<ManifestName>>,
attach_kind: OnceLock<Attach>,
}
@ -200,6 +203,7 @@ impl CachedLspAdapter {
cached_binary: Default::default(),
reinstall_attempt_count: AtomicU64::new(0),
attach_kind: Default::default(),
manifest_name: Default::default(),
})
}
@ -261,14 +265,10 @@ impl CachedLspAdapter {
.cloned()
.unwrap_or_else(|| language_name.lsp_id())
}
pub fn find_project_root(
&self,
path: &Path,
ancestor_depth: usize,
delegate: &Arc<dyn LspAdapterDelegate>,
) -> Option<Arc<Path>> {
self.adapter
.find_project_root(path, ancestor_depth, delegate)
pub fn manifest_name(&self) -> Option<ManifestName> {
self.manifest_name
.get_or_init(|| self.adapter.manifest_name())
.clone()
}
pub fn attach_kind(&self) -> Attach {
*self.attach_kind.get_or_init(|| self.adapter.attach_kind())
@ -542,18 +542,13 @@ pub trait LspAdapter: 'static + Send + Sync {
fn prepare_initialize_params(&self, original: InitializeParams) -> Result<InitializeParams> {
Ok(original)
}
fn attach_kind(&self) -> Attach {
Attach::Shared
}
fn find_project_root(
&self,
_path: &Path,
_ancestor_depth: usize,
_: &Arc<dyn LspAdapterDelegate>,
) -> Option<Arc<Path>> {
// By default all language servers are rooted at the root of the worktree.
Some(Arc::from("".as_ref()))
fn manifest_name(&self) -> Option<ManifestName> {
None
}
/// Method only implemented by the default JSON language server adapter.

View file

@ -0,0 +1,48 @@
use std::{borrow::Borrow, path::Path, sync::Arc};
use gpui::SharedString;
use crate::LspAdapterDelegate;
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ManifestName(SharedString);
impl Borrow<SharedString> for ManifestName {
fn borrow(&self) -> &SharedString {
&self.0
}
}
impl From<SharedString> for ManifestName {
fn from(value: SharedString) -> Self {
Self(value)
}
}
impl From<ManifestName> for SharedString {
fn from(value: ManifestName) -> Self {
value.0
}
}
impl AsRef<SharedString> for ManifestName {
fn as_ref(&self) -> &SharedString {
&self.0
}
}
/// Represents a manifest query; given a path to a file, [ManifestSearcher] is tasked with finding a path to the directory containing the manifest for that file.
///
/// Since parts of the path might have already been explored, there's an additional `depth` parameter that indicates to what ancestry level a given path should be explored.
/// For example, given a path like `foo/bar/baz`, a depth of 2 would explore `foo/bar/baz` and `foo/bar`, but not `foo`.
pub struct ManifestQuery {
/// Path to the file, relative to worktree root.
pub path: Arc<Path>,
pub depth: usize,
pub delegate: Arc<dyn LspAdapterDelegate>,
}
pub trait ManifestProvider {
fn name(&self) -> ManifestName;
fn search(&self, query: ManifestQuery) -> Option<Arc<Path>>;
}