language_registry.rs

  1use crate::{
  2    CachedLspAdapter, Language, LanguageConfig, LanguageMatcher, LanguageServerName, LspAdapter,
  3    LspAdapterDelegate, PARSER, PLAIN_TEXT,
  4};
  5use anyhow::{anyhow, Context as _, Result};
  6use collections::{hash_map, HashMap};
  7use futures::{
  8    channel::{mpsc, oneshot},
  9    future::Shared,
 10    FutureExt as _, TryFutureExt as _,
 11};
 12use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task};
 13use lsp::{LanguageServerBinary, LanguageServerId};
 14use parking_lot::{Mutex, RwLock};
 15use postage::watch;
 16use std::{
 17    borrow::Cow,
 18    ffi::OsStr,
 19    ops::Not,
 20    path::{Path, PathBuf},
 21    sync::Arc,
 22};
 23use sum_tree::Bias;
 24use text::{Point, Rope};
 25use theme::Theme;
 26use unicase::UniCase;
 27use util::{paths::PathExt, post_inc, ResultExt, TryFutureExt as _, UnwrapFuture};
 28
 29pub struct LanguageRegistry {
 30    state: RwLock<LanguageRegistryState>,
 31    language_server_download_dir: Option<Arc<Path>>,
 32    login_shell_env_loaded: Shared<Task<()>>,
 33    #[allow(clippy::type_complexity)]
 34    lsp_binary_paths: Mutex<
 35        HashMap<LanguageServerName, Shared<Task<Result<LanguageServerBinary, Arc<anyhow::Error>>>>>,
 36    >,
 37    executor: Option<BackgroundExecutor>,
 38    lsp_binary_status_tx: LspBinaryStatusSender,
 39}
 40
 41struct LanguageRegistryState {
 42    next_language_server_id: usize,
 43    languages: Vec<Arc<Language>>,
 44    available_languages: Vec<AvailableLanguage>,
 45    grammars: HashMap<Arc<str>, AvailableGrammar>,
 46    next_available_language_id: AvailableLanguageId,
 47    loading_languages: HashMap<AvailableLanguageId, Vec<oneshot::Sender<Result<Arc<Language>>>>>,
 48    subscription: (watch::Sender<()>, watch::Receiver<()>),
 49    theme: Option<Arc<Theme>>,
 50    version: usize,
 51    reload_count: usize,
 52}
 53
 54#[derive(Clone)]
 55pub enum LanguageServerBinaryStatus {
 56    CheckingForUpdate,
 57    Downloading,
 58    Downloaded,
 59    Cached,
 60    Failed { error: String },
 61}
 62
 63pub struct PendingLanguageServer {
 64    pub server_id: LanguageServerId,
 65    pub task: Task<Result<lsp::LanguageServer>>,
 66    pub container_dir: Option<Arc<Path>>,
 67}
 68
 69#[derive(Clone)]
 70struct AvailableLanguage {
 71    id: AvailableLanguageId,
 72    name: Arc<str>,
 73    grammar: Option<Arc<str>>,
 74    matcher: LanguageMatcher,
 75    load: Arc<dyn Fn() -> Result<(LanguageConfig, LanguageQueries)> + 'static + Send + Sync>,
 76    lsp_adapters: Vec<Arc<dyn LspAdapter>>,
 77    loaded: bool,
 78}
 79
 80type AvailableLanguageId = usize;
 81
 82enum AvailableGrammar {
 83    Native(tree_sitter::Language),
 84    Loaded(PathBuf, tree_sitter::Language),
 85    Loading(PathBuf, Vec<oneshot::Sender<Result<tree_sitter::Language>>>),
 86    Unloaded(PathBuf),
 87}
 88
 89pub const QUERY_FILENAME_PREFIXES: &[(
 90    &str,
 91    fn(&mut LanguageQueries) -> &mut Option<Cow<'static, str>>,
 92)] = &[
 93    ("highlights", |q| &mut q.highlights),
 94    ("brackets", |q| &mut q.brackets),
 95    ("outline", |q| &mut q.outline),
 96    ("indents", |q| &mut q.indents),
 97    ("embedding", |q| &mut q.embedding),
 98    ("injections", |q| &mut q.injections),
 99    ("overrides", |q| &mut q.overrides),
100    ("redactions", |q| &mut q.redactions),
101];
102
103/// Tree-sitter language queries for a given language.
104#[derive(Debug, Default)]
105pub struct LanguageQueries {
106    pub highlights: Option<Cow<'static, str>>,
107    pub brackets: Option<Cow<'static, str>>,
108    pub indents: Option<Cow<'static, str>>,
109    pub outline: Option<Cow<'static, str>>,
110    pub embedding: Option<Cow<'static, str>>,
111    pub injections: Option<Cow<'static, str>>,
112    pub overrides: Option<Cow<'static, str>>,
113    pub redactions: Option<Cow<'static, str>>,
114}
115
116#[derive(Clone, Default)]
117struct LspBinaryStatusSender {
118    txs: Arc<Mutex<Vec<mpsc::UnboundedSender<(Arc<Language>, LanguageServerBinaryStatus)>>>>,
119}
120
121impl LanguageRegistry {
122    pub fn new(login_shell_env_loaded: Task<()>) -> Self {
123        Self {
124            state: RwLock::new(LanguageRegistryState {
125                next_language_server_id: 0,
126                languages: vec![PLAIN_TEXT.clone()],
127                available_languages: Default::default(),
128                grammars: Default::default(),
129                next_available_language_id: 0,
130                loading_languages: Default::default(),
131                subscription: watch::channel(),
132                theme: Default::default(),
133                version: 0,
134                reload_count: 0,
135            }),
136            language_server_download_dir: None,
137            login_shell_env_loaded: login_shell_env_loaded.shared(),
138            lsp_binary_paths: Default::default(),
139            executor: None,
140            lsp_binary_status_tx: Default::default(),
141        }
142    }
143
144    #[cfg(any(test, feature = "test-support"))]
145    pub fn test() -> Self {
146        Self::new(Task::ready(()))
147    }
148
149    pub fn set_executor(&mut self, executor: BackgroundExecutor) {
150        self.executor = Some(executor);
151    }
152
153    /// Clears out all of the loaded languages and reload them from scratch.
154    pub fn reload(&self) {
155        self.state.write().reload();
156    }
157
158    /// Clears out the given languages and reload them from scratch.
159    pub fn reload_languages(&self, languages: &[Arc<str>], grammars: &[Arc<str>]) {
160        self.state.write().reload_languages(languages, grammars);
161    }
162
163    #[cfg(any(feature = "test-support", test))]
164    pub fn register_test_language(&self, config: LanguageConfig) {
165        self.register_language(
166            config.name.clone(),
167            config.grammar.clone(),
168            config.matcher.clone(),
169            vec![],
170            move || Ok((config.clone(), Default::default())),
171        )
172    }
173
174    /// Adds a language to the registry, which can be loaded if needed.
175    pub fn register_language(
176        &self,
177        name: Arc<str>,
178        grammar_name: Option<Arc<str>>,
179        matcher: LanguageMatcher,
180        lsp_adapters: Vec<Arc<dyn LspAdapter>>,
181        load: impl Fn() -> Result<(LanguageConfig, LanguageQueries)> + 'static + Send + Sync,
182    ) {
183        let load = Arc::new(load);
184        let state = &mut *self.state.write();
185
186        for existing_language in &mut state.available_languages {
187            if existing_language.name == name {
188                existing_language.grammar = grammar_name;
189                existing_language.matcher = matcher;
190                existing_language.lsp_adapters = lsp_adapters;
191                existing_language.load = load;
192                return;
193            }
194        }
195
196        state.available_languages.push(AvailableLanguage {
197            id: post_inc(&mut state.next_available_language_id),
198            name,
199            grammar: grammar_name,
200            matcher,
201            load,
202            lsp_adapters,
203            loaded: false,
204        });
205    }
206
207    /// Adds grammars to the registry. Language configurations reference a grammar by name. The
208    /// grammar controls how the source code is parsed.
209    pub fn register_native_grammars(
210        &self,
211        grammars: impl IntoIterator<Item = (impl Into<Arc<str>>, tree_sitter::Language)>,
212    ) {
213        self.state.write().grammars.extend(
214            grammars
215                .into_iter()
216                .map(|(name, grammar)| (name.into(), AvailableGrammar::Native(grammar))),
217        );
218    }
219
220    /// Adds paths to WASM grammar files, which can be loaded if needed.
221    pub fn register_wasm_grammars(
222        &self,
223        grammars: impl IntoIterator<Item = (impl Into<Arc<str>>, PathBuf)>,
224    ) {
225        self.state.write().grammars.extend(
226            grammars
227                .into_iter()
228                .map(|(name, path)| (name.into(), AvailableGrammar::Unloaded(path))),
229        );
230    }
231
232    pub fn language_names(&self) -> Vec<String> {
233        let state = self.state.read();
234        let mut result = state
235            .available_languages
236            .iter()
237            .filter_map(|l| l.loaded.not().then_some(l.name.to_string()))
238            .chain(state.languages.iter().map(|l| l.config.name.to_string()))
239            .collect::<Vec<_>>();
240        result.sort_unstable_by_key(|language_name| language_name.to_lowercase());
241        result
242    }
243
244    pub fn add(&self, language: Arc<Language>) {
245        self.state.write().add(language);
246    }
247
248    pub fn subscribe(&self) -> watch::Receiver<()> {
249        self.state.read().subscription.1.clone()
250    }
251
252    /// Returns the number of times that the registry has been changed,
253    /// by adding languages or reloading.
254    pub fn version(&self) -> usize {
255        self.state.read().version
256    }
257
258    /// Returns the number of times that the registry has been reloaded.
259    pub fn reload_count(&self) -> usize {
260        self.state.read().reload_count
261    }
262
263    pub fn set_theme(&self, theme: Arc<Theme>) {
264        let mut state = self.state.write();
265        state.theme = Some(theme.clone());
266        for language in &state.languages {
267            language.set_theme(theme.syntax());
268        }
269    }
270
271    pub fn set_language_server_download_dir(&mut self, path: impl Into<Arc<Path>>) {
272        self.language_server_download_dir = Some(path.into());
273    }
274
275    pub fn language_for_name(
276        self: &Arc<Self>,
277        name: &str,
278    ) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
279        let name = UniCase::new(name);
280        self.get_or_load_language(|language_name, _| UniCase::new(language_name) == name)
281    }
282
283    pub fn language_for_name_or_extension(
284        self: &Arc<Self>,
285        string: &str,
286    ) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
287        let string = UniCase::new(string);
288        self.get_or_load_language(|name, config| {
289            UniCase::new(name) == string
290                || config
291                    .path_suffixes
292                    .iter()
293                    .any(|suffix| UniCase::new(suffix) == string)
294        })
295    }
296
297    pub fn language_for_file(
298        self: &Arc<Self>,
299        path: impl AsRef<Path>,
300        content: Option<&Rope>,
301    ) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
302        let path = path.as_ref();
303        let filename = path.file_name().and_then(|name| name.to_str());
304        let extension = path.extension_or_hidden_file_name();
305        let path_suffixes = [extension, filename];
306        self.get_or_load_language(|_, config| {
307            let path_matches = config
308                .path_suffixes
309                .iter()
310                .any(|suffix| path_suffixes.contains(&Some(suffix.as_str())));
311            let content_matches = content.zip(config.first_line_pattern.as_ref()).map_or(
312                false,
313                |(content, pattern)| {
314                    let end = content.clip_point(Point::new(0, 256), Bias::Left);
315                    let end = content.point_to_offset(end);
316                    let text = content.chunks_in_range(0..end).collect::<String>();
317                    pattern.is_match(&text)
318                },
319            );
320            path_matches || content_matches
321        })
322    }
323
324    fn get_or_load_language(
325        self: &Arc<Self>,
326        callback: impl Fn(&str, &LanguageMatcher) -> bool,
327    ) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
328        let (tx, rx) = oneshot::channel();
329
330        let mut state = self.state.write();
331        if let Some(language) = state
332            .languages
333            .iter()
334            .find(|language| callback(language.config.name.as_ref(), &language.config.matcher))
335        {
336            let _ = tx.send(Ok(language.clone()));
337        } else if let Some(executor) = self.executor.clone() {
338            if let Some(language) = state
339                .available_languages
340                .iter()
341                .rfind(|l| !l.loaded && callback(&l.name, &l.matcher))
342                .cloned()
343            {
344                match state.loading_languages.entry(language.id) {
345                    hash_map::Entry::Occupied(mut entry) => entry.get_mut().push(tx),
346                    hash_map::Entry::Vacant(entry) => {
347                        let this = self.clone();
348                        executor
349                            .spawn(async move {
350                                let id = language.id;
351                                let name = language.name.clone();
352                                let language = async {
353                                    let (config, queries) = (language.load)()?;
354
355                                    let grammar = if let Some(grammar) = config.grammar.clone() {
356                                        Some(this.get_or_load_grammar(grammar).await?)
357                                    } else {
358                                        None
359                                    };
360
361                                    Language::new(config, grammar)
362                                        .with_lsp_adapters(language.lsp_adapters)
363                                        .await
364                                        .with_queries(queries)
365                                }
366                                .await;
367
368                                match language {
369                                    Ok(language) => {
370                                        let language = Arc::new(language);
371                                        let mut state = this.state.write();
372
373                                        state.add(language.clone());
374                                        state.mark_language_loaded(id);
375                                        if let Some(mut txs) = state.loading_languages.remove(&id) {
376                                            for tx in txs.drain(..) {
377                                                let _ = tx.send(Ok(language.clone()));
378                                            }
379                                        }
380                                    }
381                                    Err(e) => {
382                                        log::error!("failed to load language {name}:\n{:?}", e);
383                                        let mut state = this.state.write();
384                                        state.mark_language_loaded(id);
385                                        if let Some(mut txs) = state.loading_languages.remove(&id) {
386                                            for tx in txs.drain(..) {
387                                                let _ = tx.send(Err(anyhow!(
388                                                    "failed to load language {}: {}",
389                                                    name,
390                                                    e
391                                                )));
392                                            }
393                                        }
394                                    }
395                                };
396                            })
397                            .detach();
398                        entry.insert(vec![tx]);
399                    }
400                }
401            } else {
402                let _ = tx.send(Err(anyhow!("language not found")));
403            }
404        } else {
405            let _ = tx.send(Err(anyhow!("executor does not exist")));
406        }
407
408        rx.unwrap()
409    }
410
411    fn get_or_load_grammar(
412        self: &Arc<Self>,
413        name: Arc<str>,
414    ) -> UnwrapFuture<oneshot::Receiver<Result<tree_sitter::Language>>> {
415        let (tx, rx) = oneshot::channel();
416        let mut state = self.state.write();
417
418        if let Some(grammar) = state.grammars.get_mut(name.as_ref()) {
419            match grammar {
420                AvailableGrammar::Native(grammar) | AvailableGrammar::Loaded(_, grammar) => {
421                    tx.send(Ok(grammar.clone())).ok();
422                }
423                AvailableGrammar::Loading(_, txs) => {
424                    txs.push(tx);
425                }
426                AvailableGrammar::Unloaded(wasm_path) => {
427                    if let Some(executor) = &self.executor {
428                        let this = self.clone();
429                        executor
430                            .spawn({
431                                let wasm_path = wasm_path.clone();
432                                async move {
433                                    let wasm_bytes = std::fs::read(&wasm_path)?;
434                                    let grammar_name = wasm_path
435                                        .file_stem()
436                                        .and_then(OsStr::to_str)
437                                        .ok_or_else(|| anyhow!("invalid grammar filename"))?;
438                                    let grammar = PARSER.with(|parser| {
439                                        let mut parser = parser.borrow_mut();
440                                        let mut store = parser.take_wasm_store().unwrap();
441                                        let grammar =
442                                            store.load_language(&grammar_name, &wasm_bytes);
443                                        parser.set_wasm_store(store).unwrap();
444                                        grammar
445                                    })?;
446
447                                    if let Some(AvailableGrammar::Loading(_, txs)) =
448                                        this.state.write().grammars.insert(
449                                            name,
450                                            AvailableGrammar::Loaded(wasm_path, grammar.clone()),
451                                        )
452                                    {
453                                        for tx in txs {
454                                            tx.send(Ok(grammar.clone())).ok();
455                                        }
456                                    }
457
458                                    anyhow::Ok(())
459                                }
460                            })
461                            .detach();
462                        *grammar = AvailableGrammar::Loading(wasm_path.clone(), vec![tx]);
463                    }
464                }
465            }
466        } else {
467            tx.send(Err(anyhow!("no such grammar {}", name))).ok();
468        }
469
470        rx.unwrap()
471    }
472
473    pub fn to_vec(&self) -> Vec<Arc<Language>> {
474        self.state.read().languages.iter().cloned().collect()
475    }
476
477    pub fn create_pending_language_server(
478        self: &Arc<Self>,
479        stderr_capture: Arc<Mutex<Option<String>>>,
480        language: Arc<Language>,
481        adapter: Arc<CachedLspAdapter>,
482        root_path: Arc<Path>,
483        delegate: Arc<dyn LspAdapterDelegate>,
484        cx: &mut AppContext,
485    ) -> Option<PendingLanguageServer> {
486        let server_id = self.state.write().next_language_server_id();
487        log::info!(
488            "starting language server {:?}, path: {root_path:?}, id: {server_id}",
489            adapter.name.0
490        );
491
492        #[cfg(any(test, feature = "test-support"))]
493        if language.fake_adapter.is_some() {
494            let task = cx.spawn(|cx| async move {
495                let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap();
496                let (server, mut fake_server) = lsp::FakeLanguageServer::new(
497                    fake_adapter.name.to_string(),
498                    fake_adapter.capabilities.clone(),
499                    cx.clone(),
500                );
501
502                if let Some(initializer) = &fake_adapter.initializer {
503                    initializer(&mut fake_server);
504                }
505
506                let servers_tx = servers_tx.clone();
507                cx.background_executor()
508                    .spawn(async move {
509                        if fake_server
510                            .try_receive_notification::<lsp::notification::Initialized>()
511                            .await
512                            .is_some()
513                        {
514                            servers_tx.unbounded_send(fake_server).ok();
515                        }
516                    })
517                    .detach();
518
519                Ok(server)
520            });
521
522            return Some(PendingLanguageServer {
523                server_id,
524                task,
525                container_dir: None,
526            });
527        }
528
529        let download_dir = self
530            .language_server_download_dir
531            .clone()
532            .ok_or_else(|| anyhow!("language server download directory has not been assigned before starting server"))
533            .log_err()?;
534        let this = self.clone();
535        let language = language.clone();
536        let container_dir: Arc<Path> = Arc::from(download_dir.join(adapter.name.0.as_ref()));
537        let root_path = root_path.clone();
538        let adapter = adapter.clone();
539        let login_shell_env_loaded = self.login_shell_env_loaded.clone();
540        let lsp_binary_statuses = self.lsp_binary_status_tx.clone();
541
542        let task = {
543            let container_dir = container_dir.clone();
544            cx.spawn(move |mut cx| async move {
545                login_shell_env_loaded.await;
546
547                let entry = this
548                    .lsp_binary_paths
549                    .lock()
550                    .entry(adapter.name.clone())
551                    .or_insert_with(|| {
552                        let adapter = adapter.clone();
553                        let language = language.clone();
554                        let delegate = delegate.clone();
555                        cx.spawn(|cx| {
556                            get_binary(
557                                adapter,
558                                language,
559                                delegate,
560                                container_dir,
561                                lsp_binary_statuses,
562                                cx,
563                            )
564                            .map_err(Arc::new)
565                        })
566                        .shared()
567                    })
568                    .clone();
569
570                let binary = match entry.await {
571                    Ok(binary) => binary,
572                    Err(err) => anyhow::bail!("{err}"),
573                };
574
575                if let Some(task) = adapter.will_start_server(&delegate, &mut cx) {
576                    task.await?;
577                }
578
579                lsp::LanguageServer::new(
580                    stderr_capture,
581                    server_id,
582                    binary,
583                    &root_path,
584                    adapter.code_action_kinds(),
585                    cx,
586                )
587            })
588        };
589
590        Some(PendingLanguageServer {
591            server_id,
592            task,
593            container_dir: Some(container_dir),
594        })
595    }
596
597    pub fn language_server_binary_statuses(
598        &self,
599    ) -> mpsc::UnboundedReceiver<(Arc<Language>, LanguageServerBinaryStatus)> {
600        self.lsp_binary_status_tx.subscribe()
601    }
602
603    pub fn delete_server_container(
604        &self,
605        adapter: Arc<CachedLspAdapter>,
606        cx: &mut AppContext,
607    ) -> Task<()> {
608        log::info!("deleting server container");
609
610        let mut lock = self.lsp_binary_paths.lock();
611        lock.remove(&adapter.name);
612
613        let download_dir = self
614            .language_server_download_dir
615            .clone()
616            .expect("language server download directory has not been assigned before deleting server container");
617
618        cx.spawn(|_| async move {
619            let container_dir = download_dir.join(adapter.name.0.as_ref());
620            smol::fs::remove_dir_all(container_dir)
621                .await
622                .context("server container removal")
623                .log_err();
624        })
625    }
626
627    pub fn next_language_server_id(&self) -> LanguageServerId {
628        self.state.write().next_language_server_id()
629    }
630}
631
632#[cfg(any(test, feature = "test-support"))]
633impl Default for LanguageRegistry {
634    fn default() -> Self {
635        Self::test()
636    }
637}
638
639impl LanguageRegistryState {
640    fn next_language_server_id(&mut self) -> LanguageServerId {
641        LanguageServerId(post_inc(&mut self.next_language_server_id))
642    }
643
644    fn add(&mut self, language: Arc<Language>) {
645        if let Some(theme) = self.theme.as_ref() {
646            language.set_theme(theme.syntax());
647        }
648        self.languages.push(language);
649        self.version += 1;
650        *self.subscription.0.borrow_mut() = ();
651    }
652
653    fn reload(&mut self) {
654        self.languages.clear();
655        self.version += 1;
656        self.reload_count += 1;
657        for language in &mut self.available_languages {
658            language.loaded = false;
659        }
660        *self.subscription.0.borrow_mut() = ();
661    }
662
663    fn reload_languages(
664        &mut self,
665        languages_to_reload: &[Arc<str>],
666        grammars_to_reload: &[Arc<str>],
667    ) {
668        for (name, grammar) in self.grammars.iter_mut() {
669            if grammars_to_reload.contains(name) {
670                if let AvailableGrammar::Loaded(path, _) = grammar {
671                    *grammar = AvailableGrammar::Unloaded(path.clone());
672                }
673            }
674        }
675
676        self.languages.retain(|language| {
677            let should_reload = languages_to_reload.contains(&language.config.name)
678                || language
679                    .config
680                    .grammar
681                    .as_ref()
682                    .map_or(false, |grammar| grammars_to_reload.contains(&grammar));
683            !should_reload
684        });
685
686        for language in &mut self.available_languages {
687            if languages_to_reload.contains(&language.name)
688                || language
689                    .grammar
690                    .as_ref()
691                    .map_or(false, |grammar| grammars_to_reload.contains(grammar))
692            {
693                language.loaded = false;
694            }
695        }
696
697        self.version += 1;
698        self.reload_count += 1;
699        *self.subscription.0.borrow_mut() = ();
700    }
701
702    /// Mark the given language as having been loaded, so that the
703    /// language registry won't try to load it again.
704    fn mark_language_loaded(&mut self, id: AvailableLanguageId) {
705        for language in &mut self.available_languages {
706            if language.id == id {
707                language.loaded = true;
708                break;
709            }
710        }
711    }
712}
713
714impl LspBinaryStatusSender {
715    fn subscribe(&self) -> mpsc::UnboundedReceiver<(Arc<Language>, LanguageServerBinaryStatus)> {
716        let (tx, rx) = mpsc::unbounded();
717        self.txs.lock().push(tx);
718        rx
719    }
720
721    fn send(&self, language: Arc<Language>, status: LanguageServerBinaryStatus) {
722        let mut txs = self.txs.lock();
723        txs.retain(|tx| {
724            tx.unbounded_send((language.clone(), status.clone()))
725                .is_ok()
726        });
727    }
728}
729
730async fn get_binary(
731    adapter: Arc<CachedLspAdapter>,
732    language: Arc<Language>,
733    delegate: Arc<dyn LspAdapterDelegate>,
734    container_dir: Arc<Path>,
735    statuses: LspBinaryStatusSender,
736    mut cx: AsyncAppContext,
737) -> Result<LanguageServerBinary> {
738    if !container_dir.exists() {
739        smol::fs::create_dir_all(&container_dir)
740            .await
741            .context("failed to create container directory")?;
742    }
743
744    if let Some(task) = adapter.will_fetch_server(&delegate, &mut cx) {
745        task.await?;
746    }
747
748    let binary = fetch_latest_binary(
749        adapter.clone(),
750        language.clone(),
751        delegate.as_ref(),
752        &container_dir,
753        statuses.clone(),
754    )
755    .await;
756
757    if let Err(error) = binary.as_ref() {
758        if let Some(binary) = adapter
759            .cached_server_binary(container_dir.to_path_buf(), delegate.as_ref())
760            .await
761        {
762            statuses.send(language.clone(), LanguageServerBinaryStatus::Cached);
763            return Ok(binary);
764        } else {
765            statuses.send(
766                language.clone(),
767                LanguageServerBinaryStatus::Failed {
768                    error: format!("{:?}", error),
769                },
770            );
771        }
772    }
773
774    binary
775}
776
777async fn fetch_latest_binary(
778    adapter: Arc<CachedLspAdapter>,
779    language: Arc<Language>,
780    delegate: &dyn LspAdapterDelegate,
781    container_dir: &Path,
782    lsp_binary_statuses_tx: LspBinaryStatusSender,
783) -> Result<LanguageServerBinary> {
784    let container_dir: Arc<Path> = container_dir.into();
785    lsp_binary_statuses_tx.send(
786        language.clone(),
787        LanguageServerBinaryStatus::CheckingForUpdate,
788    );
789
790    let version_info = adapter.fetch_latest_server_version(delegate).await?;
791    lsp_binary_statuses_tx.send(language.clone(), LanguageServerBinaryStatus::Downloading);
792
793    let binary = adapter
794        .fetch_server_binary(version_info, container_dir.to_path_buf(), delegate)
795        .await?;
796    lsp_binary_statuses_tx.send(language.clone(), LanguageServerBinaryStatus::Downloaded);
797
798    Ok(binary)
799}