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