use crate::available_languages::AvailableLanguage;use crate::{ CachedLspAdapter, File, Language, LanguageConfig, LanguageId, LanguageMatcher, LanguageServerName, LspAdapter, ManifestName, PLAIN_TEXT, ToolchainLister, available_languages::AvailableLanguages, language_settings::all_language_settings, task_context::ContextProvider, with_parser,};use anyhow::{Context as _, Result, anyhow};use collections::{FxHashMap, HashMap, HashSet, hash_map};pub use language_core::{ BinaryStatus, LanguageName, LanguageQueries, LanguageServerStatusUpdate, QUERY_FILENAME_PREFIXES, ServerHealth,};use settings::{AllLanguageSettingsContent, LanguageSettingsContent}; use futures::{ Future, channel::{mpsc, oneshot},};use globset::GlobSet;use gpui::{App, BackgroundExecutor};use lsp::LanguageServerId;use parking_lot::{Mutex, RwLock};use postage::watch; use std::{ ffi::OsStr, path::{Path, PathBuf}, sync::Arc,};use text::Rope;use theme::Theme; use util::{maybe, post_inc}; pub struct LanguageRegistry { state: RwLock<LanguageRegistryState>, language_server_download_dir: Option<Arc<Path>>, executor: BackgroundExecutor, lsp_binary_status_tx: ServerStatusSender,} struct LanguageRegistryState { next_language_server_id: usize, languages: Vec<Arc<Language>>, language_settings: AllLanguageSettingsContent, available_languages: AvailableLanguages, grammars: HashMap<Arc<str>, AvailableGrammar>, lsp_adapters: HashMap<LanguageName, Vec<Arc<CachedLspAdapter>>>, all_lsp_adapters: HashMap<LanguageServerName, Arc<CachedLspAdapter>>, available_lsp_adapters: HashMap<LanguageServerName, Arc<dyn Fn() -> Arc<CachedLspAdapter> + 'static + Send + Sync>>, loading_languages: HashMap<LanguageId, Vec<oneshot::Sender<Result<Arc<Language>>>>>, subscription: (watch::Sender<()>, watch::Receiver<()>), theme: Option<Arc<Theme>>, version: usize, reload_count: usize, #[cfg(any(test, feature = "test-support"))] fake_server_entries: HashMap<LanguageServerName, FakeLanguageServerEntry>,} #[cfg(any(test, feature = "test-support"))]pub struct FakeLanguageServerEntry { pub capabilities: lsp::ServerCapabilities, pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>, pub tx: futures::channel::mpsc::UnboundedSender<lsp::FakeLanguageServer>, pub _server: Option<lsp::FakeLanguageServer>,} enum AvailableGrammar { Native(tree_sitter::Language), Loaded(#[allow(unused)] PathBuf, tree_sitter::Language), Loading( #[allow(unused)] PathBuf, Vec<oneshot::Sender<Result<tree_sitter::Language, Arc<anyhow::Error>>>>, ), Unloaded(PathBuf), LoadFailed(Arc<anyhow::Error>),} #[derive(Debug)]pub struct LanguageNotFound; impl std::fmt::Display for LanguageNotFound { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "language not found") }} #[derive(Clone, Default)]struct ServerStatusSender { txs: Arc<Mutex<Vec<mpsc::UnboundedSender<(LanguageServerName, BinaryStatus)>>>>,} pub struct LoadedLanguage { pub config: LanguageConfig, pub queries: LanguageQueries, pub context_provider: Option<Arc<dyn ContextProvider>>, pub toolchain_provider: Option<Arc<dyn ToolchainLister>>, pub manifest_name: Option<ManifestName>,} impl LanguageRegistry { pub fn new(executor: BackgroundExecutor) -> Self { let this = Self { state: RwLock::new(LanguageRegistryState { next_language_server_id: 0, languages: Vec::new(), available_languages: AvailableLanguages::default(), grammars: Default::default(), language_settings: Default::default(), loading_languages: Default::default(), lsp_adapters: Default::default(), all_lsp_adapters: Default::default(), available_lsp_adapters: HashMap::default(), subscription: watch::channel(), theme: Default::default(), version: 0, reload_count: 0, #[cfg(any(test, feature = "test-support"))] fake_server_entries: Default::default(), }), language_server_download_dir: None, lsp_binary_status_tx: Default::default(), executor, }; this.add(PLAIN_TEXT.clone()); this } #[cfg(any(test, feature = "test-support"))] pub fn test(executor: BackgroundExecutor) -> Self { let mut this = Self::new(executor); this.language_server_download_dir = Some(Path::new("/the-download-dir").into()); this } /// Clears out all of the loaded languages and reload them from scratch. pub fn reload(&self) { self.state.write().reload(); } /// Reorders the list of language servers for the given language. /// /// Uses the provided list of ordered [`CachedLspAdapters`] as the desired order. /// /// Any existing language servers not present in `ordered_lsp_adapters` will be /// appended to the end. pub fn reorder_language_servers( &self, language: &LanguageName, ordered_lsp_adapters: Vec<Arc<CachedLspAdapter>>, ) { self.state .write() .reorder_language_servers(language, ordered_lsp_adapters); } /// Removes the specified languages and grammars from the registry. pub fn remove_languages( &self, languages_to_remove: &[LanguageName], grammars_to_remove: &[Arc<str>], ) { self.state .write() .remove_languages(languages_to_remove, grammars_to_remove) } pub fn remove_lsp_adapter(&self, language_name: &LanguageName, name: &LanguageServerName) { let mut state = self.state.write(); if let Some(adapters) = state.lsp_adapters.get_mut(language_name) { adapters.retain(|adapter| &adapter.name != name) } state.all_lsp_adapters.remove(name); state.available_lsp_adapters.remove(name); state.version += 1; state.reload_count += 1; *state.subscription.0.borrow_mut() = (); } #[cfg(any(feature = "test-support", test))] pub fn register_test_language(&self, config: LanguageConfig) { self.register_language( config.name.clone(), config.grammar.clone(), config.matcher.clone(), config.hidden, None, Arc::new(move || { Ok(LoadedLanguage { config: config.clone(), queries: Default::default(), toolchain_provider: None, context_provider: None, manifest_name: None, }) }), ) } /// Registers an available language server adapter. /// /// The language server is registered under the language server name, but /// not bound to a particular language. /// /// When a language wants to load this particular language server, it will /// invoke the `load` function. pub fn register_available_lsp_adapter( &self, name: LanguageServerName, adapter: Arc<dyn LspAdapter>, ) { let mut state = self.state.write(); if adapter.is_extension() && let Some(existing_adapter) = state.all_lsp_adapters.get(&name) && !existing_adapter.adapter.is_extension() { log::warn!( "not registering extension-provided language server {name:?}, since a builtin language server exists with that name", ); return; } state.available_lsp_adapters.insert( name, Arc::new(move || CachedLspAdapter::new(adapter.clone())), ); } /// Loads the language server adapter for the language server with the given name. pub fn load_available_lsp_adapter( &self, name: &LanguageServerName, ) -> Option<Arc<CachedLspAdapter>> { let state = self.state.read(); let load_lsp_adapter = state.available_lsp_adapters.get(name)?; Some(load_lsp_adapter()) } /// Checks if a language server adapter with the given name is available to be loaded. pub fn is_lsp_adapter_available(&self, name: &LanguageServerName) -> bool { let state = self.state.read(); state.available_lsp_adapters.contains_key(name) } /// Returns the names of all available LSP adapters (registered via `register_available_lsp_adapter`). /// These are adapters that are not bound to a specific language but can be enabled via settings. pub fn available_lsp_adapter_names(&self) -> Vec<LanguageServerName> { self.state .read() .available_lsp_adapters .keys() .cloned() .collect() } pub fn register_lsp_adapter(&self, language_name: LanguageName, adapter: Arc<dyn LspAdapter>) { let mut state = self.state.write(); if adapter.is_extension() && let Some(existing_adapter) = state.all_lsp_adapters.get(&adapter.name()) && !existing_adapter.adapter.is_extension() { log::warn!( "not registering extension-provided language server {:?} for language {language_name:?}, since a builtin language server exists with that name", adapter.name(), ); return; } let cached = CachedLspAdapter::new(adapter); state .lsp_adapters .entry(language_name) .or_default() .push(cached.clone()); state .all_lsp_adapters .insert(cached.name.clone(), cached.clone()); state.version += 1; *state.subscription.0.borrow_mut() = (); } /// Register a fake language server and adapter /// The returned channel receives a new instance of the language server every time it is started #[cfg(any(feature = "test-support", test))] pub fn register_fake_lsp( &self, language_name: impl Into<LanguageName>, mut adapter: crate::FakeLspAdapter, ) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> { let adapter_name = LanguageServerName(adapter.name.into()); let capabilities = adapter.capabilities.clone(); let initializer = adapter.initializer.take(); self.register_fake_lsp_adapter(language_name, adapter); self.register_fake_lsp_server(adapter_name, capabilities, initializer) } /// Register a fake lsp adapter (without the language server) #[cfg(any(feature = "test-support", test))] pub fn register_fake_lsp_adapter( &self, language_name: impl Into<LanguageName>, adapter: crate::FakeLspAdapter, ) { let language_name = language_name.into(); let mut state = self.state.write(); let cached_adapter = CachedLspAdapter::new(Arc::new(adapter)); state .lsp_adapters .entry(language_name) .or_default() .push(cached_adapter.clone()); state .all_lsp_adapters .insert(cached_adapter.name(), cached_adapter); state.version += 1; *state.subscription.0.borrow_mut() = (); } /// Register a fake language server (without the adapter) /// The returned channel receives a new instance of the language server every time it is started #[cfg(any(feature = "test-support", test))] pub fn register_fake_lsp_server( &self, lsp_name: LanguageServerName, capabilities: lsp::ServerCapabilities, initializer: Option<Box<dyn Fn(&mut lsp::FakeLanguageServer) + Send + Sync>>, ) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> { let (servers_tx, servers_rx) = futures::channel::mpsc::unbounded(); self.state.write().fake_server_entries.insert( lsp_name, FakeLanguageServerEntry { tx: servers_tx, capabilities, initializer, _server: None, }, ); servers_rx } #[cfg(any(feature = "test-support", test))] pub fn register_fake_available_lsp_adapter( &self, name: impl Into<LanguageServerName>, adapter: crate::FakeLspAdapter, ) { let name = name.into(); let adapter = Arc::new(adapter); let mut state = self.state.write(); state.available_lsp_adapters.insert( name, Arc::new(move || CachedLspAdapter::new(adapter.clone())), ); } #[cfg(any(feature = "test-support", test))] pub fn has_fake_lsp_server(&self, lsp_name: &LanguageServerName) -> bool { self.state.read().fake_server_entries.contains_key(lsp_name) } /// Adds a language to the registry, which can be loaded if needed. pub fn register_language( &self, name: LanguageName, grammar_name: Option<Arc<str>>, matcher: Arc<LanguageMatcher>, hidden: bool, manifest_name: Option<ManifestName>, load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>, ) { let state = &mut *self.state.write(); let was_added = state.available_languages.register( name, grammar_name, matcher, hidden, manifest_name, load, ); if !was_added { return; } state.version += 1; state.reload_count += 1; *state.subscription.0.borrow_mut() = (); } /// Adds grammars to the registry. Language configurations reference a grammar by name. The /// grammar controls how the source code is parsed. pub fn register_native_grammars( &self, grammars: impl IntoIterator<Item = (impl Into<Arc<str>>, impl Into<tree_sitter::Language>)>, ) { self.state.write().grammars.extend( grammars .into_iter() .map(|(name, grammar)| (name.into(), AvailableGrammar::Native(grammar.into()))), ); } /// Adds paths to WASM grammar files, which can be loaded if needed. pub fn register_wasm_grammars(&self, grammars: Vec<(Arc<str>, PathBuf)>) { if grammars.is_empty() { return; } let mut state = self.state.write(); state.grammars.extend( grammars .into_iter() .map(|(name, path)| (name, AvailableGrammar::Unloaded(path))), ); state.version += 1; state.reload_count += 1; *state.subscription.0.borrow_mut() = (); } pub fn language_settings(&self) -> AllLanguageSettingsContent { self.state.read().language_settings.clone() } pub fn language_names(&self) -> Vec<LanguageName> { let state = self.state.read(); let mut result = state.available_languages.unloaded_language_names(); result.extend( state .languages .iter() .map(|language| language.config.name.clone()), ); result.sort_unstable_by_key(|language_name| language_name.as_ref().to_lowercase()); result } pub fn grammar_names(&self) -> Vec<Arc<str>> { let state = self.state.read(); let mut result = state.grammars.keys().cloned().collect::<Vec<_>>(); result.sort_unstable_by_key(|grammar_name| grammar_name.to_lowercase()); result } /// Add a pre-loaded language to the registry. pub fn add(&self, language: Arc<Language>) { let mut state = self.state.write(); state.available_languages.add(AvailableLanguage { id: language.id, name: language.name(), grammar: language.config.grammar.clone(), matcher: language.config.matcher.clone(), hidden: language.config.hidden, manifest_name: None, load: Arc::new(|| Err(anyhow!("already loaded"))), loaded: true, }); state.add(language); } pub fn subscribe(&self) -> watch::Receiver<()> { self.state.read().subscription.1.clone() } /// Returns the number of times that the registry has been changed, /// by adding languages or reloading. pub fn version(&self) -> usize { self.state.read().version } /// Returns the number of times that the registry has been reloaded. pub fn reload_count(&self) -> usize { self.state.read().reload_count } pub fn set_theme(&self, theme: Arc<Theme>) { let mut state = self.state.write(); state.theme = Some(theme.clone()); for language in &state.languages { language.set_theme(theme.syntax()); } } pub fn set_language_server_download_dir(&mut self, path: impl Into<Arc<Path>>) { self.language_server_download_dir = Some(path.into()); } pub fn language_for_name( self: &Arc<Self>, name: &str, ) -> impl Future<Output = Result<Arc<Language>>> + use<> { let language_id = self.state.read().available_languages.find_by_name(name); let rx = self.get_or_load_language(language_id);Lines 1–500 of 956. Load more
use crate::available_languages::AvailableLanguage; use crate::{ CachedLspAdapter, File, Language, LanguageConfig, LanguageId, LanguageMatcher, LanguageServerName, LspAdapter, ManifestName, PLAIN_TEXT, ToolchainLister, available_languages::AvailableLanguages, language_settings::all_language_settings, task_context::ContextProvider, with_parser, }; use anyhow::{Context as _, Result, anyhow}; use collections::{FxHashMap, HashMap, HashSet, hash_map}; pub use language_core::{ BinaryStatus, LanguageName, LanguageQueries, LanguageServerStatusUpdate, QUERY_FILENAME_PREFIXES, ServerHealth, }; use settings::{AllLanguageSettingsContent, LanguageSettingsContent}; use futures::{ Future, channel::{mpsc, oneshot}, }; use globset::GlobSet; use gpui::{App, BackgroundExecutor}; use lsp::LanguageServerId; use parking_lot::{Mutex, RwLock}; use postage::watch; use std::{ ffi::OsStr, path::{Path, PathBuf}, sync::Arc, }; use text::Rope; use theme::Theme; use util::{maybe, post_inc}; pub struct LanguageRegistry { state: RwLock<LanguageRegistryState>, language_server_download_dir: Option<Arc<Path>>, executor: BackgroundExecutor, lsp_binary_status_tx: ServerStatusSender, } struct LanguageRegistryState { next_language_server_id: usize, languages: Vec<Arc<Language>>, language_settings: AllLanguageSettingsContent, available_languages: AvailableLanguages, grammars: HashMap<Arc<str>, AvailableGrammar>, lsp_adapters: HashMap<LanguageName, Vec<Arc<CachedLspAdapter>>>, all_lsp_adapters: HashMap<LanguageServerName, Arc<CachedLspAdapter>>, available_lsp_adapters: HashMap<LanguageServerName, Arc<dyn Fn() -> Arc<CachedLspAdapter> + 'static + Send + Sync>>, loading_languages: HashMap<LanguageId, Vec<oneshot::Sender<Result<Arc<Language>>>>>, subscription: (watch::Sender<()>, watch::Receiver<()>), theme: Option<Arc<Theme>>, version: usize, reload_count: usize, #[cfg(any(test, feature = "test-support"))] fake_server_entries: HashMap<LanguageServerName, FakeLanguageServerEntry>, } #[cfg(any(test, feature = "test-support"))] pub struct FakeLanguageServerEntry { pub capabilities: lsp::ServerCapabilities, pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>, pub tx: futures::channel::mpsc::UnboundedSender<lsp::FakeLanguageServer>, pub _server: Option<lsp::FakeLanguageServer>, } enum AvailableGrammar { Native(tree_sitter::Language), Loaded(#[allow(unused)] PathBuf, tree_sitter::Language), Loading( #[allow(unused)] PathBuf, Vec<oneshot::Sender<Result<tree_sitter::Language, Arc<anyhow::Error>>>>, ), Unloaded(PathBuf), LoadFailed(Arc<anyhow::Error>), } #[derive(Debug)] pub struct LanguageNotFound; impl std::fmt::Display for LanguageNotFound { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "language not found") } } #[derive(Clone, Default)] struct ServerStatusSender { txs: Arc<Mutex<Vec<mpsc::UnboundedSender<(LanguageServerName, BinaryStatus)>>>>, } pub struct LoadedLanguage { pub config: LanguageConfig, pub queries: LanguageQueries, pub context_provider: Option<Arc<dyn ContextProvider>>, pub toolchain_provider: Option<Arc<dyn ToolchainLister>>, pub manifest_name: Option<ManifestName>, } impl LanguageRegistry { pub fn new(executor: BackgroundExecutor) -> Self { let this = Self { state: RwLock::new(LanguageRegistryState { next_language_server_id: 0, languages: Vec::new(), available_languages: AvailableLanguages::default(), grammars: Default::default(), language_settings: Default::default(), loading_languages: Default::default(), lsp_adapters: Default::default(), all_lsp_adapters: Default::default(), available_lsp_adapters: HashMap::default(), subscription: watch::channel(), theme: Default::default(), version: 0, reload_count: 0, #[cfg(any(test, feature = "test-support"))] fake_server_entries: Default::default(), }), language_server_download_dir: None, lsp_binary_status_tx: Default::default(), executor, }; this.add(PLAIN_TEXT.clone()); this } #[cfg(any(test, feature = "test-support"))] pub fn test(executor: BackgroundExecutor) -> Self { let mut this = Self::new(executor); this.language_server_download_dir = Some(Path::new("/the-download-dir").into()); this } /// Clears out all of the loaded languages and reload them from scratch. pub fn reload(&self) { self.state.write().reload(); } /// Reorders the list of language servers for the given language. /// /// Uses the provided list of ordered [`CachedLspAdapters`] as the desired order. /// /// Any existing language servers not present in `ordered_lsp_adapters` will be /// appended to the end. pub fn reorder_language_servers( &self, language: &LanguageName, ordered_lsp_adapters: Vec<Arc<CachedLspAdapter>>, ) { self.state .write() .reorder_language_servers(language, ordered_lsp_adapters); } /// Removes the specified languages and grammars from the registry. pub fn remove_languages( &self, languages_to_remove: &[LanguageName], grammars_to_remove: &[Arc<str>], ) { self.state .write() .remove_languages(languages_to_remove, grammars_to_remove) } pub fn remove_lsp_adapter(&self, language_name: &LanguageName, name: &LanguageServerName) { let mut state = self.state.write(); if let Some(adapters) = state.lsp_adapters.get_mut(language_name) { adapters.retain(|adapter| &adapter.name != name) } state.all_lsp_adapters.remove(name); state.available_lsp_adapters.remove(name); state.version += 1; state.reload_count += 1; *state.subscription.0.borrow_mut() = (); } #[cfg(any(feature = "test-support", test))] pub fn register_test_language(&self, config: LanguageConfig) { self.register_language( config.name.clone(), config.grammar.clone(), config.matcher.clone(), config.hidden, None, Arc::new(move || { Ok(LoadedLanguage { config: config.clone(), queries: Default::default(), toolchain_provider: None, context_provider: None, manifest_name: None, }) }), ) } /// Registers an available language server adapter. /// /// The language server is registered under the language server name, but /// not bound to a particular language. /// /// When a language wants to load this particular language server, it will /// invoke the `load` function. pub fn register_available_lsp_adapter( &self, name: LanguageServerName, adapter: Arc<dyn LspAdapter>, ) { let mut state = self.state.write(); if adapter.is_extension() && let Some(existing_adapter) = state.all_lsp_adapters.get(&name) && !existing_adapter.adapter.is_extension() { log::warn!( "not registering extension-provided language server {name:?}, since a builtin language server exists with that name", ); return; } state.available_lsp_adapters.insert( name, Arc::new(move || CachedLspAdapter::new(adapter.clone())), ); } /// Loads the language server adapter for the language server with the given name. pub fn load_available_lsp_adapter( &self, name: &LanguageServerName, ) -> Option<Arc<CachedLspAdapter>> { let state = self.state.read(); let load_lsp_adapter = state.available_lsp_adapters.get(name)?; Some(load_lsp_adapter()) } /// Checks if a language server adapter with the given name is available to be loaded. pub fn is_lsp_adapter_available(&self, name: &LanguageServerName) -> bool { let state = self.state.read(); state.available_lsp_adapters.contains_key(name) } /// Returns the names of all available LSP adapters (registered via `register_available_lsp_adapter`). /// These are adapters that are not bound to a specific language but can be enabled via settings. pub fn available_lsp_adapter_names(&self) -> Vec<LanguageServerName> { self.state .read() .available_lsp_adapters .keys() .cloned() .collect() } pub fn register_lsp_adapter(&self, language_name: LanguageName, adapter: Arc<dyn LspAdapter>) { let mut state = self.state.write(); if adapter.is_extension() && let Some(existing_adapter) = state.all_lsp_adapters.get(&adapter.name()) && !existing_adapter.adapter.is_extension() { log::warn!( "not registering extension-provided language server {:?} for language {language_name:?}, since a builtin language server exists with that name", adapter.name(), ); return; } let cached = CachedLspAdapter::new(adapter); state .lsp_adapters .entry(language_name) .or_default() .push(cached.clone()); state .all_lsp_adapters .insert(cached.name.clone(), cached.clone()); state.version += 1; *state.subscription.0.borrow_mut() = (); } /// Register a fake language server and adapter /// The returned channel receives a new instance of the language server every time it is started #[cfg(any(feature = "test-support", test))] pub fn register_fake_lsp( &self, language_name: impl Into<LanguageName>, mut adapter: crate::FakeLspAdapter, ) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> { let adapter_name = LanguageServerName(adapter.name.into()); let capabilities = adapter.capabilities.clone(); let initializer = adapter.initializer.take(); self.register_fake_lsp_adapter(language_name, adapter); self.register_fake_lsp_server(adapter_name, capabilities, initializer) } /// Register a fake lsp adapter (without the language server) #[cfg(any(feature = "test-support", test))] pub fn register_fake_lsp_adapter( &self, language_name: impl Into<LanguageName>, adapter: crate::FakeLspAdapter, ) { let language_name = language_name.into(); let mut state = self.state.write(); let cached_adapter = CachedLspAdapter::new(Arc::new(adapter)); state .lsp_adapters .entry(language_name) .or_default() .push(cached_adapter.clone()); state .all_lsp_adapters .insert(cached_adapter.name(), cached_adapter); state.version += 1; *state.subscription.0.borrow_mut() = (); } /// Register a fake language server (without the adapter) /// The returned channel receives a new instance of the language server every time it is started #[cfg(any(feature = "test-support", test))] pub fn register_fake_lsp_server( &self, lsp_name: LanguageServerName, capabilities: lsp::ServerCapabilities, initializer: Option<Box<dyn Fn(&mut lsp::FakeLanguageServer) + Send + Sync>>, ) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> { let (servers_tx, servers_rx) = futures::channel::mpsc::unbounded(); self.state.write().fake_server_entries.insert( lsp_name, FakeLanguageServerEntry { tx: servers_tx, capabilities, initializer, _server: None, }, ); servers_rx } #[cfg(any(feature = "test-support", test))] pub fn register_fake_available_lsp_adapter( &self, name: impl Into<LanguageServerName>, adapter: crate::FakeLspAdapter, ) { let name = name.into(); let adapter = Arc::new(adapter); let mut state = self.state.write(); state.available_lsp_adapters.insert( name, Arc::new(move || CachedLspAdapter::new(adapter.clone())), ); } #[cfg(any(feature = "test-support", test))] pub fn has_fake_lsp_server(&self, lsp_name: &LanguageServerName) -> bool { self.state.read().fake_server_entries.contains_key(lsp_name) } /// Adds a language to the registry, which can be loaded if needed. pub fn register_language( &self, name: LanguageName, grammar_name: Option<Arc<str>>, matcher: Arc<LanguageMatcher>, hidden: bool, manifest_name: Option<ManifestName>, load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>, ) { let state = &mut *self.state.write(); let was_added = state.available_languages.register( name, grammar_name, matcher, hidden, manifest_name, load, ); if !was_added { return; } state.version += 1; state.reload_count += 1; *state.subscription.0.borrow_mut() = (); } /// Adds grammars to the registry. Language configurations reference a grammar by name. The /// grammar controls how the source code is parsed. pub fn register_native_grammars( &self, grammars: impl IntoIterator<Item = (impl Into<Arc<str>>, impl Into<tree_sitter::Language>)>, ) { self.state.write().grammars.extend( grammars .into_iter() .map(|(name, grammar)| (name.into(), AvailableGrammar::Native(grammar.into()))), ); } /// Adds paths to WASM grammar files, which can be loaded if needed. pub fn register_wasm_grammars(&self, grammars: Vec<(Arc<str>, PathBuf)>) { if grammars.is_empty() { return; } let mut state = self.state.write(); state.grammars.extend( grammars .into_iter() .map(|(name, path)| (name, AvailableGrammar::Unloaded(path))), ); state.version += 1; state.reload_count += 1; *state.subscription.0.borrow_mut() = (); } pub fn language_settings(&self) -> AllLanguageSettingsContent { self.state.read().language_settings.clone() } pub fn language_names(&self) -> Vec<LanguageName> { let state = self.state.read(); let mut result = state.available_languages.unloaded_language_names(); result.extend( state .languages .iter() .map(|language| language.config.name.clone()), ); result.sort_unstable_by_key(|language_name| language_name.as_ref().to_lowercase()); result } pub fn grammar_names(&self) -> Vec<Arc<str>> { let state = self.state.read(); let mut result = state.grammars.keys().cloned().collect::<Vec<_>>(); result.sort_unstable_by_key(|grammar_name| grammar_name.to_lowercase()); result } /// Add a pre-loaded language to the registry. pub fn add(&self, language: Arc<Language>) { let mut state = self.state.write(); state.available_languages.add(AvailableLanguage { id: language.id, name: language.name(), grammar: language.config.grammar.clone(), matcher: language.config.matcher.clone(), hidden: language.config.hidden, manifest_name: None, load: Arc::new(|| Err(anyhow!("already loaded"))), loaded: true, }); state.add(language); } pub fn subscribe(&self) -> watch::Receiver<()> { self.state.read().subscription.1.clone() } /// Returns the number of times that the registry has been changed, /// by adding languages or reloading. pub fn version(&self) -> usize { self.state.read().version } /// Returns the number of times that the registry has been reloaded. pub fn reload_count(&self) -> usize { self.state.read().reload_count } pub fn set_theme(&self, theme: Arc<Theme>) { let mut state = self.state.write(); state.theme = Some(theme.clone()); for language in &state.languages { language.set_theme(theme.syntax()); } } pub fn set_language_server_download_dir(&mut self, path: impl Into<Arc<Path>>) { self.language_server_download_dir = Some(path.into()); } pub fn language_for_name( self: &Arc<Self>, name: &str, ) -> impl Future<Output = Result<Arc<Language>>> + use<> { let language_id = self.state.read().available_languages.find_by_name(name); let rx = self.get_or_load_language(language_id);