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