1//! This module defines an LSP Tree.
2//!
3//! An LSP Tree is responsible for determining which language servers apply to a given project path.
4//!
5//! ## RPC
6//! LSP Tree is transparent to RPC peers; when clients ask host to spawn a new language server, the host will perform LSP Tree lookup for provided path; it may decide
7//! to reuse existing language server. The client maintains it's own LSP Tree that is a subset of host LSP Tree. Done this way, the client does not need to
8//! ask about suitable language server for each path it interacts with; it can resolve most of the queries locally.
9
10use std::{
11 collections::{BTreeMap, BTreeSet},
12 path::Path,
13 sync::{Arc, Weak},
14};
15
16use collections::IndexMap;
17use gpui::{App, AppContext as _, Entity, Subscription};
18use language::{
19 CachedLspAdapter, LanguageName, LanguageRegistry, ManifestDelegate,
20 language_settings::AllLanguageSettings,
21};
22use lsp::LanguageServerName;
23use settings::{Settings, SettingsLocation, WorktreeId};
24use std::sync::OnceLock;
25
26use crate::{LanguageServerId, ProjectPath, project_settings::LspSettings};
27
28use super::{ManifestTree, ManifestTreeEvent};
29
30#[derive(Debug, Default)]
31pub(crate) struct ServersForWorktree {
32 pub(crate) roots: BTreeMap<
33 Arc<Path>,
34 BTreeMap<LanguageServerName, (Arc<InnerTreeNode>, BTreeSet<LanguageName>)>,
35 >,
36}
37
38pub struct LanguageServerTree {
39 manifest_tree: Entity<ManifestTree>,
40 pub(crate) instances: BTreeMap<WorktreeId, ServersForWorktree>,
41 languages: Arc<LanguageRegistry>,
42 _subscriptions: Subscription,
43}
44
45/// A node in language server tree represents either:
46/// - A language server that has already been initialized/updated for a given project
47/// - A soon-to-be-initialized language server.
48#[derive(Clone)]
49pub struct LanguageServerTreeNode(Weak<InnerTreeNode>);
50
51/// Describes a request to launch a language server.
52#[derive(Debug)]
53pub(crate) struct LaunchDisposition<'a> {
54 pub(crate) server_name: &'a LanguageServerName,
55 pub(crate) path: ProjectPath,
56 pub(crate) settings: Arc<LspSettings>,
57}
58
59impl<'a> From<&'a InnerTreeNode> for LaunchDisposition<'a> {
60 fn from(value: &'a InnerTreeNode) -> Self {
61 LaunchDisposition {
62 server_name: &value.name,
63 path: value.path.clone(),
64 settings: value.settings.clone(),
65 }
66 }
67}
68impl LanguageServerTreeNode {
69 /// Returns a language server ID for this node if there is one.
70 /// Returns None if this node has not been initialized yet or it is no longer in the tree.
71 pub(crate) fn server_id(&self) -> Option<LanguageServerId> {
72 self.0.upgrade()?.id.get().copied()
73 }
74
75 /// Returns a language server ID for this node if it has already been initialized; otherwise runs the provided closure to initialize the language server node in a tree.
76 /// May return None if the node no longer belongs to the server tree it was created in.
77 pub(crate) fn server_id_or_init(
78 &self,
79 init: impl FnOnce(LaunchDisposition) -> LanguageServerId,
80 ) -> Option<LanguageServerId> {
81 let this = self.0.upgrade()?;
82 Some(
83 *this
84 .id
85 .get_or_init(|| init(LaunchDisposition::from(&*this))),
86 )
87 }
88
89 /// Returns a language server name as the language server adapter would return.
90 pub fn name(&self) -> Option<LanguageServerName> {
91 self.0.upgrade().map(|node| node.name.clone())
92 }
93}
94
95impl From<Weak<InnerTreeNode>> for LanguageServerTreeNode {
96 fn from(weak: Weak<InnerTreeNode>) -> Self {
97 LanguageServerTreeNode(weak)
98 }
99}
100
101#[derive(Debug)]
102pub struct InnerTreeNode {
103 id: OnceLock<LanguageServerId>,
104 name: LanguageServerName,
105 path: ProjectPath,
106 settings: Arc<LspSettings>,
107}
108
109impl InnerTreeNode {
110 fn new(
111 name: LanguageServerName,
112 path: ProjectPath,
113 settings: impl Into<Arc<LspSettings>>,
114 ) -> Self {
115 InnerTreeNode {
116 id: Default::default(),
117 name,
118 path,
119 settings: settings.into(),
120 }
121 }
122}
123
124/// Determines how the list of adapters to query should be constructed.
125pub(crate) enum AdapterQuery<'a> {
126 /// Search for roots of all adapters associated with a given language name.
127 /// Layman: Look for all project roots along the queried path that have any
128 /// language server associated with this language running.
129 Language(&'a LanguageName),
130 /// Search for roots of adapter with a given name.
131 /// Layman: Look for all project roots along the queried path that have this server running.
132 Adapter(&'a LanguageServerName),
133}
134
135impl LanguageServerTree {
136 pub(crate) fn new(
137 manifest_tree: Entity<ManifestTree>,
138 languages: Arc<LanguageRegistry>,
139 cx: &mut App,
140 ) -> Entity<Self> {
141 cx.new(|cx| Self {
142 _subscriptions: cx.subscribe(&manifest_tree, |_: &mut Self, _, event, _| {
143 if event == &ManifestTreeEvent::Cleared {}
144 }),
145 manifest_tree,
146 instances: Default::default(),
147
148 languages,
149 })
150 }
151
152 /// Get all language server root points for a given path and language; the language servers might already be initialized at a given path.
153 pub(crate) fn get<'a>(
154 &'a mut self,
155 path: ProjectPath,
156 query: AdapterQuery<'_>,
157 delegate: Arc<dyn ManifestDelegate>,
158 cx: &mut App,
159 ) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
160 let settings_location = SettingsLocation {
161 worktree_id: path.worktree_id,
162 path: &path.path,
163 };
164 let adapters = match query {
165 AdapterQuery::Language(language_name) => {
166 self.adapters_for_language(settings_location, language_name, cx)
167 }
168 AdapterQuery::Adapter(language_server_name) => {
169 IndexMap::from_iter(self.adapter_for_name(language_server_name).map(|adapter| {
170 (
171 adapter.name(),
172 (LspSettings::default(), BTreeSet::new(), adapter),
173 )
174 }))
175 }
176 };
177 self.get_with_adapters(path, adapters, delegate, cx)
178 }
179
180 fn get_with_adapters<'a>(
181 &'a mut self,
182 path: ProjectPath,
183 adapters: IndexMap<
184 LanguageServerName,
185 (LspSettings, BTreeSet<LanguageName>, Arc<CachedLspAdapter>),
186 >,
187 delegate: Arc<dyn ManifestDelegate>,
188 cx: &mut App,
189 ) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
190 let worktree_id = path.worktree_id;
191
192 let mut manifest_to_adapters = BTreeMap::default();
193 for (_, _, adapter) in adapters.values() {
194 if let Some(manifest_name) = adapter.manifest_name() {
195 manifest_to_adapters
196 .entry(manifest_name)
197 .or_insert_with(Vec::default)
198 .push(adapter.clone());
199 }
200 }
201
202 let roots = self.manifest_tree.update(cx, |this, cx| {
203 this.root_for_path(
204 path,
205 &mut manifest_to_adapters.keys().cloned(),
206 delegate,
207 cx,
208 )
209 });
210 let root_path = std::cell::LazyCell::new(move || ProjectPath {
211 worktree_id,
212 path: Arc::from("".as_ref()),
213 });
214 adapters
215 .into_iter()
216 .map(move |(_, (settings, new_languages, adapter))| {
217 // Backwards-compat: Fill in any adapters for which we did not detect the root as having the project root at the root of a worktree.
218 let root_path = adapter
219 .manifest_name()
220 .and_then(|name| roots.get(&name))
221 .cloned()
222 .unwrap_or_else(|| root_path.clone());
223
224 let inner_node = self
225 .instances
226 .entry(root_path.worktree_id)
227 .or_default()
228 .roots
229 .entry(root_path.path.clone())
230 .or_default()
231 .entry(adapter.name());
232 let (node, languages) = inner_node.or_insert_with(|| {
233 (
234 Arc::new(InnerTreeNode::new(
235 adapter.name(),
236 root_path.clone(),
237 settings.clone(),
238 )),
239 Default::default(),
240 )
241 });
242 languages.extend(new_languages.iter().cloned());
243 Arc::downgrade(&node).into()
244 })
245 }
246
247 fn adapter_for_name(&self, name: &LanguageServerName) -> Option<Arc<CachedLspAdapter>> {
248 self.languages.adapter_for_name(name)
249 }
250
251 fn adapters_for_language(
252 &self,
253 settings_location: SettingsLocation,
254 language_name: &LanguageName,
255 cx: &App,
256 ) -> IndexMap<LanguageServerName, (LspSettings, BTreeSet<LanguageName>, Arc<CachedLspAdapter>)>
257 {
258 let settings = AllLanguageSettings::get(Some(settings_location), cx).language(
259 Some(settings_location),
260 Some(language_name),
261 cx,
262 );
263 if !settings.enable_language_server {
264 return Default::default();
265 }
266 let available_lsp_adapters = self.languages.lsp_adapters(&language_name);
267 let available_language_servers = available_lsp_adapters
268 .iter()
269 .map(|lsp_adapter| lsp_adapter.name.clone())
270 .collect::<Vec<_>>();
271
272 let desired_language_servers =
273 settings.customized_language_servers(&available_language_servers);
274 let adapters_with_settings = desired_language_servers
275 .into_iter()
276 .filter_map(|desired_adapter| {
277 let adapter = if let Some(adapter) = available_lsp_adapters
278 .iter()
279 .find(|adapter| adapter.name == desired_adapter)
280 {
281 Some(adapter.clone())
282 } else if let Some(adapter) =
283 self.languages.load_available_lsp_adapter(&desired_adapter)
284 {
285 self.languages
286 .register_lsp_adapter(language_name.clone(), adapter.adapter.clone());
287 Some(adapter)
288 } else {
289 None
290 }?;
291 let adapter_settings = crate::lsp_store::language_server_settings_for(
292 settings_location,
293 &adapter.name,
294 cx,
295 )
296 .cloned()
297 .unwrap_or_default();
298 Some((
299 adapter.name(),
300 (
301 adapter_settings,
302 BTreeSet::from_iter([language_name.clone()]),
303 adapter,
304 ),
305 ))
306 })
307 .collect::<IndexMap<_, _>>();
308 // After starting all the language servers, reorder them to reflect the desired order
309 // based on the settings.
310 //
311 // This is done, in part, to ensure that language servers loaded at different points
312 // (e.g., native vs extension) still end up in the right order at the end, rather than
313 // it being based on which language server happened to be loaded in first.
314 self.languages.reorder_language_servers(
315 &language_name,
316 adapters_with_settings
317 .values()
318 .map(|(_, _, adapter)| adapter.clone())
319 .collect(),
320 );
321
322 adapters_with_settings
323 }
324
325 // Rebasing a tree:
326 // - Clears it out
327 // - Provides you with the indirect access to the old tree while you're reinitializing a new one (by querying it).
328 pub(crate) fn rebase(&mut self) -> ServerTreeRebase<'_> {
329 ServerTreeRebase::new(self)
330 }
331
332 /// Remove nodes with a given ID from the tree.
333 pub(crate) fn remove_nodes(&mut self, ids: &BTreeSet<LanguageServerId>) {
334 for (_, servers) in &mut self.instances {
335 for (_, nodes) in &mut servers.roots {
336 nodes.retain(|_, (node, _)| node.id.get().map_or(true, |id| !ids.contains(&id)));
337 }
338 }
339 }
340
341 pub(crate) fn register_reused(
342 &mut self,
343 worktree_id: WorktreeId,
344 language_name: LanguageName,
345 reused: LanguageServerTreeNode,
346 ) {
347 let Some(node) = reused.0.upgrade() else {
348 return;
349 };
350
351 self.instances
352 .entry(worktree_id)
353 .or_default()
354 .roots
355 .entry(Arc::from(Path::new("")))
356 .or_default()
357 .entry(node.name.clone())
358 .or_insert_with(|| (node, BTreeSet::new()))
359 .1
360 .insert(language_name);
361 }
362}
363
364pub(crate) struct ServerTreeRebase<'a> {
365 old_contents: BTreeMap<WorktreeId, ServersForWorktree>,
366 new_tree: &'a mut LanguageServerTree,
367 /// All server IDs seen in the old tree.
368 all_server_ids: BTreeMap<LanguageServerId, LanguageServerName>,
369 /// Server IDs we've preserved for a new iteration of the tree. `all_server_ids - rebased_server_ids` is the
370 /// set of server IDs that can be shut down.
371 rebased_server_ids: BTreeSet<LanguageServerId>,
372}
373
374impl<'tree> ServerTreeRebase<'tree> {
375 fn new(new_tree: &'tree mut LanguageServerTree) -> Self {
376 let old_contents = std::mem::take(&mut new_tree.instances);
377 let all_server_ids = old_contents
378 .values()
379 .flat_map(|nodes| {
380 nodes.roots.values().flat_map(|servers| {
381 servers.values().filter_map(|server| {
382 server
383 .0
384 .id
385 .get()
386 .copied()
387 .map(|id| (id, server.0.name.clone()))
388 })
389 })
390 })
391 .collect();
392 Self {
393 old_contents,
394 new_tree,
395 all_server_ids,
396 rebased_server_ids: BTreeSet::new(),
397 }
398 }
399
400 pub(crate) fn get<'a>(
401 &'a mut self,
402 path: ProjectPath,
403 query: AdapterQuery<'_>,
404 delegate: Arc<dyn ManifestDelegate>,
405 cx: &mut App,
406 ) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
407 let settings_location = SettingsLocation {
408 worktree_id: path.worktree_id,
409 path: &path.path,
410 };
411 let adapters = match query {
412 AdapterQuery::Language(language_name) => {
413 self.new_tree
414 .adapters_for_language(settings_location, language_name, cx)
415 }
416 AdapterQuery::Adapter(language_server_name) => {
417 IndexMap::from_iter(self.new_tree.adapter_for_name(language_server_name).map(
418 |adapter| {
419 (
420 adapter.name(),
421 (LspSettings::default(), BTreeSet::new(), adapter),
422 )
423 },
424 ))
425 }
426 };
427
428 self.new_tree
429 .get_with_adapters(path, adapters, delegate, cx)
430 .filter_map(|node| {
431 // Inspect result of the query and initialize it ourselves before
432 // handing it off to the caller.
433 let disposition = node.0.upgrade()?;
434
435 if disposition.id.get().is_some() {
436 return Some(node);
437 }
438 let Some((existing_node, _)) = self
439 .old_contents
440 .get(&disposition.path.worktree_id)
441 .and_then(|worktree_nodes| worktree_nodes.roots.get(&disposition.path.path))
442 .and_then(|roots| roots.get(&disposition.name))
443 .filter(|(old_node, _)| disposition.settings == old_node.settings)
444 else {
445 return Some(node);
446 };
447 if let Some(existing_id) = existing_node.id.get() {
448 self.rebased_server_ids.insert(*existing_id);
449 disposition.id.set(*existing_id).ok();
450 }
451
452 Some(node)
453 })
454 }
455
456 /// Returns IDs of servers that are no longer referenced (and can be shut down).
457 pub(crate) fn finish(self) -> BTreeMap<LanguageServerId, LanguageServerName> {
458 self.all_server_ids
459 .into_iter()
460 .filter(|(id, _)| !self.rebased_server_ids.contains(id))
461 .collect()
462 }
463
464 pub(crate) fn server_tree(&mut self) -> &mut LanguageServerTree {
465 &mut self.new_tree
466 }
467}