Incomplete refactor to allow for multiple adapters per language

This commit is contained in:
Julia 2023-04-07 11:46:05 -04:00 committed by Max Brunsfeld
parent 21e39e7523
commit ba7233f265
10 changed files with 818 additions and 577 deletions

View file

@ -414,7 +414,7 @@ pub struct BracketPair {
pub struct Language {
pub(crate) config: LanguageConfig,
pub(crate) grammar: Option<Arc<Grammar>>,
pub(crate) adapter: Option<Arc<CachedLspAdapter>>,
pub(crate) adapters: Vec<Arc<CachedLspAdapter>>,
#[cfg(any(test, feature = "test-support"))]
fake_adapter: Option<(
@ -492,7 +492,7 @@ struct AvailableLanguage {
path: &'static str,
config: LanguageConfig,
grammar: tree_sitter::Language,
lsp_adapter: Option<Arc<dyn LspAdapter>>,
lsp_adapters: Vec<Arc<dyn LspAdapter>>,
get_queries: fn(&str) -> LanguageQueries,
}
@ -513,6 +513,7 @@ pub struct LanguageRegistry {
}
struct LanguageRegistryState {
next_language_server_id: usize,
languages: Vec<Arc<Language>>,
available_languages: Vec<AvailableLanguage>,
next_available_language_id: AvailableLanguageId,
@ -522,11 +523,17 @@ struct LanguageRegistryState {
version: usize,
}
pub struct PendingLanguageServer {
pub server_id: usize,
pub task: Task<Result<lsp::LanguageServer>>,
}
impl LanguageRegistry {
pub fn new(login_shell_env_loaded: Task<()>) -> Self {
let (lsp_binary_statuses_tx, lsp_binary_statuses_rx) = async_broadcast::broadcast(16);
Self {
state: RwLock::new(LanguageRegistryState {
next_language_server_id: 0,
languages: vec![PLAIN_TEXT.clone()],
available_languages: Default::default(),
next_available_language_id: 0,
@ -558,7 +565,7 @@ impl LanguageRegistry {
path: &'static str,
config: LanguageConfig,
grammar: tree_sitter::Language,
lsp_adapter: Option<Arc<dyn LspAdapter>>,
lsp_adapters: Vec<Arc<dyn LspAdapter>>,
get_queries: fn(&str) -> LanguageQueries,
) {
let state = &mut *self.state.write();
@ -567,7 +574,7 @@ impl LanguageRegistry {
path,
config,
grammar,
lsp_adapter,
lsp_adapters,
get_queries,
});
}
@ -590,12 +597,13 @@ impl LanguageRegistry {
state
.available_languages
.iter()
.filter_map(|l| l.lsp_adapter.clone())
.flat_map(|l| l.lsp_adapters.clone())
.chain(
state
.languages
.iter()
.filter_map(|l| l.adapter.as_ref().map(|a| a.adapter.clone())),
.flat_map(|language| &language.adapters)
.map(|adapter| adapter.adapter.clone()),
)
.collect::<Vec<_>>()
};
@ -721,7 +729,7 @@ impl LanguageRegistry {
let queries = (language.get_queries)(&language.path);
let language =
Language::new(language.config, Some(language.grammar))
.with_lsp_adapter(language.lsp_adapter)
.with_lsp_adapters(language.lsp_adapters)
.await;
let name = language.name();
match language.with_queries(queries) {
@ -774,18 +782,16 @@ impl LanguageRegistry {
self.state.read().languages.iter().cloned().collect()
}
pub fn start_language_server(
pub fn start_language_servers(
self: &Arc<Self>,
server_id: usize,
language: Arc<Language>,
root_path: Arc<Path>,
http_client: Arc<dyn HttpClient>,
cx: &mut AppContext,
) -> Option<Task<Result<lsp::LanguageServer>>> {
) -> Vec<PendingLanguageServer> {
#[cfg(any(test, feature = "test-support"))]
if language.fake_adapter.is_some() {
let language = language;
return Some(cx.spawn(|cx| async move {
let task = cx.spawn(|cx| async move {
let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap();
let (server, mut fake_server) = lsp::LanguageServer::fake(
fake_adapter.name.to_string(),
@ -810,53 +816,71 @@ impl LanguageRegistry {
})
.detach();
Ok(server)
}));
});
return vec![PendingLanguageServer { server_id: 0, task }];
}
let download_dir = self
.language_server_download_dir
.clone()
.ok_or_else(|| anyhow!("language server download directory has not been assigned"))
.log_err()?;
.log_err();
let download_dir = match download_dir {
Some(download_dir) => download_dir,
None => return Vec::new(),
};
let this = self.clone();
let adapter = language.adapter.clone()?;
let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone();
let login_shell_env_loaded = self.login_shell_env_loaded.clone();
let mut results = Vec::new();
Some(cx.spawn(|cx| async move {
login_shell_env_loaded.await;
for adapter in &language.adapters {
let this = self.clone();
let language = language.clone();
let http_client = http_client.clone();
let download_dir = download_dir.clone();
let root_path = root_path.clone();
let adapter = adapter.clone();
let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone();
let login_shell_env_loaded = self.login_shell_env_loaded.clone();
let server_id = post_inc(&mut self.state.write().next_language_server_id);
let mut lock = this.lsp_binary_paths.lock();
let entry = lock
.entry(adapter.name.clone())
.or_insert_with(|| {
get_binary(
adapter.clone(),
language.clone(),
http_client,
download_dir,
lsp_binary_statuses,
)
.map_err(Arc::new)
.boxed()
.shared()
})
.clone();
drop(lock);
let binary = entry.clone().map_err(|e| anyhow!(e)).await?;
let task = cx.spawn(|cx| async move {
login_shell_env_loaded.await;
let server = lsp::LanguageServer::new(
server_id,
&binary.path,
&binary.arguments,
&root_path,
adapter.code_action_kinds(),
cx,
)?;
let mut lock = this.lsp_binary_paths.lock();
let entry = lock
.entry(adapter.name.clone())
.or_insert_with(|| {
get_binary(
adapter.clone(),
language.clone(),
http_client,
download_dir,
lsp_binary_statuses,
)
.map_err(Arc::new)
.boxed()
.shared()
})
.clone();
drop(lock);
let binary = entry.clone().map_err(|e| anyhow!(e)).await?;
Ok(server)
}))
let server = lsp::LanguageServer::new(
server_id,
&binary.path,
&binary.arguments,
&root_path,
adapter.code_action_kinds(),
cx,
)?;
Ok(server)
});
results.push(PendingLanguageServer { server_id, task });
}
results
}
pub fn language_server_binary_statuses(
@ -974,15 +998,15 @@ impl Language {
highlight_map: Default::default(),
})
}),
adapter: None,
adapters: Vec::new(),
#[cfg(any(test, feature = "test-support"))]
fake_adapter: None,
}
}
pub fn lsp_adapter(&self) -> Option<Arc<CachedLspAdapter>> {
self.adapter.clone()
pub fn lsp_adapters(&self) -> &[Arc<CachedLspAdapter>] {
&self.adapters
}
pub fn id(&self) -> Option<usize> {
@ -1209,9 +1233,9 @@ impl Language {
Arc::get_mut(self.grammar.as_mut().unwrap()).unwrap()
}
pub async fn with_lsp_adapter(mut self, lsp_adapter: Option<Arc<dyn LspAdapter>>) -> Self {
if let Some(adapter) = lsp_adapter {
self.adapter = Some(CachedLspAdapter::new(adapter).await);
pub async fn with_lsp_adapters(mut self, lsp_adapters: Vec<Arc<dyn LspAdapter>>) -> Self {
for adapter in lsp_adapters {
self.adapters.push(CachedLspAdapter::new(adapter).await);
}
self
}
@ -1224,7 +1248,7 @@ impl Language {
let (servers_tx, servers_rx) = mpsc::unbounded();
self.fake_adapter = Some((servers_tx, fake_lsp_adapter.clone()));
let adapter = CachedLspAdapter::new(Arc::new(fake_lsp_adapter)).await;
self.adapter = Some(adapter);
self.adapters = vec![adapter];
servers_rx
}
@ -1233,28 +1257,31 @@ impl Language {
}
pub async fn disk_based_diagnostic_sources(&self) -> &[String] {
match self.adapter.as_ref() {
match self.adapters.first().as_ref() {
Some(adapter) => &adapter.disk_based_diagnostic_sources,
None => &[],
}
}
pub async fn disk_based_diagnostics_progress_token(&self) -> Option<&str> {
if let Some(adapter) = self.adapter.as_ref() {
adapter.disk_based_diagnostics_progress_token.as_deref()
} else {
None
for adapter in &self.adapters {
let token = adapter.disk_based_diagnostics_progress_token.as_deref();
if token.is_some() {
return token;
}
}
None
}
pub async fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams) {
if let Some(processor) = self.adapter.as_ref() {
processor.process_diagnostics(diagnostics).await;
for adapter in &self.adapters {
adapter.process_diagnostics(diagnostics).await;
}
}
pub async fn process_completion(self: &Arc<Self>, completion: &mut lsp::CompletionItem) {
if let Some(adapter) = self.adapter.as_ref() {
for adapter in &self.adapters {
adapter.process_completion(completion).await;
}
}
@ -1263,7 +1290,8 @@ impl Language {
self: &Arc<Self>,
completion: &lsp::CompletionItem,
) -> Option<CodeLabel> {
self.adapter
self.adapters
.first()
.as_ref()?
.label_for_completion(completion, self)
.await
@ -1274,7 +1302,8 @@ impl Language {
name: &str,
kind: lsp::SymbolKind,
) -> Option<CodeLabel> {
self.adapter
self.adapters
.first()
.as_ref()?
.label_for_symbol(name, kind, self)
.await
@ -1595,7 +1624,7 @@ mod tests {
..Default::default()
},
tree_sitter_json::language(),
None,
vec![],
|_| Default::default(),
);
languages.register(
@ -1606,7 +1635,7 @@ mod tests {
..Default::default()
},
tree_sitter_rust::language(),
None,
vec![],
|_| Default::default(),
);
assert_eq!(