1use crate::{
2 CachedLspAdapter, File, Language, LanguageConfig, LanguageId, LanguageMatcher,
3 LanguageServerName, LspAdapter, ManifestName, PLAIN_TEXT, ToolchainLister,
4 language_settings::all_language_settings, task_context::ContextProvider, with_parser,
5};
6use anyhow::{Context as _, Result, anyhow};
7use collections::{FxHashMap, HashMap, HashSet, hash_map};
8use settings::{AllLanguageSettingsContent, LanguageSettingsContent};
9
10use futures::{
11 Future,
12 channel::{mpsc, oneshot},
13};
14use globset::GlobSet;
15use gpui::{App, BackgroundExecutor, SharedString};
16use lsp::LanguageServerId;
17use parking_lot::{Mutex, RwLock};
18use postage::watch;
19use schemars::JsonSchema;
20use serde::{Deserialize, Serialize};
21use smallvec::SmallVec;
22use std::{
23 borrow::{Borrow, Cow},
24 cell::LazyCell,
25 ffi::OsStr,
26 ops::Not,
27 path::{Path, PathBuf},
28 sync::Arc,
29};
30use sum_tree::Bias;
31use text::{Point, Rope};
32use theme::Theme;
33use unicase::UniCase;
34use util::{ResultExt, maybe, post_inc};
35
36#[derive(
37 Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, JsonSchema,
38)]
39pub struct LanguageName(pub SharedString);
40
41impl LanguageName {
42 pub fn new(s: &str) -> Self {
43 Self(SharedString::new(s))
44 }
45
46 pub fn new_static(s: &'static str) -> Self {
47 Self(SharedString::new_static(s))
48 }
49
50 pub fn from_proto(s: String) -> Self {
51 Self(SharedString::from(s))
52 }
53
54 pub fn to_proto(&self) -> String {
55 self.0.to_string()
56 }
57
58 pub fn lsp_id(&self) -> String {
59 match self.0.as_ref() {
60 "Plain Text" => "plaintext".to_string(),
61 language_name => language_name.to_lowercase(),
62 }
63 }
64}
65
66impl From<LanguageName> for SharedString {
67 fn from(value: LanguageName) -> Self {
68 value.0
69 }
70}
71
72impl From<SharedString> for LanguageName {
73 fn from(value: SharedString) -> Self {
74 LanguageName(value)
75 }
76}
77
78impl AsRef<str> for LanguageName {
79 fn as_ref(&self) -> &str {
80 self.0.as_ref()
81 }
82}
83
84impl Borrow<str> for LanguageName {
85 fn borrow(&self) -> &str {
86 self.0.as_ref()
87 }
88}
89
90impl PartialEq<str> for LanguageName {
91 fn eq(&self, other: &str) -> bool {
92 self.0.as_ref() == other
93 }
94}
95
96impl PartialEq<&str> for LanguageName {
97 fn eq(&self, other: &&str) -> bool {
98 self.0.as_ref() == *other
99 }
100}
101
102impl std::fmt::Display for LanguageName {
103 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
104 write!(f, "{}", self.0)
105 }
106}
107
108impl From<&'static str> for LanguageName {
109 fn from(str: &'static str) -> Self {
110 Self(SharedString::new_static(str))
111 }
112}
113
114impl From<LanguageName> for String {
115 fn from(value: LanguageName) -> Self {
116 let value: &str = &value.0;
117 Self::from(value)
118 }
119}
120
121pub struct LanguageRegistry {
122 state: RwLock<LanguageRegistryState>,
123 language_server_download_dir: Option<Arc<Path>>,
124 executor: BackgroundExecutor,
125 lsp_binary_status_tx: ServerStatusSender,
126}
127
128struct LanguageRegistryState {
129 next_language_server_id: usize,
130 languages: Vec<Arc<Language>>,
131 language_settings: AllLanguageSettingsContent,
132 available_languages: Vec<AvailableLanguage>,
133 grammars: HashMap<Arc<str>, AvailableGrammar>,
134 lsp_adapters: HashMap<LanguageName, Vec<Arc<CachedLspAdapter>>>,
135 all_lsp_adapters: HashMap<LanguageServerName, Arc<CachedLspAdapter>>,
136 available_lsp_adapters:
137 HashMap<LanguageServerName, Arc<dyn Fn() -> Arc<CachedLspAdapter> + 'static + Send + Sync>>,
138 loading_languages: HashMap<LanguageId, Vec<oneshot::Sender<Result<Arc<Language>>>>>,
139 subscription: (watch::Sender<()>, watch::Receiver<()>),
140 theme: Option<Arc<Theme>>,
141 version: usize,
142 reload_count: usize,
143
144 #[cfg(any(test, feature = "test-support"))]
145 fake_server_entries: HashMap<LanguageServerName, FakeLanguageServerEntry>,
146}
147
148#[cfg(any(test, feature = "test-support"))]
149pub struct FakeLanguageServerEntry {
150 pub capabilities: lsp::ServerCapabilities,
151 pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
152 pub tx: futures::channel::mpsc::UnboundedSender<lsp::FakeLanguageServer>,
153 pub _server: Option<lsp::FakeLanguageServer>,
154}
155
156#[derive(Clone, Debug, PartialEq, Eq)]
157pub enum LanguageServerStatusUpdate {
158 Binary(BinaryStatus),
159 Health(ServerHealth, Option<SharedString>),
160}
161
162#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone, Copy)]
163#[serde(rename_all = "camelCase")]
164pub enum ServerHealth {
165 Ok,
166 Warning,
167 Error,
168}
169
170#[derive(Clone, Debug, PartialEq, Eq)]
171pub enum BinaryStatus {
172 None,
173 CheckingForUpdate,
174 Downloading,
175 Starting,
176 Stopping,
177 Stopped,
178 Failed { error: String },
179}
180
181#[derive(Clone)]
182pub struct AvailableLanguage {
183 id: LanguageId,
184 name: LanguageName,
185 grammar: Option<Arc<str>>,
186 matcher: LanguageMatcher,
187 hidden: bool,
188 load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,
189 loaded: bool,
190 manifest_name: Option<ManifestName>,
191}
192
193impl AvailableLanguage {
194 pub fn name(&self) -> LanguageName {
195 self.name.clone()
196 }
197
198 pub fn matcher(&self) -> &LanguageMatcher {
199 &self.matcher
200 }
201
202 pub fn hidden(&self) -> bool {
203 self.hidden
204 }
205}
206
207#[derive(Copy, Clone, Default)]
208enum LanguageMatchPrecedence {
209 #[default]
210 Undetermined,
211 PathOrContent(usize),
212 UserConfigured(usize),
213}
214
215enum AvailableGrammar {
216 Native(tree_sitter::Language),
217 Loaded(#[allow(unused)] PathBuf, tree_sitter::Language),
218 Loading(
219 #[allow(unused)] PathBuf,
220 Vec<oneshot::Sender<Result<tree_sitter::Language, Arc<anyhow::Error>>>>,
221 ),
222 Unloaded(PathBuf),
223 LoadFailed(Arc<anyhow::Error>),
224}
225
226#[derive(Debug)]
227pub struct LanguageNotFound;
228
229impl std::fmt::Display for LanguageNotFound {
230 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231 write!(f, "language not found")
232 }
233}
234
235#[derive(Copy, Clone, PartialEq, Eq, strum::EnumIter)]
236#[strum(serialize_all = "snake_case")]
237pub enum LanguageQuery {
238 Highlights,
239 Brackets,
240 Outline,
241 Indents,
242 Injections,
243 Overrides,
244 Runnables,
245 Debugger,
246 Textobjects,
247 Imports,
248}
249
250impl LanguageQuery {
251 pub fn variants() -> impl Iterator<Item = Self> {
252 use strum::IntoEnumIterator;
253 Self::iter()
254 }
255
256 pub fn query_mut<'a>(
257 &self,
258 queries: &'a mut LanguageQueries,
259 ) -> &'a mut Option<Cow<'static, str>> {
260 match self {
261 LanguageQuery::Highlights => &mut queries.highlights,
262 LanguageQuery::Brackets => &mut queries.brackets,
263 LanguageQuery::Outline => &mut queries.outline,
264 LanguageQuery::Indents => &mut queries.indents,
265 LanguageQuery::Injections => &mut queries.injections,
266 LanguageQuery::Overrides => &mut queries.overrides,
267 LanguageQuery::Runnables => &mut queries.runnables,
268 LanguageQuery::Debugger => &mut queries.debugger,
269 LanguageQuery::Textobjects => &mut queries.text_objects,
270 LanguageQuery::Imports => &mut queries.imports,
271 }
272 }
273
274 pub fn query_path(&self, folder_path: &Path) -> PathBuf {
275 folder_path.join(self.file_name())
276 }
277
278 pub const fn file_name(&self) -> &'static str {
279 match self {
280 LanguageQuery::Highlights => "highlights.scm",
281 LanguageQuery::Brackets => "brackets.scm",
282 LanguageQuery::Outline => "outline.scm",
283 LanguageQuery::Indents => "indents.scm",
284 LanguageQuery::Injections => "injections.scm",
285 LanguageQuery::Overrides => "overrides.scm",
286 LanguageQuery::Runnables => "runnables.scm",
287 LanguageQuery::Debugger => "debugger.scm",
288 LanguageQuery::Textobjects => "textobjects.scm",
289 LanguageQuery::Imports => "imports.scm",
290 }
291 }
292}
293
294/// Tree-sitter language queries for a given language.
295#[derive(Debug, Default)]
296pub struct LanguageQueries {
297 pub highlights: Option<Cow<'static, str>>,
298 pub brackets: Option<Cow<'static, str>>,
299 pub indents: Option<Cow<'static, str>>,
300 pub outline: Option<Cow<'static, str>>,
301 pub injections: Option<Cow<'static, str>>,
302 pub overrides: Option<Cow<'static, str>>,
303 pub redactions: Option<Cow<'static, str>>,
304 pub runnables: Option<Cow<'static, str>>,
305 pub text_objects: Option<Cow<'static, str>>,
306 pub debugger: Option<Cow<'static, str>>,
307 pub imports: Option<Cow<'static, str>>,
308}
309
310#[derive(Clone, Default)]
311struct ServerStatusSender {
312 txs: Arc<Mutex<Vec<mpsc::UnboundedSender<(LanguageServerName, BinaryStatus)>>>>,
313}
314
315pub struct LoadedLanguage {
316 pub config: LanguageConfig,
317 pub queries: LanguageQueries,
318 pub context_provider: Option<Arc<dyn ContextProvider>>,
319 pub toolchain_provider: Option<Arc<dyn ToolchainLister>>,
320 pub manifest_name: Option<ManifestName>,
321}
322
323impl LanguageRegistry {
324 pub fn new(executor: BackgroundExecutor) -> Self {
325 let this = Self {
326 state: RwLock::new(LanguageRegistryState {
327 next_language_server_id: 0,
328 languages: Vec::new(),
329 available_languages: Vec::new(),
330 grammars: Default::default(),
331 language_settings: Default::default(),
332 loading_languages: Default::default(),
333 lsp_adapters: Default::default(),
334 all_lsp_adapters: Default::default(),
335 available_lsp_adapters: HashMap::default(),
336 subscription: watch::channel(),
337 theme: Default::default(),
338 version: 0,
339 reload_count: 0,
340
341 #[cfg(any(test, feature = "test-support"))]
342 fake_server_entries: Default::default(),
343 }),
344 language_server_download_dir: None,
345 lsp_binary_status_tx: Default::default(),
346 executor,
347 };
348 this.add(PLAIN_TEXT.clone());
349 this
350 }
351
352 #[cfg(any(test, feature = "test-support"))]
353 pub fn test(executor: BackgroundExecutor) -> Self {
354 let mut this = Self::new(executor);
355 this.language_server_download_dir = Some(Path::new("/the-download-dir").into());
356 this
357 }
358
359 /// Clears out all of the loaded languages and reload them from scratch.
360 pub fn reload(&self) {
361 self.state.write().reload();
362 }
363
364 /// Reorders the list of language servers for the given language.
365 ///
366 /// Uses the provided list of ordered [`CachedLspAdapters`] as the desired order.
367 ///
368 /// Any existing language servers not present in `ordered_lsp_adapters` will be
369 /// appended to the end.
370 pub fn reorder_language_servers(
371 &self,
372 language: &LanguageName,
373 ordered_lsp_adapters: Vec<Arc<CachedLspAdapter>>,
374 ) {
375 self.state
376 .write()
377 .reorder_language_servers(language, ordered_lsp_adapters);
378 }
379
380 /// Removes the specified languages and grammars from the registry.
381 pub fn remove_languages(
382 &self,
383 languages_to_remove: &[LanguageName],
384 grammars_to_remove: &[Arc<str>],
385 ) {
386 self.state
387 .write()
388 .remove_languages(languages_to_remove, grammars_to_remove)
389 }
390
391 pub fn remove_lsp_adapter(&self, language_name: &LanguageName, name: &LanguageServerName) {
392 let mut state = self.state.write();
393 if let Some(adapters) = state.lsp_adapters.get_mut(language_name) {
394 adapters.retain(|adapter| &adapter.name != name)
395 }
396 state.all_lsp_adapters.remove(name);
397 state.available_lsp_adapters.remove(name);
398
399 state.version += 1;
400 state.reload_count += 1;
401 *state.subscription.0.borrow_mut() = ();
402 }
403
404 #[cfg(any(feature = "test-support", test))]
405 pub fn register_test_language(&self, config: LanguageConfig) {
406 self.register_language(
407 config.name.clone(),
408 config.grammar.clone(),
409 config.matcher.clone(),
410 config.hidden,
411 None,
412 Arc::new(move || {
413 Ok(LoadedLanguage {
414 config: config.clone(),
415 queries: Default::default(),
416 toolchain_provider: None,
417 context_provider: None,
418 manifest_name: None,
419 })
420 }),
421 )
422 }
423
424 /// Registers an available language server adapter.
425 ///
426 /// The language server is registered under the language server name, but
427 /// not bound to a particular language.
428 ///
429 /// When a language wants to load this particular language server, it will
430 /// invoke the `load` function.
431 pub fn register_available_lsp_adapter(
432 &self,
433 name: LanguageServerName,
434 adapter: Arc<dyn LspAdapter>,
435 ) {
436 let mut state = self.state.write();
437
438 if adapter.is_extension()
439 && let Some(existing_adapter) = state.all_lsp_adapters.get(&name)
440 && !existing_adapter.adapter.is_extension()
441 {
442 log::warn!(
443 "not registering extension-provided language server {name:?}, since a builtin language server exists with that name",
444 );
445 return;
446 }
447
448 state.available_lsp_adapters.insert(
449 name,
450 Arc::new(move || CachedLspAdapter::new(adapter.clone())),
451 );
452 }
453
454 /// Loads the language server adapter for the language server with the given name.
455 pub fn load_available_lsp_adapter(
456 &self,
457 name: &LanguageServerName,
458 ) -> Option<Arc<CachedLspAdapter>> {
459 let state = self.state.read();
460 let load_lsp_adapter = state.available_lsp_adapters.get(name)?;
461
462 Some(load_lsp_adapter())
463 }
464
465 /// Checks if a language server adapter with the given name is available to be loaded.
466 pub fn is_lsp_adapter_available(&self, name: &LanguageServerName) -> bool {
467 let state = self.state.read();
468 state.available_lsp_adapters.contains_key(name)
469 }
470
471 /// Returns the names of all available LSP adapters (registered via `register_available_lsp_adapter`).
472 /// These are adapters that are not bound to a specific language but can be enabled via settings.
473 pub fn available_lsp_adapter_names(&self) -> Vec<LanguageServerName> {
474 self.state
475 .read()
476 .available_lsp_adapters
477 .keys()
478 .cloned()
479 .collect()
480 }
481
482 pub fn register_lsp_adapter(&self, language_name: LanguageName, adapter: Arc<dyn LspAdapter>) {
483 let mut state = self.state.write();
484
485 if adapter.is_extension()
486 && let Some(existing_adapter) = state.all_lsp_adapters.get(&adapter.name())
487 && !existing_adapter.adapter.is_extension()
488 {
489 log::warn!(
490 "not registering extension-provided language server {:?} for language {language_name:?}, since a builtin language server exists with that name",
491 adapter.name(),
492 );
493 return;
494 }
495
496 let cached = CachedLspAdapter::new(adapter);
497 state
498 .lsp_adapters
499 .entry(language_name)
500 .or_default()
501 .push(cached.clone());
502 state
503 .all_lsp_adapters
504 .insert(cached.name.clone(), cached.clone());
505 }
506
507 /// Register a fake language server and adapter
508 /// The returned channel receives a new instance of the language server every time it is started
509 #[cfg(any(feature = "test-support", test))]
510 pub fn register_fake_lsp(
511 &self,
512 language_name: impl Into<LanguageName>,
513 mut adapter: crate::FakeLspAdapter,
514 ) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {
515 let adapter_name = LanguageServerName(adapter.name.into());
516 let capabilities = adapter.capabilities.clone();
517 let initializer = adapter.initializer.take();
518 self.register_fake_lsp_adapter(language_name, adapter);
519 self.register_fake_lsp_server(adapter_name, capabilities, initializer)
520 }
521
522 /// Register a fake lsp adapter (without the language server)
523 #[cfg(any(feature = "test-support", test))]
524 pub fn register_fake_lsp_adapter(
525 &self,
526 language_name: impl Into<LanguageName>,
527 adapter: crate::FakeLspAdapter,
528 ) {
529 let language_name = language_name.into();
530 let mut state = self.state.write();
531 let cached_adapter = CachedLspAdapter::new(Arc::new(adapter));
532 state
533 .lsp_adapters
534 .entry(language_name)
535 .or_default()
536 .push(cached_adapter.clone());
537 state
538 .all_lsp_adapters
539 .insert(cached_adapter.name(), cached_adapter);
540 }
541
542 /// Register a fake language server (without the adapter)
543 /// The returned channel receives a new instance of the language server every time it is started
544 #[cfg(any(feature = "test-support", test))]
545 pub fn register_fake_lsp_server(
546 &self,
547 lsp_name: LanguageServerName,
548 capabilities: lsp::ServerCapabilities,
549 initializer: Option<Box<dyn Fn(&mut lsp::FakeLanguageServer) + Send + Sync>>,
550 ) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {
551 let (servers_tx, servers_rx) = futures::channel::mpsc::unbounded();
552 self.state.write().fake_server_entries.insert(
553 lsp_name,
554 FakeLanguageServerEntry {
555 tx: servers_tx,
556 capabilities,
557 initializer,
558 _server: None,
559 },
560 );
561 servers_rx
562 }
563
564 #[cfg(any(feature = "test-support", test))]
565 pub fn has_fake_lsp_server(&self, lsp_name: &LanguageServerName) -> bool {
566 self.state.read().fake_server_entries.contains_key(lsp_name)
567 }
568
569 /// Adds a language to the registry, which can be loaded if needed.
570 pub fn register_language(
571 &self,
572 name: LanguageName,
573 grammar_name: Option<Arc<str>>,
574 matcher: LanguageMatcher,
575 hidden: bool,
576 manifest_name: Option<ManifestName>,
577 load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,
578 ) {
579 let state = &mut *self.state.write();
580
581 for existing_language in &mut state.available_languages {
582 if existing_language.name == name {
583 existing_language.grammar = grammar_name;
584 existing_language.matcher = matcher;
585 existing_language.load = load;
586 existing_language.manifest_name = manifest_name;
587 return;
588 }
589 }
590
591 state.available_languages.push(AvailableLanguage {
592 id: LanguageId::new(),
593 name,
594 grammar: grammar_name,
595 matcher,
596 load,
597 hidden,
598 loaded: false,
599 manifest_name,
600 });
601 state.version += 1;
602 state.reload_count += 1;
603 *state.subscription.0.borrow_mut() = ();
604 }
605
606 /// Adds grammars to the registry. Language configurations reference a grammar by name. The
607 /// grammar controls how the source code is parsed.
608 pub fn register_native_grammars(
609 &self,
610 grammars: impl IntoIterator<Item = (impl Into<Arc<str>>, impl Into<tree_sitter::Language>)>,
611 ) {
612 self.state.write().grammars.extend(
613 grammars
614 .into_iter()
615 .map(|(name, grammar)| (name.into(), AvailableGrammar::Native(grammar.into()))),
616 );
617 }
618
619 /// Adds paths to WASM grammar files, which can be loaded if needed.
620 pub fn register_wasm_grammars(&self, grammars: Vec<(Arc<str>, PathBuf)>) {
621 if grammars.is_empty() {
622 return;
623 }
624
625 let mut state = self.state.write();
626 state.grammars.extend(
627 grammars
628 .into_iter()
629 .map(|(name, path)| (name, AvailableGrammar::Unloaded(path))),
630 );
631 state.version += 1;
632 state.reload_count += 1;
633 *state.subscription.0.borrow_mut() = ();
634 }
635
636 pub fn language_settings(&self) -> AllLanguageSettingsContent {
637 self.state.read().language_settings.clone()
638 }
639
640 pub fn language_names(&self) -> Vec<LanguageName> {
641 let state = self.state.read();
642 let mut result = state
643 .available_languages
644 .iter()
645 .filter_map(|l| l.loaded.not().then_some(l.name.clone()))
646 .chain(state.languages.iter().map(|l| l.config.name.clone()))
647 .collect::<Vec<_>>();
648 result.sort_unstable_by_key(|language_name| language_name.as_ref().to_lowercase());
649 result
650 }
651
652 pub fn grammar_names(&self) -> Vec<Arc<str>> {
653 let state = self.state.read();
654 let mut result = state.grammars.keys().cloned().collect::<Vec<_>>();
655 result.sort_unstable_by_key(|grammar_name| grammar_name.to_lowercase());
656 result
657 }
658
659 /// Add a pre-loaded language to the registry.
660 pub fn add(&self, language: Arc<Language>) {
661 let mut state = self.state.write();
662 state.available_languages.push(AvailableLanguage {
663 id: language.id,
664 name: language.name(),
665 grammar: language.config.grammar.clone(),
666 matcher: language.config.matcher.clone(),
667 hidden: language.config.hidden,
668 manifest_name: None,
669 load: Arc::new(|| Err(anyhow!("already loaded"))),
670 loaded: true,
671 });
672 state.add(language);
673 }
674
675 pub fn subscribe(&self) -> watch::Receiver<()> {
676 self.state.read().subscription.1.clone()
677 }
678
679 /// Returns the number of times that the registry has been changed,
680 /// by adding languages or reloading.
681 pub fn version(&self) -> usize {
682 self.state.read().version
683 }
684
685 /// Returns the number of times that the registry has been reloaded.
686 pub fn reload_count(&self) -> usize {
687 self.state.read().reload_count
688 }
689
690 pub fn set_theme(&self, theme: Arc<Theme>) {
691 let mut state = self.state.write();
692 state.theme = Some(theme.clone());
693 for language in &state.languages {
694 language.set_theme(theme.syntax());
695 }
696 }
697
698 pub fn set_language_server_download_dir(&mut self, path: impl Into<Arc<Path>>) {
699 self.language_server_download_dir = Some(path.into());
700 }
701
702 pub fn language_for_name(
703 self: &Arc<Self>,
704 name: &str,
705 ) -> impl Future<Output = Result<Arc<Language>>> + use<> {
706 let name = UniCase::new(name);
707 let rx = self.get_or_load_language(|language_name, _, current_best_match| {
708 match current_best_match {
709 LanguageMatchPrecedence::Undetermined if UniCase::new(&language_name.0) == name => {
710 Some(LanguageMatchPrecedence::PathOrContent(name.len()))
711 }
712 LanguageMatchPrecedence::Undetermined
713 | LanguageMatchPrecedence::UserConfigured(_)
714 | LanguageMatchPrecedence::PathOrContent(_) => None,
715 }
716 });
717 async move { rx.await? }
718 }
719
720 pub async fn language_for_id(self: &Arc<Self>, id: LanguageId) -> Result<Arc<Language>> {
721 let available_language = {
722 let state = self.state.read();
723
724 let Some(available_language) = state
725 .available_languages
726 .iter()
727 .find(|lang| lang.id == id)
728 .cloned()
729 else {
730 anyhow::bail!(LanguageNotFound);
731 };
732 available_language
733 };
734
735 self.load_language(&available_language).await?
736 }
737
738 pub fn language_name_for_extension(self: &Arc<Self>, extension: &str) -> Option<LanguageName> {
739 self.state.try_read().and_then(|state| {
740 state
741 .available_languages
742 .iter()
743 .find(|language| {
744 language
745 .matcher()
746 .path_suffixes
747 .iter()
748 .any(|suffix| *suffix == extension)
749 })
750 .map(|language| language.name.clone())
751 })
752 }
753
754 pub fn language_for_name_or_extension(
755 self: &Arc<Self>,
756 string: &str,
757 ) -> impl Future<Output = Result<Arc<Language>>> {
758 let string = UniCase::new(string);
759 let rx = self.get_or_load_language(|name, config, current_best_match| {
760 let name_matches = || {
761 UniCase::new(&name.0) == string
762 || config
763 .path_suffixes
764 .iter()
765 .any(|suffix| UniCase::new(suffix) == string)
766 };
767
768 match current_best_match {
769 LanguageMatchPrecedence::Undetermined => {
770 name_matches().then_some(LanguageMatchPrecedence::PathOrContent(string.len()))
771 }
772 LanguageMatchPrecedence::PathOrContent(len) => (string.len() > len
773 && name_matches())
774 .then_some(LanguageMatchPrecedence::PathOrContent(string.len())),
775 LanguageMatchPrecedence::UserConfigured(_) => None,
776 }
777 });
778 async move { rx.await? }
779 }
780
781 pub fn available_language_for_name(self: &Arc<Self>, name: &str) -> Option<AvailableLanguage> {
782 let state = self.state.read();
783 state
784 .available_languages
785 .iter()
786 .find(|l| l.name.0.as_ref() == name)
787 .cloned()
788 }
789
790 pub fn language_for_file(
791 self: &Arc<Self>,
792 file: &Arc<dyn File>,
793 content: Option<&Rope>,
794 cx: &App,
795 ) -> Option<AvailableLanguage> {
796 let user_file_types = all_language_settings(Some(file), cx);
797
798 self.language_for_file_internal(
799 &file.full_path(cx),
800 content,
801 Some(&user_file_types.file_types),
802 )
803 }
804
805 pub fn language_for_file_path(self: &Arc<Self>, path: &Path) -> Option<AvailableLanguage> {
806 self.language_for_file_internal(path, None, None)
807 }
808
809 #[ztracing::instrument(skip_all)]
810 pub fn load_language_for_file_path<'a>(
811 self: &Arc<Self>,
812 path: &'a Path,
813 ) -> impl Future<Output = Result<Arc<Language>>> + 'a {
814 let language = self.language_for_file_path(path);
815
816 let this = self.clone();
817 async move {
818 if let Some(language) = language {
819 this.load_language(&language).await?
820 } else {
821 Err(anyhow!(LanguageNotFound))
822 }
823 }
824 }
825
826 fn language_for_file_internal(
827 self: &Arc<Self>,
828 path: &Path,
829 content: Option<&Rope>,
830 user_file_types: Option<&FxHashMap<Arc<str>, (GlobSet, Vec<String>)>>,
831 ) -> Option<AvailableLanguage> {
832 let filename = path.file_name().and_then(|filename| filename.to_str());
833 // `Path.extension()` returns None for files with a leading '.'
834 // and no other extension which is not the desired behavior here,
835 // as we want `.zshrc` to result in extension being `Some("zshrc")`
836 let extension = filename.and_then(|filename| filename.split('.').next_back());
837 let path_suffixes = [extension, filename, path.to_str()]
838 .iter()
839 .filter_map(|suffix| suffix.map(|suffix| (suffix, globset::Candidate::new(suffix))))
840 .collect::<SmallVec<[_; 3]>>();
841 let content = LazyCell::new(|| {
842 content.map(|content| {
843 let end = content.clip_point(Point::new(0, 256), Bias::Left);
844 let end = content.point_to_offset(end);
845 content.chunks_in_range(0..end).collect::<String>()
846 })
847 });
848 self.find_matching_language(move |language_name, config, current_best_match| {
849 let path_matches_default_suffix = || {
850 let len =
851 config
852 .path_suffixes
853 .iter()
854 .fold(0, |acc: usize, path_suffix: &String| {
855 let ext = ".".to_string() + path_suffix;
856
857 let matched_suffix_len = path_suffixes
858 .iter()
859 .find(|(suffix, _)| suffix.ends_with(&ext) || suffix == path_suffix)
860 .map(|(suffix, _)| suffix.len());
861
862 match matched_suffix_len {
863 Some(len) => acc.max(len),
864 None => acc,
865 }
866 });
867 (len > 0).then_some(len)
868 };
869
870 let path_matches_custom_suffix = || {
871 user_file_types
872 .and_then(|types| types.get(language_name.as_ref()))
873 .map_or(None, |(custom_suffixes, _)| {
874 path_suffixes
875 .iter()
876 .find(|(_, candidate)| custom_suffixes.is_match_candidate(candidate))
877 .map(|(suffix, _)| suffix.len())
878 })
879 };
880
881 let content_matches = || {
882 config.first_line_pattern.as_ref().is_some_and(|pattern| {
883 content
884 .as_ref()
885 .is_some_and(|content| pattern.is_match(content))
886 })
887 };
888
889 // Only return a match for the given file if we have a better match than
890 // the current one.
891 match current_best_match {
892 LanguageMatchPrecedence::PathOrContent(current_len) => {
893 if let Some(len) = path_matches_custom_suffix() {
894 // >= because user config should win tie with system ext len
895 (len >= current_len).then_some(LanguageMatchPrecedence::UserConfigured(len))
896 } else if let Some(len) = path_matches_default_suffix() {
897 // >= because user config should win tie with system ext len
898 (len >= current_len).then_some(LanguageMatchPrecedence::PathOrContent(len))
899 } else {
900 None
901 }
902 }
903 LanguageMatchPrecedence::Undetermined => {
904 if let Some(len) = path_matches_custom_suffix() {
905 Some(LanguageMatchPrecedence::UserConfigured(len))
906 } else if let Some(len) = path_matches_default_suffix() {
907 Some(LanguageMatchPrecedence::PathOrContent(len))
908 } else if content_matches() {
909 Some(LanguageMatchPrecedence::PathOrContent(1))
910 } else {
911 None
912 }
913 }
914 LanguageMatchPrecedence::UserConfigured(_) => None,
915 }
916 })
917 }
918
919 fn find_matching_language(
920 self: &Arc<Self>,
921 callback: impl Fn(
922 &LanguageName,
923 &LanguageMatcher,
924 LanguageMatchPrecedence,
925 ) -> Option<LanguageMatchPrecedence>,
926 ) -> Option<AvailableLanguage> {
927 let state = self.state.read();
928 let available_language = state
929 .available_languages
930 .iter()
931 .rev()
932 .fold(None, |best_language_match, language| {
933 let current_match_type = best_language_match
934 .as_ref()
935 .map_or(LanguageMatchPrecedence::default(), |(_, score)| *score);
936 let language_score =
937 callback(&language.name, &language.matcher, current_match_type);
938
939 match (language_score, current_match_type) {
940 // no current best, so our candidate is better
941 (
942 Some(
943 LanguageMatchPrecedence::PathOrContent(_)
944 | LanguageMatchPrecedence::UserConfigured(_),
945 ),
946 LanguageMatchPrecedence::Undetermined,
947 ) => language_score.map(|new_score| (language.clone(), new_score)),
948
949 // our candidate is better only if the name is longer
950 (
951 Some(LanguageMatchPrecedence::PathOrContent(new_len)),
952 LanguageMatchPrecedence::PathOrContent(current_len),
953 )
954 | (
955 Some(LanguageMatchPrecedence::UserConfigured(new_len)),
956 LanguageMatchPrecedence::UserConfigured(current_len),
957 )
958 | (
959 Some(LanguageMatchPrecedence::PathOrContent(new_len)),
960 LanguageMatchPrecedence::UserConfigured(current_len),
961 ) => {
962 if new_len > current_len {
963 language_score.map(|new_score| (language.clone(), new_score))
964 } else {
965 best_language_match
966 }
967 }
968
969 // our candidate is better if the name is longer or equal to
970 (
971 Some(LanguageMatchPrecedence::UserConfigured(new_len)),
972 LanguageMatchPrecedence::PathOrContent(current_len),
973 ) => {
974 if new_len >= current_len {
975 language_score.map(|new_score| (language.clone(), new_score))
976 } else {
977 best_language_match
978 }
979 }
980
981 // no candidate, use current best
982 (None, _) | (Some(LanguageMatchPrecedence::Undetermined), _) => {
983 best_language_match
984 }
985 }
986 })
987 .map(|(available_language, _)| available_language);
988 drop(state);
989 available_language
990 }
991
992 #[ztracing::instrument(skip_all)]
993 pub fn load_language(
994 self: &Arc<Self>,
995 language: &AvailableLanguage,
996 ) -> oneshot::Receiver<Result<Arc<Language>>> {
997 let (tx, rx) = oneshot::channel();
998
999 let mut state = self.state.write();
1000
1001 // If the language is already loaded, resolve with it immediately.
1002 for loaded_language in state.languages.iter() {
1003 if loaded_language.id == language.id {
1004 tx.send(Ok(loaded_language.clone())).unwrap();
1005 return rx;
1006 }
1007 }
1008
1009 match state.loading_languages.entry(language.id) {
1010 // If the language is already being loaded, then add this
1011 // channel to a list that will be sent to when the load completes.
1012 hash_map::Entry::Occupied(mut entry) => entry.get_mut().push(tx),
1013
1014 // Otherwise, start loading the language.
1015 hash_map::Entry::Vacant(entry) => {
1016 let this = self.clone();
1017
1018 let id = language.id;
1019 let name = language.name.clone();
1020 let language_load = language.load.clone();
1021
1022 self.executor
1023 .spawn(async move {
1024 let language = async {
1025 let loaded_language = (language_load)()?;
1026 if let Some(grammar) = loaded_language.config.grammar.clone() {
1027 let grammar = Some(this.get_or_load_grammar(grammar).await?);
1028
1029 Language::new_with_id(id, loaded_language.config, grammar)
1030 .with_context_provider(loaded_language.context_provider)
1031 .with_toolchain_lister(loaded_language.toolchain_provider)
1032 .with_manifest(loaded_language.manifest_name)
1033 .with_queries(loaded_language.queries)
1034 } else {
1035 Ok(Language::new_with_id(id, loaded_language.config, None)
1036 .with_context_provider(loaded_language.context_provider)
1037 .with_manifest(loaded_language.manifest_name)
1038 .with_toolchain_lister(loaded_language.toolchain_provider))
1039 }
1040 }
1041 .await;
1042
1043 match language {
1044 Ok(language) => {
1045 let language = Arc::new(language);
1046 let mut state = this.state.write();
1047
1048 state.add(language.clone());
1049 state.mark_language_loaded(id);
1050 if let Some(mut txs) = state.loading_languages.remove(&id) {
1051 for tx in txs.drain(..) {
1052 let _ = tx.send(Ok(language.clone()));
1053 }
1054 }
1055 }
1056 Err(e) => {
1057 log::error!("failed to load language {name}:\n{e:?}");
1058 let mut state = this.state.write();
1059 state.mark_language_loaded(id);
1060 if let Some(mut txs) = state.loading_languages.remove(&id) {
1061 for tx in txs.drain(..) {
1062 let _ = tx.send(Err(anyhow!(
1063 "failed to load language {name}: {e}",
1064 )));
1065 }
1066 }
1067 }
1068 };
1069 })
1070 .detach();
1071
1072 entry.insert(vec![tx]);
1073 }
1074 }
1075
1076 drop(state);
1077 rx
1078 }
1079
1080 #[ztracing::instrument(skip_all)]
1081 fn get_or_load_language(
1082 self: &Arc<Self>,
1083 callback: impl Fn(
1084 &LanguageName,
1085 &LanguageMatcher,
1086 LanguageMatchPrecedence,
1087 ) -> Option<LanguageMatchPrecedence>,
1088 ) -> oneshot::Receiver<Result<Arc<Language>>> {
1089 let Some(language) = self.find_matching_language(callback) else {
1090 let (tx, rx) = oneshot::channel();
1091 let _ = tx.send(Err(anyhow!(LanguageNotFound)));
1092 return rx;
1093 };
1094
1095 self.load_language(&language)
1096 }
1097
1098 fn get_or_load_grammar(
1099 self: &Arc<Self>,
1100 name: Arc<str>,
1101 ) -> impl Future<Output = Result<tree_sitter::Language>> {
1102 let span = ztracing::debug_span!("get_or_load_grammar", name = &*name.clone());
1103 let _enter = span.enter();
1104 let (tx, rx) = oneshot::channel();
1105 let mut state = self.state.write();
1106
1107 if let Some(grammar) = state.grammars.get_mut(name.as_ref()) {
1108 match grammar {
1109 AvailableGrammar::LoadFailed(error) => {
1110 tx.send(Err(error.clone())).ok();
1111 }
1112 AvailableGrammar::Native(grammar) | AvailableGrammar::Loaded(_, grammar) => {
1113 tx.send(Ok(grammar.clone())).ok();
1114 }
1115 AvailableGrammar::Loading(_, txs) => {
1116 txs.push(tx);
1117 }
1118 AvailableGrammar::Unloaded(wasm_path) => {
1119 log::trace!("start loading grammar {name:?}");
1120 let this = self.clone();
1121 let wasm_path = wasm_path.clone();
1122 *grammar = AvailableGrammar::Loading(wasm_path.clone(), vec![tx]);
1123 self.executor
1124 .spawn(async move {
1125 let grammar_result = maybe!({
1126 let wasm_bytes = std::fs::read(&wasm_path)?;
1127 let grammar_name = wasm_path
1128 .file_stem()
1129 .and_then(OsStr::to_str)
1130 .context("invalid grammar filename")?;
1131 anyhow::Ok(with_parser(|parser| {
1132 let mut store = parser.take_wasm_store().unwrap();
1133 let grammar = store.load_language(grammar_name, &wasm_bytes);
1134 parser.set_wasm_store(store).unwrap();
1135 grammar
1136 })?)
1137 })
1138 .map_err(Arc::new);
1139
1140 let value = match &grammar_result {
1141 Ok(grammar) => AvailableGrammar::Loaded(wasm_path, grammar.clone()),
1142 Err(error) => AvailableGrammar::LoadFailed(error.clone()),
1143 };
1144
1145 log::trace!("finish loading grammar {name:?}");
1146 let old_value = this.state.write().grammars.insert(name, value);
1147 if let Some(AvailableGrammar::Loading(_, txs)) = old_value {
1148 for tx in txs {
1149 tx.send(grammar_result.clone()).ok();
1150 }
1151 }
1152 })
1153 .detach();
1154 }
1155 }
1156 } else {
1157 tx.send(Err(Arc::new(anyhow!("no such grammar {name}"))))
1158 .ok();
1159 }
1160
1161 async move { rx.await?.map_err(|e| anyhow!(e)) }
1162 }
1163
1164 pub fn to_vec(&self) -> Vec<Arc<Language>> {
1165 self.state.read().languages.to_vec()
1166 }
1167
1168 pub fn lsp_adapters(&self, language_name: &LanguageName) -> Vec<Arc<CachedLspAdapter>> {
1169 self.state
1170 .read()
1171 .lsp_adapters
1172 .get(language_name)
1173 .cloned()
1174 .unwrap_or_default()
1175 }
1176
1177 pub fn all_lsp_adapters(&self) -> Vec<Arc<CachedLspAdapter>> {
1178 self.state
1179 .read()
1180 .all_lsp_adapters
1181 .values()
1182 .cloned()
1183 .collect()
1184 }
1185
1186 pub fn adapter_for_name(&self, name: &LanguageServerName) -> Option<Arc<CachedLspAdapter>> {
1187 self.state.read().all_lsp_adapters.get(name).cloned()
1188 }
1189
1190 pub fn update_lsp_binary_status(&self, server_name: LanguageServerName, status: BinaryStatus) {
1191 self.lsp_binary_status_tx.send(server_name, status);
1192 }
1193
1194 pub fn next_language_server_id(&self) -> LanguageServerId {
1195 self.state.write().next_language_server_id()
1196 }
1197
1198 pub fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
1199 self.language_server_download_dir
1200 .as_ref()
1201 .map(|dir| Arc::from(dir.join(name.0.as_ref())))
1202 }
1203
1204 #[cfg(any(test, feature = "test-support"))]
1205 pub fn create_fake_language_server(
1206 &self,
1207 server_id: LanguageServerId,
1208 name: &LanguageServerName,
1209 binary: lsp::LanguageServerBinary,
1210 cx: &mut gpui::AsyncApp,
1211 ) -> Option<lsp::LanguageServer> {
1212 let mut state = self.state.write();
1213 let fake_entry = state.fake_server_entries.get_mut(name)?;
1214
1215 let (server, mut fake_server) = lsp::FakeLanguageServer::new(
1216 server_id,
1217 binary,
1218 name.0.to_string(),
1219 fake_entry.capabilities.clone(),
1220 cx,
1221 );
1222 fake_entry._server = Some(fake_server.clone());
1223
1224 if let Some(initializer) = &fake_entry.initializer {
1225 initializer(&mut fake_server);
1226 }
1227
1228 // Emit synchronously so tests can reliably observe server creation even if the LSP startup
1229 // task hasn't progressed to initialization yet.
1230 fake_entry.tx.unbounded_send(fake_server).ok();
1231
1232 Some(server)
1233 }
1234
1235 pub fn language_server_binary_statuses(
1236 &self,
1237 ) -> mpsc::UnboundedReceiver<(LanguageServerName, BinaryStatus)> {
1238 self.lsp_binary_status_tx.subscribe()
1239 }
1240
1241 pub async fn delete_server_container(&self, name: LanguageServerName) {
1242 log::info!("deleting server container");
1243 let Some(dir) = self.language_server_download_dir(&name) else {
1244 return;
1245 };
1246
1247 smol::fs::remove_dir_all(dir)
1248 .await
1249 .context("server container removal")
1250 .log_err();
1251 }
1252}
1253
1254impl LanguageRegistryState {
1255 fn next_language_server_id(&mut self) -> LanguageServerId {
1256 LanguageServerId(post_inc(&mut self.next_language_server_id))
1257 }
1258
1259 fn add(&mut self, language: Arc<Language>) {
1260 if let Some(theme) = self.theme.as_ref() {
1261 language.set_theme(theme.syntax());
1262 }
1263 self.language_settings.languages.0.insert(
1264 language.name().0.to_string(),
1265 LanguageSettingsContent {
1266 tab_size: language.config.tab_size,
1267 hard_tabs: language.config.hard_tabs,
1268 soft_wrap: language.config.soft_wrap,
1269 auto_indent_on_paste: language.config.auto_indent_on_paste,
1270 ..Default::default()
1271 },
1272 );
1273 self.languages.push(language);
1274 self.version += 1;
1275 *self.subscription.0.borrow_mut() = ();
1276 }
1277
1278 fn reload(&mut self) {
1279 self.languages.clear();
1280 self.version += 1;
1281 self.reload_count += 1;
1282 for language in &mut self.available_languages {
1283 language.loaded = false;
1284 }
1285 *self.subscription.0.borrow_mut() = ();
1286 }
1287
1288 /// Reorders the list of language servers for the given language.
1289 ///
1290 /// Uses the provided list of ordered [`CachedLspAdapters`] as the desired order.
1291 ///
1292 /// Any existing language servers not present in `ordered_lsp_adapters` will be
1293 /// appended to the end.
1294 fn reorder_language_servers(
1295 &mut self,
1296 language_name: &LanguageName,
1297 ordered_lsp_adapters: Vec<Arc<CachedLspAdapter>>,
1298 ) {
1299 let Some(lsp_adapters) = self.lsp_adapters.get_mut(language_name) else {
1300 return;
1301 };
1302
1303 let ordered_lsp_adapter_ids = ordered_lsp_adapters
1304 .iter()
1305 .map(|lsp_adapter| lsp_adapter.name.clone())
1306 .collect::<HashSet<_>>();
1307
1308 let mut new_lsp_adapters = ordered_lsp_adapters;
1309 for adapter in lsp_adapters.iter() {
1310 if !ordered_lsp_adapter_ids.contains(&adapter.name) {
1311 new_lsp_adapters.push(adapter.clone());
1312 }
1313 }
1314
1315 *lsp_adapters = new_lsp_adapters;
1316 }
1317
1318 fn remove_languages(
1319 &mut self,
1320 languages_to_remove: &[LanguageName],
1321 grammars_to_remove: &[Arc<str>],
1322 ) {
1323 if languages_to_remove.is_empty() && grammars_to_remove.is_empty() {
1324 return;
1325 }
1326
1327 self.languages
1328 .retain(|language| !languages_to_remove.contains(&language.name()));
1329 self.available_languages
1330 .retain(|language| !languages_to_remove.contains(&language.name));
1331 self.grammars
1332 .retain(|name, _| !grammars_to_remove.contains(name));
1333 self.version += 1;
1334 self.reload_count += 1;
1335 *self.subscription.0.borrow_mut() = ();
1336 }
1337
1338 /// Mark the given language as having been loaded, so that the
1339 /// language registry won't try to load it again.
1340 fn mark_language_loaded(&mut self, id: LanguageId) {
1341 for language in &mut self.available_languages {
1342 if language.id == id {
1343 language.loaded = true;
1344 break;
1345 }
1346 }
1347 }
1348}
1349
1350impl ServerStatusSender {
1351 fn subscribe(&self) -> mpsc::UnboundedReceiver<(LanguageServerName, BinaryStatus)> {
1352 let (tx, rx) = mpsc::unbounded();
1353 self.txs.lock().push(tx);
1354 rx
1355 }
1356
1357 fn send(&self, name: LanguageServerName, status: BinaryStatus) {
1358 let mut txs = self.txs.lock();
1359 txs.retain(|tx| tx.unbounded_send((name.clone(), status.clone())).is_ok());
1360 }
1361}