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, LspAdapterDelegate,
 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)]
 31struct ServersForWorktree {
 32    roots: BTreeMap<
 33        Arc<Path>,
 34        BTreeMap<LanguageServerName, (Arc<InnerTreeNode>, BTreeSet<LanguageName>)>,
 35    >,
 36}
 37
 38pub struct LanguageServerTree {
 39    manifest_tree: Entity<ManifestTree>,
 40    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(crate) 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)]
 99struct 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 LspAdapterDelegate>,
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 LspAdapterDelegate>,
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    pub fn server_id_for_name(&self, name: &LanguageServerName) -> Option<LanguageServerId> {
251        self.instances
252            .values()
253            .flat_map(|instance| instance.roots.values())
254            .flatten()
255            .find_map(|(server_name, (data, _))| {
256                if server_name == name {
257                    data.id.get().copied()
258                } else {
259                    None
260                }
261            })
262    }
263
264    fn adapters_for_language(
265        &self,
266        settings_location: SettingsLocation,
267        language_name: &LanguageName,
268        cx: &App,
269    ) -> IndexMap<LanguageServerName, (LspSettings, BTreeSet<LanguageName>, Arc<CachedLspAdapter>)>
270    {
271        let settings = AllLanguageSettings::get(Some(settings_location), cx).language(
272            Some(settings_location),
273            Some(language_name),
274            cx,
275        );
276        if !settings.enable_language_server {
277            return Default::default();
278        }
279        let available_lsp_adapters = self.languages.lsp_adapters(&language_name);
280        let available_language_servers = available_lsp_adapters
281            .iter()
282            .map(|lsp_adapter| lsp_adapter.name.clone())
283            .collect::<Vec<_>>();
284
285        let desired_language_servers =
286            settings.customized_language_servers(&available_language_servers);
287        let adapters_with_settings = desired_language_servers
288            .into_iter()
289            .filter_map(|desired_adapter| {
290                let adapter = if let Some(adapter) = available_lsp_adapters
291                    .iter()
292                    .find(|adapter| adapter.name == desired_adapter)
293                {
294                    Some(adapter.clone())
295                } else if let Some(adapter) =
296                    self.languages.load_available_lsp_adapter(&desired_adapter)
297                {
298                    self.languages
299                        .register_lsp_adapter(language_name.clone(), adapter.adapter.clone());
300                    Some(adapter)
301                } else {
302                    None
303                }?;
304                let adapter_settings = crate::lsp_store::language_server_settings_for(
305                    settings_location,
306                    &adapter.name,
307                    cx,
308                )
309                .cloned()
310                .unwrap_or_default();
311                Some((
312                    adapter.name(),
313                    (
314                        adapter_settings,
315                        BTreeSet::from_iter([language_name.clone()]),
316                        adapter,
317                    ),
318                ))
319            })
320            .collect::<IndexMap<_, _>>();
321        // After starting all the language servers, reorder them to reflect the desired order
322        // based on the settings.
323        //
324        // This is done, in part, to ensure that language servers loaded at different points
325        // (e.g., native vs extension) still end up in the right order at the end, rather than
326        // it being based on which language server happened to be loaded in first.
327        self.languages.reorder_language_servers(
328            &language_name,
329            adapters_with_settings
330                .values()
331                .map(|(_, _, adapter)| adapter.clone())
332                .collect(),
333        );
334
335        adapters_with_settings
336    }
337
338    // Rebasing a tree:
339    // - Clears it out
340    // - Provides you with the indirect access to the old tree while you're reinitializing a new one (by querying it).
341    pub(crate) fn rebase(&mut self) -> ServerTreeRebase<'_> {
342        ServerTreeRebase::new(self)
343    }
344
345    /// Remove nodes with a given ID from the tree.
346    pub(crate) fn remove_nodes(&mut self, ids: &BTreeSet<LanguageServerId>) {
347        for (_, servers) in &mut self.instances {
348            for (_, nodes) in &mut servers.roots {
349                nodes.retain(|_, (node, _)| node.id.get().map_or(true, |id| !ids.contains(&id)));
350            }
351        }
352    }
353}
354
355pub(crate) struct ServerTreeRebase<'a> {
356    old_contents: BTreeMap<WorktreeId, ServersForWorktree>,
357    new_tree: &'a mut LanguageServerTree,
358    /// All server IDs seen in the old tree.
359    all_server_ids: BTreeMap<LanguageServerId, LanguageServerName>,
360    /// Server IDs we've preserved for a new iteration of the tree. `all_server_ids - rebased_server_ids` is the
361    /// set of server IDs that can be shut down.
362    rebased_server_ids: BTreeSet<LanguageServerId>,
363}
364
365impl<'tree> ServerTreeRebase<'tree> {
366    fn new(new_tree: &'tree mut LanguageServerTree) -> Self {
367        let old_contents = std::mem::take(&mut new_tree.instances);
368        new_tree.attach_kind_cache.clear();
369        let all_server_ids = old_contents
370            .values()
371            .flat_map(|nodes| {
372                nodes.roots.values().flat_map(|servers| {
373                    servers.values().filter_map(|server| {
374                        server
375                            .0
376                            .id
377                            .get()
378                            .copied()
379                            .map(|id| (id, server.0.name.clone()))
380                    })
381                })
382            })
383            .collect();
384        Self {
385            old_contents,
386            new_tree,
387            all_server_ids,
388            rebased_server_ids: BTreeSet::new(),
389        }
390    }
391
392    pub(crate) fn get<'a>(
393        &'a mut self,
394        path: ProjectPath,
395        query: AdapterQuery<'_>,
396        delegate: Arc<dyn LspAdapterDelegate>,
397        cx: &mut App,
398    ) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
399        let settings_location = SettingsLocation {
400            worktree_id: path.worktree_id,
401            path: &path.path,
402        };
403        let adapters = match query {
404            AdapterQuery::Language(language_name) => {
405                self.new_tree
406                    .adapters_for_language(settings_location, language_name, cx)
407            }
408            AdapterQuery::Adapter(language_server_name) => {
409                IndexMap::from_iter(self.new_tree.adapter_for_name(language_server_name).map(
410                    |adapter| {
411                        (
412                            adapter.name(),
413                            (LspSettings::default(), BTreeSet::new(), adapter),
414                        )
415                    },
416                ))
417            }
418        };
419
420        self.new_tree
421            .get_with_adapters(path, adapters, delegate, cx)
422            .filter_map(|node| {
423                // Inspect result of the query and initialize it ourselves before
424                // handing it off to the caller.
425                let disposition = node.0.upgrade()?;
426
427                if disposition.id.get().is_some() {
428                    return Some(node);
429                }
430                let Some((existing_node, _)) = self
431                    .old_contents
432                    .get(&disposition.path.worktree_id)
433                    .and_then(|worktree_nodes| worktree_nodes.roots.get(&disposition.path.path))
434                    .and_then(|roots| roots.get(&disposition.name))
435                    .filter(|(old_node, _)| {
436                        disposition.attach == old_node.attach
437                            && disposition.settings == old_node.settings
438                    })
439                else {
440                    return Some(node);
441                };
442                if let Some(existing_id) = existing_node.id.get() {
443                    self.rebased_server_ids.insert(*existing_id);
444                    disposition.id.set(*existing_id).ok();
445                }
446
447                Some(node)
448            })
449    }
450
451    /// Returns IDs of servers that are no longer referenced (and can be shut down).
452    pub(crate) fn finish(self) -> BTreeMap<LanguageServerId, LanguageServerName> {
453        self.all_server_ids
454            .into_iter()
455            .filter(|(id, _)| !self.rebased_server_ids.contains(id))
456            .collect()
457    }
458}