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    /// 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.
 78    /// May return None if the node no longer belongs to the server tree it was created in.
 79    pub(crate) fn server_id_or_init(
 80        &self,
 81        init: impl FnOnce(LaunchDisposition) -> LanguageServerId,
 82    ) -> Option<LanguageServerId> {
 83        let this = self.0.upgrade()?;
 84        Some(
 85            *this
 86                .id
 87                .get_or_init(|| init(LaunchDisposition::from(&*this))),
 88        )
 89    }
 90}
 91
 92impl From<Weak<InnerTreeNode>> for LanguageServerTreeNode {
 93    fn from(weak: Weak<InnerTreeNode>) -> Self {
 94        LanguageServerTreeNode(weak)
 95    }
 96}
 97
 98#[derive(Debug)]
 99pub struct InnerTreeNode {
100    id: OnceLock<LanguageServerId>,
101    name: LanguageServerName,
102    attach: Attach,
103    path: ProjectPath,
104    settings: Arc<LspSettings>,
105}
106
107impl InnerTreeNode {
108    fn new(
109        name: LanguageServerName,
110        attach: Attach,
111        path: ProjectPath,
112        settings: impl Into<Arc<LspSettings>>,
113    ) -> Self {
114        InnerTreeNode {
115            id: Default::default(),
116            name,
117            attach,
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    Language(&'a LanguageName),
128    /// Search for roots of adapter with a given name.
129    Adapter(&'a LanguageServerName),
130}
131
132impl LanguageServerTree {
133    pub(crate) fn new(
134        manifest_tree: Entity<ManifestTree>,
135        languages: Arc<LanguageRegistry>,
136        cx: &mut App,
137    ) -> Entity<Self> {
138        cx.new(|cx| Self {
139            _subscriptions: cx.subscribe(&manifest_tree, |_: &mut Self, _, event, _| {
140                if event == &ManifestTreeEvent::Cleared {}
141            }),
142            manifest_tree,
143            instances: Default::default(),
144            attach_kind_cache: Default::default(),
145            languages,
146        })
147    }
148
149    /// Get all language server root points for a given path and language; the language servers might already be initialized at a given path.
150    pub(crate) fn get<'a>(
151        &'a mut self,
152        path: ProjectPath,
153        query: AdapterQuery<'_>,
154        delegate: Arc<dyn ManifestDelegate>,
155        cx: &mut App,
156    ) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
157        let settings_location = SettingsLocation {
158            worktree_id: path.worktree_id,
159            path: &path.path,
160        };
161        let adapters = match query {
162            AdapterQuery::Language(language_name) => {
163                self.adapters_for_language(settings_location, language_name, cx)
164            }
165            AdapterQuery::Adapter(language_server_name) => {
166                IndexMap::from_iter(self.adapter_for_name(language_server_name).map(|adapter| {
167                    (
168                        adapter.name(),
169                        (LspSettings::default(), BTreeSet::new(), adapter),
170                    )
171                }))
172            }
173        };
174        self.get_with_adapters(path, adapters, delegate, cx)
175    }
176
177    fn get_with_adapters<'a>(
178        &'a mut self,
179        path: ProjectPath,
180        adapters: IndexMap<
181            LanguageServerName,
182            (LspSettings, BTreeSet<LanguageName>, Arc<CachedLspAdapter>),
183        >,
184        delegate: Arc<dyn ManifestDelegate>,
185        cx: &mut App,
186    ) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
187        let worktree_id = path.worktree_id;
188
189        let mut manifest_to_adapters = BTreeMap::default();
190        for (_, _, adapter) in adapters.values() {
191            if let Some(manifest_name) = adapter.manifest_name() {
192                manifest_to_adapters
193                    .entry(manifest_name)
194                    .or_insert_with(Vec::default)
195                    .push(adapter.clone());
196            }
197        }
198
199        let roots = self.manifest_tree.update(cx, |this, cx| {
200            this.root_for_path(
201                path,
202                &mut manifest_to_adapters.keys().cloned(),
203                delegate,
204                cx,
205            )
206        });
207        let root_path = std::cell::LazyCell::new(move || ProjectPath {
208            worktree_id,
209            path: Arc::from("".as_ref()),
210        });
211        adapters
212            .into_iter()
213            .map(move |(_, (settings, new_languages, adapter))| {
214                // 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.
215                let root_path = adapter
216                    .manifest_name()
217                    .and_then(|name| roots.get(&name))
218                    .cloned()
219                    .unwrap_or_else(|| root_path.clone());
220                let attach = adapter.attach_kind();
221
222                let inner_node = self
223                    .instances
224                    .entry(root_path.worktree_id)
225                    .or_default()
226                    .roots
227                    .entry(root_path.path.clone())
228                    .or_default()
229                    .entry(adapter.name());
230                let (node, languages) = inner_node.or_insert_with(|| {
231                    (
232                        Arc::new(InnerTreeNode::new(
233                            adapter.name(),
234                            attach,
235                            root_path.clone(),
236                            settings.clone(),
237                        )),
238                        Default::default(),
239                    )
240                });
241                languages.extend(new_languages.iter().cloned());
242                Arc::downgrade(&node).into()
243            })
244    }
245
246    fn adapter_for_name(&self, name: &LanguageServerName) -> Option<Arc<CachedLspAdapter>> {
247        self.languages.adapter_for_name(name)
248    }
249
250    fn adapters_for_language(
251        &self,
252        settings_location: SettingsLocation,
253        language_name: &LanguageName,
254        cx: &App,
255    ) -> IndexMap<LanguageServerName, (LspSettings, BTreeSet<LanguageName>, Arc<CachedLspAdapter>)>
256    {
257        let settings = AllLanguageSettings::get(Some(settings_location), cx).language(
258            Some(settings_location),
259            Some(language_name),
260            cx,
261        );
262        if !settings.enable_language_server {
263            return Default::default();
264        }
265        let available_lsp_adapters = self.languages.lsp_adapters(&language_name);
266        let available_language_servers = available_lsp_adapters
267            .iter()
268            .map(|lsp_adapter| lsp_adapter.name.clone())
269            .collect::<Vec<_>>();
270
271        let desired_language_servers =
272            settings.customized_language_servers(&available_language_servers);
273        let adapters_with_settings = desired_language_servers
274            .into_iter()
275            .filter_map(|desired_adapter| {
276                let adapter = if let Some(adapter) = available_lsp_adapters
277                    .iter()
278                    .find(|adapter| adapter.name == desired_adapter)
279                {
280                    Some(adapter.clone())
281                } else if let Some(adapter) =
282                    self.languages.load_available_lsp_adapter(&desired_adapter)
283                {
284                    self.languages
285                        .register_lsp_adapter(language_name.clone(), adapter.adapter.clone());
286                    Some(adapter)
287                } else {
288                    None
289                }?;
290                let adapter_settings = crate::lsp_store::language_server_settings_for(
291                    settings_location,
292                    &adapter.name,
293                    cx,
294                )
295                .cloned()
296                .unwrap_or_default();
297                Some((
298                    adapter.name(),
299                    (
300                        adapter_settings,
301                        BTreeSet::from_iter([language_name.clone()]),
302                        adapter,
303                    ),
304                ))
305            })
306            .collect::<IndexMap<_, _>>();
307        // After starting all the language servers, reorder them to reflect the desired order
308        // based on the settings.
309        //
310        // This is done, in part, to ensure that language servers loaded at different points
311        // (e.g., native vs extension) still end up in the right order at the end, rather than
312        // it being based on which language server happened to be loaded in first.
313        self.languages.reorder_language_servers(
314            &language_name,
315            adapters_with_settings
316                .values()
317                .map(|(_, _, adapter)| adapter.clone())
318                .collect(),
319        );
320
321        adapters_with_settings
322    }
323
324    // Rebasing a tree:
325    // - Clears it out
326    // - Provides you with the indirect access to the old tree while you're reinitializing a new one (by querying it).
327    pub(crate) fn rebase(&mut self) -> ServerTreeRebase<'_> {
328        ServerTreeRebase::new(self)
329    }
330
331    /// Remove nodes with a given ID from the tree.
332    pub(crate) fn remove_nodes(&mut self, ids: &BTreeSet<LanguageServerId>) {
333        for (_, servers) in &mut self.instances {
334            for (_, nodes) in &mut servers.roots {
335                nodes.retain(|_, (node, _)| node.id.get().map_or(true, |id| !ids.contains(&id)));
336            }
337        }
338    }
339
340    pub(crate) fn register_reused(
341        &mut self,
342        worktree_id: WorktreeId,
343        language_name: LanguageName,
344        reused: LanguageServerTreeNode,
345    ) {
346        let Some(node) = reused.0.upgrade() else {
347            return;
348        };
349
350        self.instances
351            .entry(worktree_id)
352            .or_default()
353            .roots
354            .entry(Arc::from(Path::new("")))
355            .or_default()
356            .entry(node.name.clone())
357            .or_insert_with(|| (node, BTreeSet::new()))
358            .1
359            .insert(language_name);
360    }
361}
362
363pub(crate) struct ServerTreeRebase<'a> {
364    old_contents: BTreeMap<WorktreeId, ServersForWorktree>,
365    new_tree: &'a mut LanguageServerTree,
366    /// All server IDs seen in the old tree.
367    all_server_ids: BTreeMap<LanguageServerId, LanguageServerName>,
368    /// Server IDs we've preserved for a new iteration of the tree. `all_server_ids - rebased_server_ids` is the
369    /// set of server IDs that can be shut down.
370    rebased_server_ids: BTreeSet<LanguageServerId>,
371}
372
373impl<'tree> ServerTreeRebase<'tree> {
374    fn new(new_tree: &'tree mut LanguageServerTree) -> Self {
375        let old_contents = std::mem::take(&mut new_tree.instances);
376        new_tree.attach_kind_cache.clear();
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, _)| {
444                        disposition.attach == old_node.attach
445                            && disposition.settings == old_node.settings
446                    })
447                else {
448                    return Some(node);
449                };
450                if let Some(existing_id) = existing_node.id.get() {
451                    self.rebased_server_ids.insert(*existing_id);
452                    disposition.id.set(*existing_id).ok();
453                }
454
455                Some(node)
456            })
457    }
458
459    /// Returns IDs of servers that are no longer referenced (and can be shut down).
460    pub(crate) fn finish(self) -> BTreeMap<LanguageServerId, LanguageServerName> {
461        self.all_server_ids
462            .into_iter()
463            .filter(|(id, _)| !self.rebased_server_ids.contains(id))
464            .collect()
465    }
466
467    pub(crate) fn server_tree(&mut self) -> &mut LanguageServerTree {
468        &mut self.new_tree
469    }
470}