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