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
|
@ -2764,6 +2764,15 @@ impl MultiBufferSnapshot {
|
||||||
.and_then(|(buffer, offset)| buffer.language_scope_at(offset))
|
.and_then(|(buffer, offset)| buffer.language_scope_at(offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn language_indent_size_at<T: ToOffset>(
|
||||||
|
&self,
|
||||||
|
position: T,
|
||||||
|
cx: &AppContext,
|
||||||
|
) -> Option<IndentSize> {
|
||||||
|
let (buffer_snapshot, offset) = self.point_to_buffer_offset(position)?;
|
||||||
|
Some(buffer_snapshot.language_indent_size_at(offset, cx))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_dirty(&self) -> bool {
|
pub fn is_dirty(&self) -> bool {
|
||||||
self.is_dirty
|
self.is_dirty
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,7 @@ pub struct Completion {
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CodeAction {
|
pub struct CodeAction {
|
||||||
|
pub server_id: usize,
|
||||||
pub range: Range<Anchor>,
|
pub range: Range<Anchor>,
|
||||||
pub lsp_action: lsp::CodeAction,
|
pub lsp_action: lsp::CodeAction,
|
||||||
}
|
}
|
||||||
|
|
|
@ -414,7 +414,7 @@ pub struct BracketPair {
|
||||||
pub struct Language {
|
pub struct Language {
|
||||||
pub(crate) config: LanguageConfig,
|
pub(crate) config: LanguageConfig,
|
||||||
pub(crate) grammar: Option<Arc<Grammar>>,
|
pub(crate) grammar: Option<Arc<Grammar>>,
|
||||||
pub(crate) adapter: Option<Arc<CachedLspAdapter>>,
|
pub(crate) adapters: Vec<Arc<CachedLspAdapter>>,
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
fake_adapter: Option<(
|
fake_adapter: Option<(
|
||||||
|
@ -492,7 +492,7 @@ struct AvailableLanguage {
|
||||||
path: &'static str,
|
path: &'static str,
|
||||||
config: LanguageConfig,
|
config: LanguageConfig,
|
||||||
grammar: tree_sitter::Language,
|
grammar: tree_sitter::Language,
|
||||||
lsp_adapter: Option<Arc<dyn LspAdapter>>,
|
lsp_adapters: Vec<Arc<dyn LspAdapter>>,
|
||||||
get_queries: fn(&str) -> LanguageQueries,
|
get_queries: fn(&str) -> LanguageQueries,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,6 +513,7 @@ pub struct LanguageRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LanguageRegistryState {
|
struct LanguageRegistryState {
|
||||||
|
next_language_server_id: usize,
|
||||||
languages: Vec<Arc<Language>>,
|
languages: Vec<Arc<Language>>,
|
||||||
available_languages: Vec<AvailableLanguage>,
|
available_languages: Vec<AvailableLanguage>,
|
||||||
next_available_language_id: AvailableLanguageId,
|
next_available_language_id: AvailableLanguageId,
|
||||||
|
@ -522,11 +523,17 @@ struct LanguageRegistryState {
|
||||||
version: usize,
|
version: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PendingLanguageServer {
|
||||||
|
pub server_id: usize,
|
||||||
|
pub task: Task<Result<lsp::LanguageServer>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl LanguageRegistry {
|
impl LanguageRegistry {
|
||||||
pub fn new(login_shell_env_loaded: Task<()>) -> Self {
|
pub fn new(login_shell_env_loaded: Task<()>) -> Self {
|
||||||
let (lsp_binary_statuses_tx, lsp_binary_statuses_rx) = async_broadcast::broadcast(16);
|
let (lsp_binary_statuses_tx, lsp_binary_statuses_rx) = async_broadcast::broadcast(16);
|
||||||
Self {
|
Self {
|
||||||
state: RwLock::new(LanguageRegistryState {
|
state: RwLock::new(LanguageRegistryState {
|
||||||
|
next_language_server_id: 0,
|
||||||
languages: vec![PLAIN_TEXT.clone()],
|
languages: vec![PLAIN_TEXT.clone()],
|
||||||
available_languages: Default::default(),
|
available_languages: Default::default(),
|
||||||
next_available_language_id: 0,
|
next_available_language_id: 0,
|
||||||
|
@ -558,7 +565,7 @@ impl LanguageRegistry {
|
||||||
path: &'static str,
|
path: &'static str,
|
||||||
config: LanguageConfig,
|
config: LanguageConfig,
|
||||||
grammar: tree_sitter::Language,
|
grammar: tree_sitter::Language,
|
||||||
lsp_adapter: Option<Arc<dyn LspAdapter>>,
|
lsp_adapters: Vec<Arc<dyn LspAdapter>>,
|
||||||
get_queries: fn(&str) -> LanguageQueries,
|
get_queries: fn(&str) -> LanguageQueries,
|
||||||
) {
|
) {
|
||||||
let state = &mut *self.state.write();
|
let state = &mut *self.state.write();
|
||||||
|
@ -567,7 +574,7 @@ impl LanguageRegistry {
|
||||||
path,
|
path,
|
||||||
config,
|
config,
|
||||||
grammar,
|
grammar,
|
||||||
lsp_adapter,
|
lsp_adapters,
|
||||||
get_queries,
|
get_queries,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -590,12 +597,13 @@ impl LanguageRegistry {
|
||||||
state
|
state
|
||||||
.available_languages
|
.available_languages
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|l| l.lsp_adapter.clone())
|
.flat_map(|l| l.lsp_adapters.clone())
|
||||||
.chain(
|
.chain(
|
||||||
state
|
state
|
||||||
.languages
|
.languages
|
||||||
.iter()
|
.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<_>>()
|
.collect::<Vec<_>>()
|
||||||
};
|
};
|
||||||
|
@ -721,7 +729,7 @@ impl LanguageRegistry {
|
||||||
let queries = (language.get_queries)(&language.path);
|
let queries = (language.get_queries)(&language.path);
|
||||||
let language =
|
let language =
|
||||||
Language::new(language.config, Some(language.grammar))
|
Language::new(language.config, Some(language.grammar))
|
||||||
.with_lsp_adapter(language.lsp_adapter)
|
.with_lsp_adapters(language.lsp_adapters)
|
||||||
.await;
|
.await;
|
||||||
let name = language.name();
|
let name = language.name();
|
||||||
match language.with_queries(queries) {
|
match language.with_queries(queries) {
|
||||||
|
@ -774,18 +782,16 @@ impl LanguageRegistry {
|
||||||
self.state.read().languages.iter().cloned().collect()
|
self.state.read().languages.iter().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_language_server(
|
pub fn start_language_servers(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
server_id: usize,
|
|
||||||
language: Arc<Language>,
|
language: Arc<Language>,
|
||||||
root_path: Arc<Path>,
|
root_path: Arc<Path>,
|
||||||
http_client: Arc<dyn HttpClient>,
|
http_client: Arc<dyn HttpClient>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Option<Task<Result<lsp::LanguageServer>>> {
|
) -> Vec<PendingLanguageServer> {
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
if language.fake_adapter.is_some() {
|
if language.fake_adapter.is_some() {
|
||||||
let language = language;
|
let task = cx.spawn(|cx| async move {
|
||||||
return Some(cx.spawn(|cx| async move {
|
|
||||||
let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap();
|
let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap();
|
||||||
let (server, mut fake_server) = lsp::LanguageServer::fake(
|
let (server, mut fake_server) = lsp::LanguageServer::fake(
|
||||||
fake_adapter.name.to_string(),
|
fake_adapter.name.to_string(),
|
||||||
|
@ -810,53 +816,71 @@ impl LanguageRegistry {
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
Ok(server)
|
Ok(server)
|
||||||
}));
|
});
|
||||||
|
return vec![PendingLanguageServer { server_id: 0, task }];
|
||||||
}
|
}
|
||||||
|
|
||||||
let download_dir = self
|
let download_dir = self
|
||||||
.language_server_download_dir
|
.language_server_download_dir
|
||||||
.clone()
|
.clone()
|
||||||
.ok_or_else(|| anyhow!("language server download directory has not been assigned"))
|
.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 mut results = Vec::new();
|
||||||
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();
|
|
||||||
|
|
||||||
Some(cx.spawn(|cx| async move {
|
for adapter in &language.adapters {
|
||||||
login_shell_env_loaded.await;
|
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 task = cx.spawn(|cx| async move {
|
||||||
let entry = lock
|
login_shell_env_loaded.await;
|
||||||
.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 server = lsp::LanguageServer::new(
|
let mut lock = this.lsp_binary_paths.lock();
|
||||||
server_id,
|
let entry = lock
|
||||||
&binary.path,
|
.entry(adapter.name.clone())
|
||||||
&binary.arguments,
|
.or_insert_with(|| {
|
||||||
&root_path,
|
get_binary(
|
||||||
adapter.code_action_kinds(),
|
adapter.clone(),
|
||||||
cx,
|
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(
|
pub fn language_server_binary_statuses(
|
||||||
|
@ -974,15 +998,15 @@ impl Language {
|
||||||
highlight_map: Default::default(),
|
highlight_map: Default::default(),
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
adapter: None,
|
adapters: Vec::new(),
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
fake_adapter: None,
|
fake_adapter: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lsp_adapter(&self) -> Option<Arc<CachedLspAdapter>> {
|
pub fn lsp_adapters(&self) -> &[Arc<CachedLspAdapter>] {
|
||||||
self.adapter.clone()
|
&self.adapters
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> Option<usize> {
|
pub fn id(&self) -> Option<usize> {
|
||||||
|
@ -1209,9 +1233,9 @@ impl Language {
|
||||||
Arc::get_mut(self.grammar.as_mut().unwrap()).unwrap()
|
Arc::get_mut(self.grammar.as_mut().unwrap()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn with_lsp_adapter(mut self, lsp_adapter: Option<Arc<dyn LspAdapter>>) -> Self {
|
pub async fn with_lsp_adapters(mut self, lsp_adapters: Vec<Arc<dyn LspAdapter>>) -> Self {
|
||||||
if let Some(adapter) = lsp_adapter {
|
for adapter in lsp_adapters {
|
||||||
self.adapter = Some(CachedLspAdapter::new(adapter).await);
|
self.adapters.push(CachedLspAdapter::new(adapter).await);
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -1224,7 +1248,7 @@ impl Language {
|
||||||
let (servers_tx, servers_rx) = mpsc::unbounded();
|
let (servers_tx, servers_rx) = mpsc::unbounded();
|
||||||
self.fake_adapter = Some((servers_tx, fake_lsp_adapter.clone()));
|
self.fake_adapter = Some((servers_tx, fake_lsp_adapter.clone()));
|
||||||
let adapter = CachedLspAdapter::new(Arc::new(fake_lsp_adapter)).await;
|
let adapter = CachedLspAdapter::new(Arc::new(fake_lsp_adapter)).await;
|
||||||
self.adapter = Some(adapter);
|
self.adapters = vec![adapter];
|
||||||
servers_rx
|
servers_rx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1233,28 +1257,31 @@ impl Language {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn disk_based_diagnostic_sources(&self) -> &[String] {
|
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,
|
Some(adapter) => &adapter.disk_based_diagnostic_sources,
|
||||||
None => &[],
|
None => &[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn disk_based_diagnostics_progress_token(&self) -> Option<&str> {
|
pub async fn disk_based_diagnostics_progress_token(&self) -> Option<&str> {
|
||||||
if let Some(adapter) = self.adapter.as_ref() {
|
for adapter in &self.adapters {
|
||||||
adapter.disk_based_diagnostics_progress_token.as_deref()
|
let token = adapter.disk_based_diagnostics_progress_token.as_deref();
|
||||||
} else {
|
if token.is_some() {
|
||||||
None
|
return token;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams) {
|
pub async fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams) {
|
||||||
if let Some(processor) = self.adapter.as_ref() {
|
for adapter in &self.adapters {
|
||||||
processor.process_diagnostics(diagnostics).await;
|
adapter.process_diagnostics(diagnostics).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn process_completion(self: &Arc<Self>, completion: &mut lsp::CompletionItem) {
|
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;
|
adapter.process_completion(completion).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1263,7 +1290,8 @@ impl Language {
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
completion: &lsp::CompletionItem,
|
completion: &lsp::CompletionItem,
|
||||||
) -> Option<CodeLabel> {
|
) -> Option<CodeLabel> {
|
||||||
self.adapter
|
self.adapters
|
||||||
|
.first()
|
||||||
.as_ref()?
|
.as_ref()?
|
||||||
.label_for_completion(completion, self)
|
.label_for_completion(completion, self)
|
||||||
.await
|
.await
|
||||||
|
@ -1274,7 +1302,8 @@ impl Language {
|
||||||
name: &str,
|
name: &str,
|
||||||
kind: lsp::SymbolKind,
|
kind: lsp::SymbolKind,
|
||||||
) -> Option<CodeLabel> {
|
) -> Option<CodeLabel> {
|
||||||
self.adapter
|
self.adapters
|
||||||
|
.first()
|
||||||
.as_ref()?
|
.as_ref()?
|
||||||
.label_for_symbol(name, kind, self)
|
.label_for_symbol(name, kind, self)
|
||||||
.await
|
.await
|
||||||
|
@ -1595,7 +1624,7 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
tree_sitter_json::language(),
|
tree_sitter_json::language(),
|
||||||
None,
|
vec![],
|
||||||
|_| Default::default(),
|
|_| Default::default(),
|
||||||
);
|
);
|
||||||
languages.register(
|
languages.register(
|
||||||
|
@ -1606,7 +1635,7 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
tree_sitter_rust::language(),
|
tree_sitter_rust::language(),
|
||||||
None,
|
vec![],
|
||||||
|_| Default::default(),
|
|_| Default::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -462,6 +462,7 @@ pub async fn deserialize_completion(
|
||||||
|
|
||||||
pub fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
|
pub fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
|
||||||
proto::CodeAction {
|
proto::CodeAction {
|
||||||
|
server_id: action.server_id as u64,
|
||||||
start: Some(serialize_anchor(&action.range.start)),
|
start: Some(serialize_anchor(&action.range.start)),
|
||||||
end: Some(serialize_anchor(&action.range.end)),
|
end: Some(serialize_anchor(&action.range.end)),
|
||||||
lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(),
|
lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(),
|
||||||
|
@ -479,6 +480,7 @@ pub fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction>
|
||||||
.ok_or_else(|| anyhow!("invalid end"))?;
|
.ok_or_else(|| anyhow!("invalid end"))?;
|
||||||
let lsp_action = serde_json::from_slice(&action.lsp_action)?;
|
let lsp_action = serde_json::from_slice(&action.lsp_action)?;
|
||||||
Ok(CodeAction {
|
Ok(CodeAction {
|
||||||
|
server_id: action.server_id as usize,
|
||||||
range: start..end,
|
range: start..end,
|
||||||
lsp_action,
|
lsp_action,
|
||||||
})
|
})
|
||||||
|
|
|
@ -33,21 +33,25 @@ pub(crate) trait LspCommand: 'static + Sized {
|
||||||
language_server: &Arc<LanguageServer>,
|
language_server: &Arc<LanguageServer>,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> <Self::LspRequest as lsp::request::Request>::Params;
|
) -> <Self::LspRequest as lsp::request::Request>::Params;
|
||||||
|
|
||||||
async fn response_from_lsp(
|
async fn response_from_lsp(
|
||||||
self,
|
self,
|
||||||
message: <Self::LspRequest as lsp::request::Request>::Result,
|
message: <Self::LspRequest as lsp::request::Request>::Result,
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
server_id: usize,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
) -> Result<Self::Response>;
|
) -> Result<Self::Response>;
|
||||||
|
|
||||||
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;
|
||||||
|
|
||||||
async fn from_proto(
|
async fn from_proto(
|
||||||
message: Self::ProtoRequest,
|
message: Self::ProtoRequest,
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
) -> Result<Self>;
|
) -> Result<Self>;
|
||||||
|
|
||||||
fn response_to_proto(
|
fn response_to_proto(
|
||||||
response: Self::Response,
|
response: Self::Response,
|
||||||
project: &mut Project,
|
project: &mut Project,
|
||||||
|
@ -55,6 +59,7 @@ pub(crate) trait LspCommand: 'static + Sized {
|
||||||
buffer_version: &clock::Global,
|
buffer_version: &clock::Global,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
|
) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
|
||||||
|
|
||||||
async fn response_from_proto(
|
async fn response_from_proto(
|
||||||
self,
|
self,
|
||||||
message: <Self::ProtoRequest as proto::RequestMessage>::Response,
|
message: <Self::ProtoRequest as proto::RequestMessage>::Response,
|
||||||
|
@ -62,6 +67,7 @@ pub(crate) trait LspCommand: 'static + Sized {
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
) -> Result<Self::Response>;
|
) -> Result<Self::Response>;
|
||||||
|
|
||||||
fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64;
|
fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +143,7 @@ impl LspCommand for PrepareRename {
|
||||||
message: Option<lsp::PrepareRenameResponse>,
|
message: Option<lsp::PrepareRenameResponse>,
|
||||||
_: ModelHandle<Project>,
|
_: ModelHandle<Project>,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
_: usize,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
) -> Result<Option<Range<Anchor>>> {
|
) -> Result<Option<Range<Anchor>>> {
|
||||||
buffer.read_with(&cx, |buffer, _| {
|
buffer.read_with(&cx, |buffer, _| {
|
||||||
|
@ -263,10 +270,12 @@ impl LspCommand for PerformRename {
|
||||||
message: Option<lsp::WorkspaceEdit>,
|
message: Option<lsp::WorkspaceEdit>,
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
server_id: usize,
|
||||||
mut cx: AsyncAppContext,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<ProjectTransaction> {
|
) -> Result<ProjectTransaction> {
|
||||||
if let Some(edit) = message {
|
if let Some(edit) = message {
|
||||||
let (lsp_adapter, lsp_server) = language_server_for_buffer(&project, &buffer, &mut cx)?;
|
let (lsp_adapter, lsp_server) =
|
||||||
|
language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
|
||||||
Project::deserialize_workspace_edit(
|
Project::deserialize_workspace_edit(
|
||||||
project,
|
project,
|
||||||
edit,
|
edit,
|
||||||
|
@ -380,9 +389,10 @@ impl LspCommand for GetDefinition {
|
||||||
message: Option<lsp::GotoDefinitionResponse>,
|
message: Option<lsp::GotoDefinitionResponse>,
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
server_id: usize,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
) -> Result<Vec<LocationLink>> {
|
) -> Result<Vec<LocationLink>> {
|
||||||
location_links_from_lsp(message, project, buffer, cx).await
|
location_links_from_lsp(message, project, buffer, server_id, cx).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
|
||||||
|
@ -472,9 +482,10 @@ impl LspCommand for GetTypeDefinition {
|
||||||
message: Option<lsp::GotoTypeDefinitionResponse>,
|
message: Option<lsp::GotoTypeDefinitionResponse>,
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
server_id: usize,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
) -> Result<Vec<LocationLink>> {
|
) -> Result<Vec<LocationLink>> {
|
||||||
location_links_from_lsp(message, project, buffer, cx).await
|
location_links_from_lsp(message, project, buffer, server_id, cx).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
|
||||||
|
@ -537,12 +548,13 @@ impl LspCommand for GetTypeDefinition {
|
||||||
fn language_server_for_buffer(
|
fn language_server_for_buffer(
|
||||||
project: &ModelHandle<Project>,
|
project: &ModelHandle<Project>,
|
||||||
buffer: &ModelHandle<Buffer>,
|
buffer: &ModelHandle<Buffer>,
|
||||||
|
server_id: usize,
|
||||||
cx: &mut AsyncAppContext,
|
cx: &mut AsyncAppContext,
|
||||||
) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
|
) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
|
||||||
project
|
project
|
||||||
.read_with(cx, |project, cx| {
|
.read_with(cx, |project, cx| {
|
||||||
project
|
project
|
||||||
.language_server_for_buffer(buffer.read(cx), cx)
|
.language_server_for_buffer(buffer.read(cx), server_id, cx)
|
||||||
.map(|(adapter, server)| (adapter.clone(), server.clone()))
|
.map(|(adapter, server)| (adapter.clone(), server.clone()))
|
||||||
})
|
})
|
||||||
.ok_or_else(|| anyhow!("no language server found for buffer"))
|
.ok_or_else(|| anyhow!("no language server found for buffer"))
|
||||||
|
@ -614,6 +626,7 @@ async fn location_links_from_lsp(
|
||||||
message: Option<lsp::GotoDefinitionResponse>,
|
message: Option<lsp::GotoDefinitionResponse>,
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
server_id: usize,
|
||||||
mut cx: AsyncAppContext,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<Vec<LocationLink>> {
|
) -> Result<Vec<LocationLink>> {
|
||||||
let message = match message {
|
let message = match message {
|
||||||
|
@ -642,7 +655,8 @@ async fn location_links_from_lsp(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (lsp_adapter, language_server) = language_server_for_buffer(&project, &buffer, &mut cx)?;
|
let (lsp_adapter, language_server) =
|
||||||
|
language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
|
||||||
let mut definitions = Vec::new();
|
let mut definitions = Vec::new();
|
||||||
for (origin_range, target_uri, target_range) in unresolved_links {
|
for (origin_range, target_uri, target_range) in unresolved_links {
|
||||||
let target_buffer_handle = project
|
let target_buffer_handle = project
|
||||||
|
@ -756,11 +770,12 @@ impl LspCommand for GetReferences {
|
||||||
locations: Option<Vec<lsp::Location>>,
|
locations: Option<Vec<lsp::Location>>,
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
server_id: usize,
|
||||||
mut cx: AsyncAppContext,
|
mut cx: AsyncAppContext,
|
||||||
) -> Result<Vec<Location>> {
|
) -> Result<Vec<Location>> {
|
||||||
let mut references = Vec::new();
|
let mut references = Vec::new();
|
||||||
let (lsp_adapter, language_server) =
|
let (lsp_adapter, language_server) =
|
||||||
language_server_for_buffer(&project, &buffer, &mut cx)?;
|
language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
|
||||||
|
|
||||||
if let Some(locations) = locations {
|
if let Some(locations) = locations {
|
||||||
for lsp_location in locations {
|
for lsp_location in locations {
|
||||||
|
@ -917,6 +932,7 @@ impl LspCommand for GetDocumentHighlights {
|
||||||
lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
|
lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
|
||||||
_: ModelHandle<Project>,
|
_: ModelHandle<Project>,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
_: usize,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
) -> Result<Vec<DocumentHighlight>> {
|
) -> Result<Vec<DocumentHighlight>> {
|
||||||
buffer.read_with(&cx, |buffer, _| {
|
buffer.read_with(&cx, |buffer, _| {
|
||||||
|
@ -1062,6 +1078,7 @@ impl LspCommand for GetHover {
|
||||||
message: Option<lsp::Hover>,
|
message: Option<lsp::Hover>,
|
||||||
_: ModelHandle<Project>,
|
_: ModelHandle<Project>,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
_: usize,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
) -> Result<Self::Response> {
|
) -> Result<Self::Response> {
|
||||||
Ok(message.and_then(|hover| {
|
Ok(message.and_then(|hover| {
|
||||||
|
@ -1283,6 +1300,7 @@ impl LspCommand for GetCompletions {
|
||||||
completions: Option<lsp::CompletionResponse>,
|
completions: Option<lsp::CompletionResponse>,
|
||||||
_: ModelHandle<Project>,
|
_: ModelHandle<Project>,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
_: usize,
|
||||||
cx: AsyncAppContext,
|
cx: AsyncAppContext,
|
||||||
) -> Result<Vec<Completion>> {
|
) -> Result<Vec<Completion>> {
|
||||||
let completions = if let Some(completions) = completions {
|
let completions = if let Some(completions) = completions {
|
||||||
|
@ -1502,6 +1520,7 @@ impl LspCommand for GetCodeActions {
|
||||||
actions: Option<lsp::CodeActionResponse>,
|
actions: Option<lsp::CodeActionResponse>,
|
||||||
_: ModelHandle<Project>,
|
_: ModelHandle<Project>,
|
||||||
_: ModelHandle<Buffer>,
|
_: ModelHandle<Buffer>,
|
||||||
|
server_id: usize,
|
||||||
_: AsyncAppContext,
|
_: AsyncAppContext,
|
||||||
) -> Result<Vec<CodeAction>> {
|
) -> Result<Vec<CodeAction>> {
|
||||||
Ok(actions
|
Ok(actions
|
||||||
|
@ -1510,6 +1529,7 @@ impl LspCommand for GetCodeActions {
|
||||||
.filter_map(|entry| {
|
.filter_map(|entry| {
|
||||||
if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
|
if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
|
||||||
Some(CodeAction {
|
Some(CodeAction {
|
||||||
|
server_id,
|
||||||
range: self.range.clone(),
|
range: self.range.clone(),
|
||||||
lsp_action,
|
lsp_action,
|
||||||
})
|
})
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1573,6 +1573,7 @@ async fn test_edits_from_lsp_with_past_version(cx: &mut gpui::TestAppContext) {
|
||||||
new_text: "".into(),
|
new_text: "".into(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
0,
|
||||||
Some(lsp_document_version),
|
Some(lsp_document_version),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -1667,6 +1668,7 @@ async fn test_edits_from_lsp_with_edits_on_adjacent_lines(cx: &mut gpui::TestApp
|
||||||
new_text: "".into(),
|
new_text: "".into(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
0,
|
||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -1770,6 +1772,7 @@ async fn test_invalid_edits_from_lsp(cx: &mut gpui::TestAppContext) {
|
||||||
.unindent(),
|
.unindent(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
0,
|
||||||
None,
|
None,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -2258,7 +2261,7 @@ async fn test_save_as(cx: &mut gpui::TestAppContext) {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
tree_sitter_rust::language(),
|
tree_sitter_rust::language(),
|
||||||
None,
|
vec![],
|
||||||
|_| Default::default(),
|
|_| Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -684,9 +684,10 @@ message SearchProjectResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
message CodeAction {
|
message CodeAction {
|
||||||
Anchor start = 1;
|
uint64 server_id = 1;
|
||||||
Anchor end = 2;
|
Anchor start = 2;
|
||||||
bytes lsp_action = 3;
|
Anchor end = 3;
|
||||||
|
bytes lsp_action = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ProjectTransaction {
|
message ProjectTransaction {
|
||||||
|
|
|
@ -37,121 +37,107 @@ pub fn init(
|
||||||
themes: Arc<ThemeRegistry>,
|
themes: Arc<ThemeRegistry>,
|
||||||
node_runtime: Arc<NodeRuntime>,
|
node_runtime: Arc<NodeRuntime>,
|
||||||
) {
|
) {
|
||||||
for (name, grammar, lsp_adapter) in [
|
fn adapter_arc(adapter: impl LspAdapter) -> Arc<dyn LspAdapter> {
|
||||||
|
Arc::new(adapter)
|
||||||
|
}
|
||||||
|
|
||||||
|
let languages_list = [
|
||||||
(
|
(
|
||||||
"c",
|
"c",
|
||||||
tree_sitter_c::language(),
|
tree_sitter_c::language(),
|
||||||
Some(Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>),
|
vec![adapter_arc(c::CLspAdapter)],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"cpp",
|
"cpp",
|
||||||
tree_sitter_cpp::language(),
|
tree_sitter_cpp::language(),
|
||||||
Some(Arc::new(c::CLspAdapter)),
|
vec![adapter_arc(c::CLspAdapter)],
|
||||||
),
|
|
||||||
(
|
|
||||||
"css",
|
|
||||||
tree_sitter_css::language(),
|
|
||||||
None, //
|
|
||||||
),
|
),
|
||||||
|
("css", tree_sitter_css::language(), vec![]),
|
||||||
(
|
(
|
||||||
"elixir",
|
"elixir",
|
||||||
tree_sitter_elixir::language(),
|
tree_sitter_elixir::language(),
|
||||||
Some(Arc::new(elixir::ElixirLspAdapter)),
|
vec![adapter_arc(elixir::ElixirLspAdapter)],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"go",
|
"go",
|
||||||
tree_sitter_go::language(),
|
tree_sitter_go::language(),
|
||||||
Some(Arc::new(go::GoLspAdapter)),
|
vec![adapter_arc(go::GoLspAdapter)],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"json",
|
"json",
|
||||||
tree_sitter_json::language(),
|
tree_sitter_json::language(),
|
||||||
Some(Arc::new(json::JsonLspAdapter::new(
|
vec![adapter_arc(json::JsonLspAdapter::new(
|
||||||
node_runtime.clone(),
|
node_runtime.clone(),
|
||||||
languages.clone(),
|
languages.clone(),
|
||||||
themes.clone(),
|
themes.clone(),
|
||||||
))),
|
))],
|
||||||
),
|
|
||||||
(
|
|
||||||
"markdown",
|
|
||||||
tree_sitter_markdown::language(),
|
|
||||||
None, //
|
|
||||||
),
|
),
|
||||||
|
("markdown", tree_sitter_markdown::language(), vec![]),
|
||||||
(
|
(
|
||||||
"python",
|
"python",
|
||||||
tree_sitter_python::language(),
|
tree_sitter_python::language(),
|
||||||
Some(Arc::new(python::PythonLspAdapter::new(
|
vec![adapter_arc(python::PythonLspAdapter::new(
|
||||||
node_runtime.clone(),
|
node_runtime.clone(),
|
||||||
))),
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"rust",
|
"rust",
|
||||||
tree_sitter_rust::language(),
|
tree_sitter_rust::language(),
|
||||||
Some(Arc::new(rust::RustLspAdapter)),
|
vec![adapter_arc(rust::RustLspAdapter)],
|
||||||
),
|
|
||||||
(
|
|
||||||
"toml",
|
|
||||||
tree_sitter_toml::language(),
|
|
||||||
None, //
|
|
||||||
),
|
),
|
||||||
|
("toml", tree_sitter_toml::language(), vec![]),
|
||||||
(
|
(
|
||||||
"tsx",
|
"tsx",
|
||||||
tree_sitter_typescript::language_tsx(),
|
tree_sitter_typescript::language_tsx(),
|
||||||
Some(Arc::new(typescript::TypeScriptLspAdapter::new(
|
vec![adapter_arc(typescript::TypeScriptLspAdapter::new(
|
||||||
node_runtime.clone(),
|
node_runtime.clone(),
|
||||||
))),
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"typescript",
|
"typescript",
|
||||||
tree_sitter_typescript::language_typescript(),
|
tree_sitter_typescript::language_typescript(),
|
||||||
Some(Arc::new(typescript::TypeScriptLspAdapter::new(
|
vec![adapter_arc(typescript::TypeScriptLspAdapter::new(
|
||||||
node_runtime.clone(),
|
node_runtime.clone(),
|
||||||
))),
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"javascript",
|
"javascript",
|
||||||
tree_sitter_typescript::language_tsx(),
|
tree_sitter_typescript::language_tsx(),
|
||||||
Some(Arc::new(typescript::TypeScriptLspAdapter::new(
|
vec![adapter_arc(typescript::TypeScriptLspAdapter::new(
|
||||||
node_runtime.clone(),
|
node_runtime.clone(),
|
||||||
))),
|
))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"html",
|
"html",
|
||||||
tree_sitter_html::language(),
|
tree_sitter_html::language(),
|
||||||
Some(Arc::new(html::HtmlLspAdapter::new(node_runtime.clone()))),
|
vec![adapter_arc(html::HtmlLspAdapter::new(node_runtime.clone()))],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"ruby",
|
"ruby",
|
||||||
tree_sitter_ruby::language(),
|
tree_sitter_ruby::language(),
|
||||||
Some(Arc::new(ruby::RubyLanguageServer)),
|
vec![adapter_arc(ruby::RubyLanguageServer)],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"erb",
|
"erb",
|
||||||
tree_sitter_embedded_template::language(),
|
tree_sitter_embedded_template::language(),
|
||||||
Some(Arc::new(ruby::RubyLanguageServer)),
|
vec![adapter_arc(ruby::RubyLanguageServer)],
|
||||||
),
|
|
||||||
(
|
|
||||||
"scheme",
|
|
||||||
tree_sitter_scheme::language(),
|
|
||||||
None, //
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"racket",
|
|
||||||
tree_sitter_racket::language(),
|
|
||||||
None, //
|
|
||||||
),
|
),
|
||||||
|
("scheme", tree_sitter_scheme::language(), vec![]),
|
||||||
|
("racket", tree_sitter_racket::language(), vec![]),
|
||||||
(
|
(
|
||||||
"lua",
|
"lua",
|
||||||
tree_sitter_lua::language(),
|
tree_sitter_lua::language(),
|
||||||
Some(Arc::new(lua::LuaLspAdapter)),
|
vec![adapter_arc(lua::LuaLspAdapter)],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"yaml",
|
"yaml",
|
||||||
tree_sitter_yaml::language(),
|
tree_sitter_yaml::language(),
|
||||||
Some(Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))),
|
vec![adapter_arc(yaml::YamlLspAdapter::new(node_runtime.clone()))],
|
||||||
),
|
),
|
||||||
] {
|
];
|
||||||
languages.register(name, load_config(name), grammar, lsp_adapter, load_queries);
|
|
||||||
|
for (name, grammar, lsp_adapters) in languages_list {
|
||||||
|
languages.register(name, load_config(name), grammar, lsp_adapters, load_queries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +149,7 @@ pub async fn language(
|
||||||
) -> Arc<Language> {
|
) -> Arc<Language> {
|
||||||
Arc::new(
|
Arc::new(
|
||||||
Language::new(load_config(name), Some(grammar))
|
Language::new(load_config(name), Some(grammar))
|
||||||
.with_lsp_adapter(lsp_adapter)
|
.with_lsp_adapters(lsp_adapter)
|
||||||
.await
|
.await
|
||||||
.with_queries(load_queries(name))
|
.with_queries(load_queries(name))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
|
|
@ -37,7 +37,7 @@ impl TypeScriptLspAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Versions {
|
struct TypeScriptVersions {
|
||||||
typescript_version: String,
|
typescript_version: String,
|
||||||
server_version: String,
|
server_version: String,
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,8 @@ impl LspAdapter for TypeScriptLspAdapter {
|
||||||
&self,
|
&self,
|
||||||
_: Arc<dyn HttpClient>,
|
_: Arc<dyn HttpClient>,
|
||||||
) -> Result<Box<dyn 'static + Send + Any>> {
|
) -> Result<Box<dyn 'static + Send + Any>> {
|
||||||
Ok(Box::new(Versions {
|
dbg!();
|
||||||
|
Ok(Box::new(TypeScriptVersions {
|
||||||
typescript_version: self.node.npm_package_latest_version("typescript").await?,
|
typescript_version: self.node.npm_package_latest_version("typescript").await?,
|
||||||
server_version: self
|
server_version: self
|
||||||
.node
|
.node
|
||||||
|
@ -67,7 +68,8 @@ impl LspAdapter for TypeScriptLspAdapter {
|
||||||
_: Arc<dyn HttpClient>,
|
_: Arc<dyn HttpClient>,
|
||||||
container_dir: PathBuf,
|
container_dir: PathBuf,
|
||||||
) -> Result<LanguageServerBinary> {
|
) -> Result<LanguageServerBinary> {
|
||||||
let versions = versions.downcast::<Versions>().unwrap();
|
dbg!();
|
||||||
|
let versions = versions.downcast::<TypeScriptVersions>().unwrap();
|
||||||
let server_path = container_dir.join(Self::NEW_SERVER_PATH);
|
let server_path = container_dir.join(Self::NEW_SERVER_PATH);
|
||||||
|
|
||||||
if fs::metadata(&server_path).await.is_err() {
|
if fs::metadata(&server_path).await.is_err() {
|
||||||
|
@ -92,18 +94,10 @@ impl LspAdapter for TypeScriptLspAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
|
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
|
||||||
|
dbg!();
|
||||||
(|| async move {
|
(|| async move {
|
||||||
let mut last_version_dir = None;
|
let old_server_path = container_dir.join(Self::OLD_SERVER_PATH);
|
||||||
let mut entries = fs::read_dir(&container_dir).await?;
|
let new_server_path = container_dir.join(Self::NEW_SERVER_PATH);
|
||||||
while let Some(entry) = entries.next().await {
|
|
||||||
let entry = entry?;
|
|
||||||
if entry.file_type().await?.is_dir() {
|
|
||||||
last_version_dir = Some(entry.path());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
|
|
||||||
let old_server_path = last_version_dir.join(Self::OLD_SERVER_PATH);
|
|
||||||
let new_server_path = last_version_dir.join(Self::NEW_SERVER_PATH);
|
|
||||||
if new_server_path.exists() {
|
if new_server_path.exists() {
|
||||||
Ok(LanguageServerBinary {
|
Ok(LanguageServerBinary {
|
||||||
path: self.node.binary_path().await?,
|
path: self.node.binary_path().await?,
|
||||||
|
@ -117,7 +111,7 @@ impl LspAdapter for TypeScriptLspAdapter {
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!(
|
Err(anyhow!(
|
||||||
"missing executable in directory {:?}",
|
"missing executable in directory {:?}",
|
||||||
last_version_dir
|
container_dir
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
@ -170,6 +164,86 @@ impl LspAdapter for TypeScriptLspAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct EsLintLspAdapter {
|
||||||
|
node: Arc<NodeRuntime>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EsLintLspAdapter {
|
||||||
|
const SERVER_PATH: &'static str = "node_modules/typescript-language-server/lib/cli.mjs";
|
||||||
|
|
||||||
|
pub fn new(node: Arc<NodeRuntime>) -> Self {
|
||||||
|
EsLintLspAdapter { node }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl LspAdapter for EsLintLspAdapter {
|
||||||
|
async fn name(&self) -> LanguageServerName {
|
||||||
|
LanguageServerName("eslint".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_latest_server_version(
|
||||||
|
&self,
|
||||||
|
_: Arc<dyn HttpClient>,
|
||||||
|
) -> Result<Box<dyn 'static + Send + Any>> {
|
||||||
|
Ok(Box::new(
|
||||||
|
self.node.npm_package_latest_version("eslint").await?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_server_binary(
|
||||||
|
&self,
|
||||||
|
versions: Box<dyn 'static + Send + Any>,
|
||||||
|
_: Arc<dyn HttpClient>,
|
||||||
|
container_dir: PathBuf,
|
||||||
|
) -> Result<LanguageServerBinary> {
|
||||||
|
let version = versions.downcast::<String>().unwrap();
|
||||||
|
let server_path = container_dir.join(Self::SERVER_PATH);
|
||||||
|
|
||||||
|
if fs::metadata(&server_path).await.is_err() {
|
||||||
|
self.node
|
||||||
|
.npm_install_packages([("eslint", version.as_str())], &container_dir)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(LanguageServerBinary {
|
||||||
|
path: self.node.binary_path().await?,
|
||||||
|
arguments: server_binary_arguments(&server_path),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
|
||||||
|
(|| async move {
|
||||||
|
let server_path = container_dir.join(Self::SERVER_PATH);
|
||||||
|
if server_path.exists() {
|
||||||
|
Ok(LanguageServerBinary {
|
||||||
|
path: self.node.binary_path().await?,
|
||||||
|
arguments: server_binary_arguments(&server_path),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(anyhow!(
|
||||||
|
"missing executable in directory {:?}",
|
||||||
|
container_dir
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
.await
|
||||||
|
.log_err()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn label_for_completion(
|
||||||
|
&self,
|
||||||
|
item: &lsp::CompletionItem,
|
||||||
|
language: &Arc<language::Language>,
|
||||||
|
) -> Option<language::CodeLabel> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn initialization_options(&self) -> Option<serde_json::Value> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use gpui::TestAppContext;
|
use gpui::TestAppContext;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue