server_tree.rs

  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}