diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 47b8e23374..0c05fdccb1 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -44,7 +44,7 @@ use syntax_map::SyntaxSnapshot; use theme::{SyntaxTheme, Theme}; use tree_sitter::{self, Query}; use unicase::UniCase; -use util::{merge_json_value_into, ResultExt, TryFutureExt as _, UnwrapFuture}; +use util::{merge_json_value_into, post_inc, ResultExt, TryFutureExt as _, UnwrapFuture}; #[cfg(any(test, feature = "test-support"))] use futures::channel::mpsc; @@ -87,11 +87,11 @@ pub struct CachedLspAdapter { pub disk_based_diagnostic_sources: Vec, pub disk_based_diagnostics_progress_token: Option, pub language_ids: HashMap, - pub adapter: Box, + pub adapter: Arc, } impl CachedLspAdapter { - pub async fn new(adapter: Box) -> Arc { + pub async fn new(adapter: Arc) -> Arc { let name = adapter.name().await; let server_args = adapter.server_args().await; let initialization_options = adapter.initialization_options().await; @@ -242,7 +242,7 @@ pub struct CodeLabel { pub filter_range: Range, } -#[derive(Deserialize)] +#[derive(Clone, Deserialize)] pub struct LanguageConfig { pub name: Arc, pub path_suffixes: Vec, @@ -279,7 +279,7 @@ pub struct LanguageScope { override_id: Option, } -#[derive(Deserialize, Default, Debug)] +#[derive(Clone, Deserialize, Default, Debug)] pub struct LanguageConfigOverride { #[serde(default)] pub line_comment: Override>, @@ -289,7 +289,7 @@ pub struct LanguageConfigOverride { pub disabled_bracket_ixs: Vec, } -#[derive(Deserialize, Debug)] +#[derive(Clone, Deserialize, Debug)] #[serde(untagged)] pub enum Override { Remove { remove: bool }, @@ -466,11 +466,15 @@ pub enum LanguageServerBinaryStatus { Failed { error: String }, } +type AvailableLanguageId = usize; + +#[derive(Clone)] struct AvailableLanguage { + id: AvailableLanguageId, path: &'static str, config: LanguageConfig, grammar: tree_sitter::Language, - lsp_adapter: Option>, + lsp_adapter: Option>, get_queries: fn(&str) -> LanguageQueries, } @@ -493,6 +497,8 @@ pub struct LanguageRegistry { struct LanguageRegistryState { languages: Vec>, available_languages: Vec, + next_available_language_id: AvailableLanguageId, + loading_languages: HashMap>>>>, subscription: (watch::Sender<()>, watch::Receiver<()>), theme: Option>, version: usize, @@ -505,6 +511,8 @@ impl LanguageRegistry { state: RwLock::new(LanguageRegistryState { languages: vec![PLAIN_TEXT.clone()], available_languages: Default::default(), + next_available_language_id: 0, + loading_languages: Default::default(), subscription: watch::channel(), theme: Default::default(), version: 0, @@ -532,19 +540,18 @@ impl LanguageRegistry { path: &'static str, config: LanguageConfig, grammar: tree_sitter::Language, - lsp_adapter: Option>, + lsp_adapter: Option>, get_queries: fn(&str) -> LanguageQueries, ) { - self.state - .write() - .available_languages - .push(AvailableLanguage { - path, - config, - grammar, - lsp_adapter, - get_queries, - }); + let state = &mut *self.state.write(); + state.available_languages.push(AvailableLanguage { + id: post_inc(&mut state.next_available_language_id), + path, + config, + grammar, + lsp_adapter, + get_queries, + }); } pub fn language_names(&self) -> Vec { @@ -588,13 +595,7 @@ impl LanguageRegistry { } pub fn add(&self, language: Arc) { - let mut state = self.state.write(); - if let Some(theme) = state.theme.as_ref() { - language.set_theme(&theme.editor.syntax); - } - state.languages.push(language); - state.version += 1; - *state.subscription.0.borrow_mut() = (); + self.state.write().add(language); } pub fn subscribe(&self) -> watch::Receiver<()> { @@ -669,37 +670,62 @@ impl LanguageRegistry { { let _ = tx.send(Ok(language.clone())); } else if let Some(executor) = self.executor.clone() { - if let Some(ix) = state + if let Some(language) = state .available_languages .iter() - .position(|l| callback(&l.config)) + .find(|l| callback(&l.config)) + .cloned() { - let language = state.available_languages.remove(ix); - drop(state); - let name = language.config.name.clone(); - let this = self.clone(); - executor - .spawn(async move { - let queries = (language.get_queries)(&language.path); - let language = Language::new(language.config, Some(language.grammar)) - .with_lsp_adapter(language.lsp_adapter) - .await; - match language.with_queries(queries) { - Ok(language) => { - let language = Arc::new(language); - this.add(language.clone()); - let _ = tx.send(Ok(language)); - } - Err(err) => { - let _ = tx.send(Err(anyhow!( - "failed to load language {}: {}", - name, - err - ))); - } - }; - }) - .detach(); + let txs = state + .loading_languages + .entry(language.id) + .or_insert_with(|| { + let this = self.clone(); + executor + .spawn(async move { + let id = language.id; + let queries = (language.get_queries)(&language.path); + let language = + Language::new(language.config, Some(language.grammar)) + .with_lsp_adapter(language.lsp_adapter) + .await; + let name = language.name(); + match language.with_queries(queries) { + Ok(language) => { + let language = Arc::new(language); + let mut state = this.state.write(); + state.add(language.clone()); + state + .available_languages + .retain(|language| language.id != id); + if let Some(mut txs) = state.loading_languages.remove(&id) { + for tx in txs.drain(..) { + let _ = tx.send(Ok(language.clone())); + } + } + } + Err(err) => { + let mut state = this.state.write(); + state + .available_languages + .retain(|language| language.id != id); + if let Some(mut txs) = state.loading_languages.remove(&id) { + for tx in txs.drain(..) { + let _ = tx.send(Err(anyhow!( + "failed to load language {}: {}", + name, + err + ))); + } + } + } + }; + }) + .detach(); + + Vec::new() + }); + txs.push(tx); } else { let _ = tx.send(Err(anyhow!("language not found"))); } @@ -804,6 +830,17 @@ impl LanguageRegistry { } } +impl LanguageRegistryState { + fn add(&mut self, language: Arc) { + if let Some(theme) = self.theme.as_ref() { + language.set_theme(&theme.editor.syntax); + } + self.languages.push(language); + self.version += 1; + *self.subscription.0.borrow_mut() = (); + } +} + #[cfg(any(test, feature = "test-support"))] impl Default for LanguageRegistry { fn default() -> Self { @@ -1135,7 +1172,7 @@ impl Language { Arc::get_mut(self.grammar.as_mut().unwrap()).unwrap() } - pub async fn with_lsp_adapter(mut self, lsp_adapter: Option>) -> Self { + pub async fn with_lsp_adapter(mut self, lsp_adapter: Option>) -> Self { if let Some(adapter) = lsp_adapter { self.adapter = Some(CachedLspAdapter::new(adapter).await); } @@ -1149,7 +1186,7 @@ impl Language { ) -> mpsc::UnboundedReceiver { let (servers_tx, servers_rx) = mpsc::unbounded(); self.fake_adapter = Some((servers_tx, fake_lsp_adapter.clone())); - let adapter = CachedLspAdapter::new(Box::new(fake_lsp_adapter)).await; + let adapter = CachedLspAdapter::new(Arc::new(fake_lsp_adapter)).await; self.adapter = Some(adapter); servers_rx } diff --git a/crates/zed/src/languages.rs b/crates/zed/src/languages.rs index 5d5ffc4f95..1acee4bad4 100644 --- a/crates/zed/src/languages.rs +++ b/crates/zed/src/languages.rs @@ -37,12 +37,12 @@ pub fn init(languages: Arc, themes: Arc) { ( "c", tree_sitter_c::language(), - Some(Box::new(c::CLspAdapter) as Box), + Some(Arc::new(c::CLspAdapter) as Arc), ), ( "cpp", tree_sitter_cpp::language(), - Some(Box::new(c::CLspAdapter)), + Some(Arc::new(c::CLspAdapter)), ), ( "css", @@ -52,17 +52,17 @@ pub fn init(languages: Arc, themes: Arc) { ( "elixir", tree_sitter_elixir::language(), - Some(Box::new(elixir::ElixirLspAdapter)), + Some(Arc::new(elixir::ElixirLspAdapter)), ), ( "go", tree_sitter_go::language(), - Some(Box::new(go::GoLspAdapter)), + Some(Arc::new(go::GoLspAdapter)), ), ( "json", tree_sitter_json::language(), - Some(Box::new(json::JsonLspAdapter::new( + Some(Arc::new(json::JsonLspAdapter::new( languages.clone(), themes.clone(), ))), @@ -75,12 +75,12 @@ pub fn init(languages: Arc, themes: Arc) { ( "python", tree_sitter_python::language(), - Some(Box::new(python::PythonLspAdapter)), + Some(Arc::new(python::PythonLspAdapter)), ), ( "rust", tree_sitter_rust::language(), - Some(Box::new(rust::RustLspAdapter)), + Some(Arc::new(rust::RustLspAdapter)), ), ( "toml", @@ -90,32 +90,32 @@ pub fn init(languages: Arc, themes: Arc) { ( "tsx", tree_sitter_typescript::language_tsx(), - Some(Box::new(typescript::TypeScriptLspAdapter)), + Some(Arc::new(typescript::TypeScriptLspAdapter)), ), ( "typescript", tree_sitter_typescript::language_typescript(), - Some(Box::new(typescript::TypeScriptLspAdapter)), + Some(Arc::new(typescript::TypeScriptLspAdapter)), ), ( "javascript", tree_sitter_typescript::language_tsx(), - Some(Box::new(typescript::TypeScriptLspAdapter)), + Some(Arc::new(typescript::TypeScriptLspAdapter)), ), ( "html", tree_sitter_html::language(), - Some(Box::new(html::HtmlLspAdapter)), + Some(Arc::new(html::HtmlLspAdapter)), ), ( "ruby", tree_sitter_ruby::language(), - Some(Box::new(ruby::RubyLanguageServer)), + Some(Arc::new(ruby::RubyLanguageServer)), ), ( "erb", tree_sitter_embedded_template::language(), - Some(Box::new(ruby::RubyLanguageServer)), + Some(Arc::new(ruby::RubyLanguageServer)), ), ( "scheme", @@ -130,12 +130,12 @@ pub fn init(languages: Arc, themes: Arc) { ( "lua", tree_sitter_lua::language(), - Some(Box::new(lua::LuaLspAdapter)), + Some(Arc::new(lua::LuaLspAdapter)), ), ( "yaml", tree_sitter_yaml::language(), - Some(Box::new(yaml::YamlLspAdapter)), + Some(Arc::new(yaml::YamlLspAdapter)), ), ] { languages.register(name, load_config(name), grammar, lsp_adapter, load_queries); @@ -146,7 +146,7 @@ pub fn init(languages: Arc, themes: Arc) { pub async fn language( name: &str, grammar: tree_sitter::Language, - lsp_adapter: Option>, + lsp_adapter: Option>, ) -> Arc { Arc::new( Language::new(load_config(name), Some(grammar)) diff --git a/crates/zed/src/languages/go.rs b/crates/zed/src/languages/go.rs index dc84599e4e..dd819338d0 100644 --- a/crates/zed/src/languages/go.rs +++ b/crates/zed/src/languages/go.rs @@ -314,7 +314,7 @@ mod tests { let language = language( "go", tree_sitter_go::language(), - Some(Box::new(GoLspAdapter)), + Some(Arc::new(GoLspAdapter)), ) .await; diff --git a/crates/zed/src/languages/rust.rs b/crates/zed/src/languages/rust.rs index 40948d5005..a8f7fcbc4d 100644 --- a/crates/zed/src/languages/rust.rs +++ b/crates/zed/src/languages/rust.rs @@ -306,7 +306,7 @@ mod tests { let language = language( "rust", tree_sitter_rust::language(), - Some(Box::new(RustLspAdapter)), + Some(Arc::new(RustLspAdapter)), ) .await; let grammar = language.grammar().unwrap(); @@ -392,7 +392,7 @@ mod tests { let language = language( "rust", tree_sitter_rust::language(), - Some(Box::new(RustLspAdapter)), + Some(Arc::new(RustLspAdapter)), ) .await; let grammar = language.grammar().unwrap();