1//! This module defines a Manifest Tree.
2//!
3//! A Manifest Tree is responsible for determining where the manifests for subprojects are located in a project.
4//! This then is used to provide those locations to language servers & determine locations eligible for toolchain selection.
5
6mod manifest_store;
7mod path_trie;
8mod server_tree;
9
10use std::{
11 borrow::Borrow,
12 collections::{BTreeMap, hash_map::Entry},
13 ops::ControlFlow,
14 sync::Arc,
15};
16
17use collections::HashMap;
18use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Subscription};
19use language::{LspAdapterDelegate, ManifestName, ManifestQuery};
20pub use manifest_store::ManifestProviders;
21use path_trie::{LabelPresence, RootPathTrie, TriePath};
22use settings::{SettingsStore, WorktreeId};
23use worktree::{Event as WorktreeEvent, Worktree};
24
25use crate::{
26 ProjectPath,
27 worktree_store::{WorktreeStore, WorktreeStoreEvent},
28};
29
30pub(crate) use server_tree::{AdapterQuery, LanguageServerTree, LaunchDisposition};
31
32struct WorktreeRoots {
33 roots: RootPathTrie<ManifestName>,
34 worktree_store: Entity<WorktreeStore>,
35 _worktree_subscription: Subscription,
36}
37
38impl WorktreeRoots {
39 fn new(
40 worktree_store: Entity<WorktreeStore>,
41 worktree: Entity<Worktree>,
42 cx: &mut App,
43 ) -> Entity<Self> {
44 cx.new(|cx| Self {
45 roots: RootPathTrie::new(),
46 worktree_store,
47 _worktree_subscription: cx.subscribe(&worktree, |this: &mut Self, _, event, cx| {
48 match event {
49 WorktreeEvent::UpdatedEntries(changes) => {
50 for (path, _, kind) in changes.iter() {
51 match kind {
52 worktree::PathChange::Removed => {
53 let path = TriePath::from(path.as_ref());
54 this.roots.remove(&path);
55 }
56 _ => {}
57 }
58 }
59 }
60 WorktreeEvent::UpdatedGitRepositories(_) => {}
61 WorktreeEvent::DeletedEntry(entry_id) => {
62 let Some(entry) = this.worktree_store.read(cx).entry_for_id(*entry_id, cx)
63 else {
64 return;
65 };
66 let path = TriePath::from(entry.path.as_ref());
67 this.roots.remove(&path);
68 }
69 }
70 }),
71 })
72 }
73}
74
75pub struct ManifestTree {
76 root_points: HashMap<WorktreeId, Entity<WorktreeRoots>>,
77 worktree_store: Entity<WorktreeStore>,
78 _subscriptions: [Subscription; 2],
79}
80
81#[derive(PartialEq)]
82pub(crate) enum ManifestTreeEvent {
83 WorktreeRemoved(WorktreeId),
84 Cleared,
85}
86
87impl EventEmitter<ManifestTreeEvent> for ManifestTree {}
88
89impl ManifestTree {
90 pub(crate) fn new(worktree_store: Entity<WorktreeStore>, cx: &mut App) -> Entity<Self> {
91 cx.new(|cx| Self {
92 root_points: Default::default(),
93 _subscriptions: [
94 cx.subscribe(&worktree_store, Self::on_worktree_store_event),
95 cx.observe_global::<SettingsStore>(|this, cx| {
96 for (_, roots) in &mut this.root_points {
97 roots.update(cx, |worktree_roots, _| {
98 worktree_roots.roots = RootPathTrie::new();
99 })
100 }
101 cx.emit(ManifestTreeEvent::Cleared);
102 }),
103 ],
104 worktree_store,
105 })
106 }
107 fn root_for_path(
108 &mut self,
109 ProjectPath { worktree_id, path }: ProjectPath,
110 manifests: &mut dyn Iterator<Item = ManifestName>,
111 delegate: Arc<dyn LspAdapterDelegate>,
112 cx: &mut App,
113 ) -> BTreeMap<ManifestName, ProjectPath> {
114 debug_assert_eq!(delegate.worktree_id(), worktree_id);
115 let mut roots = BTreeMap::from_iter(
116 manifests.map(|manifest| (manifest, (None, LabelPresence::KnownAbsent))),
117 );
118 let worktree_roots = match self.root_points.entry(worktree_id) {
119 Entry::Occupied(occupied_entry) => occupied_entry.get().clone(),
120 Entry::Vacant(vacant_entry) => {
121 let Some(worktree) = self
122 .worktree_store
123 .read(cx)
124 .worktree_for_id(worktree_id, cx)
125 else {
126 return Default::default();
127 };
128 let roots = WorktreeRoots::new(self.worktree_store.clone(), worktree, cx);
129 vacant_entry.insert(roots).clone()
130 }
131 };
132
133 let key = TriePath::from(&*path);
134 worktree_roots.update(cx, |this, _| {
135 this.roots.walk(&key, &mut |path, labels| {
136 for (label, presence) in labels {
137 if let Some((marked_path, current_presence)) = roots.get_mut(label) {
138 if *current_presence > *presence {
139 debug_assert!(false, "RootPathTrie precondition violation; while walking the tree label presence is only allowed to increase");
140 }
141 *marked_path = Some(ProjectPath {worktree_id, path: path.clone()});
142 *current_presence = *presence;
143 }
144
145 }
146 ControlFlow::Continue(())
147 });
148 });
149
150 for (manifest_name, (root_path, presence)) in &mut roots {
151 if *presence == LabelPresence::Present {
152 continue;
153 }
154
155 let depth = root_path
156 .as_ref()
157 .map(|root_path| {
158 path.strip_prefix(&root_path.path)
159 .unwrap()
160 .components()
161 .count()
162 })
163 .unwrap_or_else(|| path.components().count() + 1);
164
165 if depth > 0 {
166 let Some(provider) = ManifestProviders::global(cx).get(manifest_name.borrow())
167 else {
168 log::warn!("Manifest provider `{}` not found", manifest_name.as_ref());
169 continue;
170 };
171
172 let root = provider.search(ManifestQuery {
173 path: path.clone(),
174 depth,
175 delegate: delegate.clone(),
176 });
177 match root {
178 Some(known_root) => worktree_roots.update(cx, |this, _| {
179 let root = TriePath::from(&*known_root);
180 this.roots
181 .insert(&root, manifest_name.clone(), LabelPresence::Present);
182 *presence = LabelPresence::Present;
183 *root_path = Some(ProjectPath {
184 worktree_id,
185 path: known_root,
186 });
187 }),
188 None => worktree_roots.update(cx, |this, _| {
189 this.roots
190 .insert(&key, manifest_name.clone(), LabelPresence::KnownAbsent);
191 }),
192 }
193 }
194 }
195
196 roots
197 .into_iter()
198 .filter_map(|(k, (path, presence))| {
199 let path = path?;
200 presence.eq(&LabelPresence::Present).then(|| (k, path))
201 })
202 .collect()
203 }
204 fn on_worktree_store_event(
205 &mut self,
206 _: Entity<WorktreeStore>,
207 evt: &WorktreeStoreEvent,
208 cx: &mut Context<Self>,
209 ) {
210 match evt {
211 WorktreeStoreEvent::WorktreeRemoved(_, worktree_id) => {
212 self.root_points.remove(&worktree_id);
213 cx.emit(ManifestTreeEvent::WorktreeRemoved(*worktree_id));
214 }
215 _ => {}
216 }
217 }
218}