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