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.
  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}