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    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, Debug)]
 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) const fn server_tree(&mut self) -> &mut LanguageServerTree {
459        &mut self.new_tree
460    }
461}