Incomplete refactor to allow for multiple adapters per language
This commit is contained in:
parent
21e39e7523
commit
ba7233f265
10 changed files with 818 additions and 577 deletions
|
@ -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!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue