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::{HashMap, IndexMap};
 17use gpui::{App, AppContext as _, Entity, Subscription};
 18use language::{
 19    Attach, 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    attach_kind_cache: HashMap<LanguageServerName, Attach>,
 42    languages: Arc<LanguageRegistry>,
 43    _subscriptions: Subscription,
 44}
 45
 46/// A node in language server tree represents either:
 47/// - A language server that has already been initialized/updated for a given project
 48/// - A soon-to-be-initialized language server.
 49#[derive(Clone)]
 50pub struct LanguageServerTreeNode(Weak<InnerTreeNode>);
 51
 52/// Describes a request to launch a language server.
 53#[derive(Debug)]
 54pub(crate) struct LaunchDisposition<'a> {
 55    pub(crate) server_name: &'a LanguageServerName,
 56    pub(crate) attach: Attach,
 57    pub(crate) path: ProjectPath,
 58    pub(crate) settings: Arc<LspSettings>,
 59}
 60
 61impl<'a> From<&'a InnerTreeNode> for LaunchDisposition<'a> {
 62    fn from(value: &'a InnerTreeNode) -> Self {
 63        LaunchDisposition {
 64            server_name: &value.name,
 65            attach: value.attach,
 66            path: value.path.clone(),
 67            settings: value.settings.clone(),
 68        }
 69    }
 70}
 71impl LanguageServerTreeNode {
 72    /// Returns a language server ID for this node if there is one.
 73    /// Returns None if this node has not been initialized yet or it is no longer in the tree.
 74    pub(crate) fn server_id(&self) -> Option<LanguageServerId> {
 75        self.0.upgrade()?.id.get().copied()
 76    }
 77
 78    /// 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.
 79    /// May return None if the node no longer belongs to the server tree it was created in.
 80    pub(crate) fn server_id_or_init(
 81        &self,
 82        init: impl FnOnce(LaunchDisposition) -> LanguageServerId,
 83    ) -> Option<LanguageServerId> {
 84        let this = self.0.upgrade()?;
 85        Some(
 86            *this
 87                .id
 88                .get_or_init(|| init(LaunchDisposition::from(&*this))),
 89        )
 90    }
 91
 92    /// Returns a language server name as the language server adapter would return.
 93    pub fn name(&self) -> Option<LanguageServerName> {
 94        self.0.upgrade().map(|node| node.name.clone())
 95    }
 96}
 97
 98impl From<Weak<InnerTreeNode>> for LanguageServerTreeNode {
 99    fn from(weak: Weak<InnerTreeNode>) -> Self {
100        LanguageServerTreeNode(weak)
101    }
102}
103
104#[derive(Debug)]
105pub struct InnerTreeNode {
106    id: OnceLock<LanguageServerId>,
107    name: LanguageServerName,
108    attach: Attach,
109    path: ProjectPath,
110    settings: Arc<LspSettings>,
111}
112
113impl InnerTreeNode {
114    fn new(
115        name: LanguageServerName,
116        attach: Attach,
117        path: ProjectPath,
118        settings: impl Into<Arc<LspSettings>>,
119    ) -> Self {
120        InnerTreeNode {
121            id: Default::default(),
122            name,
123            attach,
124            path,
125            settings: settings.into(),
126        }
127    }
128}
129
130/// Determines how the list of adapters to query should be constructed.
131pub(crate) enum AdapterQuery<'a> {
132    /// Search for roots of all adapters associated with a given language name.
133    Language(&'a LanguageName),
134    /// Search for roots of adapter with a given name.
135    Adapter(&'a LanguageServerName),
136}
137
138impl LanguageServerTree {
139    pub(crate) fn new(
140        manifest_tree: Entity<ManifestTree>,
141        languages: Arc<LanguageRegistry>,
142        cx: &mut App,
143    ) -> Entity<Self> {
144        cx.new(|cx| Self {
145            _subscriptions: cx.subscribe(&manifest_tree, |_: &mut Self, _, event, _| {
146                if event == &ManifestTreeEvent::Cleared {}
147            }),
148            manifest_tree,
149            instances: Default::default(),
150            attach_kind_cache: Default::default(),
151            languages,
152        })
153    }
154
155    /// Get all language server root points for a given path and language; the language servers might already be initialized at a given path.
156    pub(crate) fn get<'a>(
157        &'a mut self,
158        path: ProjectPath,
159        query: AdapterQuery<'_>,
160        delegate: Arc<dyn ManifestDelegate>,
161        cx: &mut App,
162    ) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
163        let settings_location = SettingsLocation {
164            worktree_id: path.worktree_id,
165            path: &path.path,
166        };
167        let adapters = match query {
168            AdapterQuery::Language(language_name) => {
169                self.adapters_for_language(settings_location, language_name, cx)
170            }
171            AdapterQuery::Adapter(language_server_name) => {
172                IndexMap::from_iter(self.adapter_for_name(language_server_name).map(|adapter| {
173                    (
174                        adapter.name(),
175                        (LspSettings::default(), BTreeSet::new(), adapter),
176                    )
177                }))
178            }
179        };
180        self.get_with_adapters(path, adapters, delegate, cx)
181    }
182
183    fn get_with_adapters<'a>(
184        &'a mut self,
185        path: ProjectPath,
186        adapters: IndexMap<
187            LanguageServerName,
188            (LspSettings, BTreeSet<LanguageName>, Arc<CachedLspAdapter>),
189        >,
190        delegate: Arc<dyn ManifestDelegate>,
191        cx: &mut App,
192    ) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
193        let worktree_id = path.worktree_id;
194
195        let mut manifest_to_adapters = BTreeMap::default();
196        for (_, _, adapter) in adapters.values() {
197            if let Some(manifest_name) = adapter.manifest_name() {
198                manifest_to_adapters
199                    .entry(manifest_name)
200                    .or_insert_with(Vec::default)
201                    .push(adapter.clone());
202            }
203        }
204
205        let roots = self.manifest_tree.update(cx, |this, cx| {
206            this.root_for_path(
207                path,
208                &mut manifest_to_adapters.keys().cloned(),
209                delegate,
210                cx,
211            )
212        });
213        let root_path = std::cell::LazyCell::new(move || ProjectPath {
214            worktree_id,
215            path: Arc::from("".as_ref()),
216        });
217        adapters
218            .into_iter()
219            .map(move |(_, (settings, new_languages, adapter))| {
220                // 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.
221                let root_path = adapter
222                    .manifest_name()
223                    .and_then(|name| roots.get(&name))
224                    .cloned()
225                    .unwrap_or_else(|| root_path.clone());
226                let attach = adapter.attach_kind();
227
228                let inner_node = self
229                    .instances
230                    .entry(root_path.worktree_id)
231                    .or_default()
232                    .roots
233                    .entry(root_path.path.clone())
234                    .or_default()
235                    .entry(adapter.name());
236                let (node, languages) = inner_node.or_insert_with(|| {
237                    (
238                        Arc::new(InnerTreeNode::new(
239                            adapter.name(),
240                            attach,
241                            root_path.clone(),
242                            settings.clone(),
243                        )),
244                        Default::default(),
245                    )
246                });
247                languages.extend(new_languages.iter().cloned());
248                Arc::downgrade(&node).into()
249            })
250    }
251
252    fn adapter_for_name(&self, name: &LanguageServerName) -> Option<Arc<CachedLspAdapter>> {
253        self.languages.adapter_for_name(name)
254    }
255
256    fn adapters_for_language(
257        &self,
258        settings_location: SettingsLocation,
259        language_name: &LanguageName,
260        cx: &App,
261    ) -> IndexMap<LanguageServerName, (LspSettings, BTreeSet<LanguageName>, Arc<CachedLspAdapter>)>
262    {
263        let settings = AllLanguageSettings::get(Some(settings_location), cx).language(
264            Some(settings_location),
265            Some(language_name),
266            cx,
267        );
268        if !settings.enable_language_server {
269            return Default::default();
270        }
271        let available_lsp_adapters = self.languages.lsp_adapters(&language_name);
272        let available_language_servers = available_lsp_adapters
273            .iter()
274            .map(|lsp_adapter| lsp_adapter.name.clone())
275            .collect::<Vec<_>>();
276
277        let desired_language_servers =
278            settings.customized_language_servers(&available_language_servers);
279        let adapters_with_settings = desired_language_servers
280            .into_iter()
281            .filter_map(|desired_adapter| {
282                let adapter = if let Some(adapter) = available_lsp_adapters
283                    .iter()
284                    .find(|adapter| adapter.name == desired_adapter)
285                {
286                    Some(adapter.clone())
287                } else if let Some(adapter) =
288                    self.languages.load_available_lsp_adapter(&desired_adapter)
289                {
290                    self.languages
291                        .register_lsp_adapter(language_name.clone(), adapter.adapter.clone());
292                    Some(adapter)
293                } else {
294                    None
295                }?;
296                let adapter_settings = crate::lsp_store::language_server_settings_for(
297                    settings_location,
298                    &adapter.name,
299                    cx,
300                )
301                .cloned()
302                .unwrap_or_default();
303                Some((
304                    adapter.name(),
305                    (
306                        adapter_settings,
307                        BTreeSet::from_iter([language_name.clone()]),
308                        adapter,
309                    ),
310                ))
311            })
312            .collect::<IndexMap<_, _>>();
313        // After starting all the language servers, reorder them to reflect the desired order
314        // based on the settings.
315        //
316        // This is done, in part, to ensure that language servers loaded at different points
317        // (e.g., native vs extension) still end up in the right order at the end, rather than
318        // it being based on which language server happened to be loaded in first.
319        self.languages.reorder_language_servers(
320            &language_name,
321            adapters_with_settings
322                .values()
323                .map(|(_, _, adapter)| adapter.clone())
324                .collect(),
325        );
326
327        adapters_with_settings
328    }
329
330    // Rebasing a tree:
331    // - Clears it out
332    // - Provides you with the indirect access to the old tree while you're reinitializing a new one (by querying it).
333    pub(crate) fn rebase(&mut self) -> ServerTreeRebase<'_> {
334        ServerTreeRebase::new(self)
335    }
336
337    /// Remove nodes with a given ID from the tree.
338    pub(crate) fn remove_nodes(&mut self, ids: &BTreeSet<LanguageServerId>) {
339        for (_, servers) in &mut self.instances {
340            for (_, nodes) in &mut servers.roots {
341                nodes.retain(|_, (node, _)| node.id.get().map_or(true, |id| !ids.contains(&id)));
342            }
343        }
344    }
345
346    pub(crate) fn register_reused(
347        &mut self,
348        worktree_id: WorktreeId,
349        language_name: LanguageName,
350        reused: LanguageServerTreeNode,
351    ) {
352        let Some(node) = reused.0.upgrade() else {
353            return;
354        };
355
356        self.instances
357            .entry(worktree_id)
358            .or_default()
359            .roots
360            .entry(Arc::from(Path::new("")))
361            .or_default()
362            .entry(node.name.clone())
363            .or_insert_with(|| (node, BTreeSet::new()))
364            .1
365            .insert(language_name);
366    }
367}
368
369pub(crate) struct ServerTreeRebase<'a> {
370    old_contents: BTreeMap<WorktreeId, ServersForWorktree>,
371    new_tree: &'a mut LanguageServerTree,
372    /// All server IDs seen in the old tree.
373    all_server_ids: BTreeMap<LanguageServerId, LanguageServerName>,
374    /// Server IDs we've preserved for a new iteration of the tree. `all_server_ids - rebased_server_ids` is the
375    /// set of server IDs that can be shut down.
376    rebased_server_ids: BTreeSet<LanguageServerId>,
377}
378
379impl<'tree> ServerTreeRebase<'tree> {
380    fn new(new_tree: &'tree mut LanguageServerTree) -> Self {
381        let old_contents = std::mem::take(&mut new_tree.instances);
382        new_tree.attach_kind_cache.clear();
383        let all_server_ids = old_contents
384            .values()
385            .flat_map(|nodes| {
386                nodes.roots.values().flat_map(|servers| {
387                    servers.values().filter_map(|server| {
388                        server
389                            .0
390                            .id
391                            .get()
392                            .copied()
393                            .map(|id| (id, server.0.name.clone()))
394                    })
395                })
396            })
397            .collect();
398        Self {
399            old_contents,
400            new_tree,
401            all_server_ids,
402            rebased_server_ids: BTreeSet::new(),
403        }
404    }
405
406    pub(crate) fn get<'a>(
407        &'a mut self,
408        path: ProjectPath,
409        query: AdapterQuery<'_>,
410        delegate: Arc<dyn ManifestDelegate>,
411        cx: &mut App,
412    ) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
413        let settings_location = SettingsLocation {
414            worktree_id: path.worktree_id,
415            path: &path.path,
416        };
417        let adapters = match query {
418            AdapterQuery::Language(language_name) => {
419                self.new_tree
420                    .adapters_for_language(settings_location, language_name, cx)
421            }
422            AdapterQuery::Adapter(language_server_name) => {
423                IndexMap::from_iter(self.new_tree.adapter_for_name(language_server_name).map(
424                    |adapter| {
425                        (
426                            adapter.name(),
427                            (LspSettings::default(), BTreeSet::new(), adapter),
428                        )
429                    },
430                ))
431            }
432        };
433
434        self.new_tree
435            .get_with_adapters(path, adapters, delegate, cx)
436            .filter_map(|node| {
437                // Inspect result of the query and initialize it ourselves before
438                // handing it off to the caller.
439                let disposition = node.0.upgrade()?;
440
441                if disposition.id.get().is_some() {
442                    return Some(node);
443                }
444                let Some((existing_node, _)) = self
445                    .old_contents
446                    .get(&disposition.path.worktree_id)
447                    .and_then(|worktree_nodes| worktree_nodes.roots.get(&disposition.path.path))
448                    .and_then(|roots| roots.get(&disposition.name))
449                    .filter(|(old_node, _)| {
450                        disposition.attach == old_node.attach
451                            && disposition.settings == old_node.settings
452                    })
453                else {
454                    return Some(node);
455                };
456                if let Some(existing_id) = existing_node.id.get() {
457                    self.rebased_server_ids.insert(*existing_id);
458                    disposition.id.set(*existing_id).ok();
459                }
460
461                Some(node)
462            })
463    }
464
465    /// Returns IDs of servers that are no longer referenced (and can be shut down).
466    pub(crate) fn finish(self) -> BTreeMap<LanguageServerId, LanguageServerName> {
467        self.all_server_ids
468            .into_iter()
469            .filter(|(id, _)| !self.rebased_server_ids.contains(id))
470            .collect()
471    }
472
473    pub(crate) fn server_tree(&mut self) -> &mut LanguageServerTree {
474        &mut self.new_tree
475    }
476}