language_registry.rs

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