@@ -26,6 +26,17 @@ fn is_rust_language(language: &Language) -> bool {
}
pub fn apply_related_actions(editor: &Entity<Editor>, window: &mut Window, cx: &mut App) {
+ if editor.read(cx).project().is_some_and(|project| {
+ project
+ .read(cx)
+ .language_server_statuses(cx)
+ .any(|(_, status)| status.name == RUST_ANALYZER_NAME)
+ }) {
+ register_action(editor, window, cancel_flycheck_action);
+ register_action(editor, window, run_flycheck_action);
+ register_action(editor, window, clear_flycheck_action);
+ }
+
if editor
.read(cx)
.buffer()
@@ -38,9 +49,6 @@ pub fn apply_related_actions(editor: &Entity<Editor>, window: &mut Window, cx: &
register_action(editor, window, go_to_parent_module);
register_action(editor, window, expand_macro_recursively);
register_action(editor, window, open_docs);
- register_action(editor, window, cancel_flycheck_action);
- register_action(editor, window, run_flycheck_action);
- register_action(editor, window, clear_flycheck_action);
}
}
@@ -309,7 +317,7 @@ fn cancel_flycheck_action(
let Some(project) = &editor.project else {
return;
};
- let Some(buffer_id) = editor
+ let buffer_id = editor
.selections
.disjoint_anchors()
.iter()
@@ -321,10 +329,7 @@ fn cancel_flycheck_action(
.read(cx)
.entry_id(cx)?;
project.path_for_entry(entry_id, cx)
- })
- else {
- return;
- };
+ });
cancel_flycheck(project.clone(), buffer_id, cx).detach_and_log_err(cx);
}
@@ -337,7 +342,7 @@ fn run_flycheck_action(
let Some(project) = &editor.project else {
return;
};
- let Some(buffer_id) = editor
+ let buffer_id = editor
.selections
.disjoint_anchors()
.iter()
@@ -349,10 +354,7 @@ fn run_flycheck_action(
.read(cx)
.entry_id(cx)?;
project.path_for_entry(entry_id, cx)
- })
- else {
- return;
- };
+ });
run_flycheck(project.clone(), buffer_id, cx).detach_and_log_err(cx);
}
@@ -365,7 +367,7 @@ fn clear_flycheck_action(
let Some(project) = &editor.project else {
return;
};
- let Some(buffer_id) = editor
+ let buffer_id = editor
.selections
.disjoint_anchors()
.iter()
@@ -377,9 +379,6 @@ fn clear_flycheck_action(
.read(cx)
.entry_id(cx)?;
project.path_for_entry(entry_id, cx)
- })
- else {
- return;
- };
+ });
clear_flycheck(project.clone(), buffer_id, cx).detach_and_log_err(cx);
}
@@ -1,8 +1,8 @@
use ::serde::{Deserialize, Serialize};
use anyhow::Context as _;
-use gpui::{App, Entity, Task, WeakEntity};
-use language::ServerHealth;
-use lsp::{LanguageServer, LanguageServerName};
+use gpui::{App, AsyncApp, Entity, Task, WeakEntity};
+use language::{Buffer, ServerHealth};
+use lsp::{LanguageServer, LanguageServerId, LanguageServerName};
use rpc::proto;
use crate::{LspStore, LspStoreEvent, Project, ProjectPath, lsp_store};
@@ -83,31 +83,32 @@ pub fn register_notifications(lsp_store: WeakEntity<LspStore>, language_server:
pub fn cancel_flycheck(
project: Entity<Project>,
- buffer_path: ProjectPath,
+ buffer_path: Option<ProjectPath>,
cx: &mut App,
) -> Task<anyhow::Result<()>> {
let upstream_client = project.read(cx).lsp_store().read(cx).upstream_client();
let lsp_store = project.read(cx).lsp_store();
- let buffer = project.update(cx, |project, cx| {
- project.buffer_store().update(cx, |buffer_store, cx| {
- buffer_store.open_buffer(buffer_path, cx)
+ let buffer = buffer_path.map(|buffer_path| {
+ project.update(cx, |project, cx| {
+ project.buffer_store().update(cx, |buffer_store, cx| {
+ buffer_store.open_buffer(buffer_path, cx)
+ })
})
});
cx.spawn(async move |cx| {
- let buffer = buffer.await?;
- let Some(rust_analyzer_server) = project.read_with(cx, |project, cx| {
- project.language_server_id_for_name(buffer.read(cx), &RUST_ANALYZER_NAME, cx)
- })?
+ let buffer = match buffer {
+ Some(buffer) => Some(buffer.await?),
+ None => None,
+ };
+ let Some(rust_analyzer_server) = find_rust_analyzer_server(&project, buffer.as_ref(), cx)
else {
return Ok(());
};
- let buffer_id = buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto())?;
if let Some((client, project_id)) = upstream_client {
let request = proto::LspExtCancelFlycheck {
project_id,
- buffer_id,
language_server_id: rust_analyzer_server.to_proto(),
};
client
@@ -130,28 +131,33 @@ pub fn cancel_flycheck(
pub fn run_flycheck(
project: Entity<Project>,
- buffer_path: ProjectPath,
+ buffer_path: Option<ProjectPath>,
cx: &mut App,
) -> Task<anyhow::Result<()>> {
let upstream_client = project.read(cx).lsp_store().read(cx).upstream_client();
let lsp_store = project.read(cx).lsp_store();
- let buffer = project.update(cx, |project, cx| {
- project.buffer_store().update(cx, |buffer_store, cx| {
- buffer_store.open_buffer(buffer_path, cx)
+ let buffer = buffer_path.map(|buffer_path| {
+ project.update(cx, |project, cx| {
+ project.buffer_store().update(cx, |buffer_store, cx| {
+ buffer_store.open_buffer(buffer_path, cx)
+ })
})
});
cx.spawn(async move |cx| {
- let buffer = buffer.await?;
- let Some(rust_analyzer_server) = project.read_with(cx, |project, cx| {
- project.language_server_id_for_name(buffer.read(cx), &RUST_ANALYZER_NAME, cx)
- })?
+ let buffer = match buffer {
+ Some(buffer) => Some(buffer.await?),
+ None => None,
+ };
+ let Some(rust_analyzer_server) = find_rust_analyzer_server(&project, buffer.as_ref(), cx)
else {
return Ok(());
};
- let buffer_id = buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto())?;
if let Some((client, project_id)) = upstream_client {
+ let buffer_id = buffer
+ .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
+ .transpose()?;
let request = proto::LspExtRunFlycheck {
project_id,
buffer_id,
@@ -182,31 +188,32 @@ pub fn run_flycheck(
pub fn clear_flycheck(
project: Entity<Project>,
- buffer_path: ProjectPath,
+ buffer_path: Option<ProjectPath>,
cx: &mut App,
) -> Task<anyhow::Result<()>> {
let upstream_client = project.read(cx).lsp_store().read(cx).upstream_client();
let lsp_store = project.read(cx).lsp_store();
- let buffer = project.update(cx, |project, cx| {
- project.buffer_store().update(cx, |buffer_store, cx| {
- buffer_store.open_buffer(buffer_path, cx)
+ let buffer = buffer_path.map(|buffer_path| {
+ project.update(cx, |project, cx| {
+ project.buffer_store().update(cx, |buffer_store, cx| {
+ buffer_store.open_buffer(buffer_path, cx)
+ })
})
});
cx.spawn(async move |cx| {
- let buffer = buffer.await?;
- let Some(rust_analyzer_server) = project.read_with(cx, |project, cx| {
- project.language_server_id_for_name(buffer.read(cx), &RUST_ANALYZER_NAME, cx)
- })?
+ let buffer = match buffer {
+ Some(buffer) => Some(buffer.await?),
+ None => None,
+ };
+ let Some(rust_analyzer_server) = find_rust_analyzer_server(&project, buffer.as_ref(), cx)
else {
return Ok(());
};
- let buffer_id = buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto())?;
if let Some((client, project_id)) = upstream_client {
let request = proto::LspExtClearFlycheck {
project_id,
- buffer_id,
language_server_id: rust_analyzer_server.to_proto(),
};
client
@@ -226,3 +233,40 @@ pub fn clear_flycheck(
anyhow::Ok(())
})
}
+
+fn find_rust_analyzer_server(
+ project: &Entity<Project>,
+ buffer: Option<&Entity<Buffer>>,
+ cx: &mut AsyncApp,
+) -> Option<LanguageServerId> {
+ project
+ .read_with(cx, |project, cx| {
+ buffer
+ .and_then(|buffer| {
+ project.language_server_id_for_name(buffer.read(cx), &RUST_ANALYZER_NAME, cx)
+ })
+ // If no rust-analyzer found for the current buffer (e.g. `settings.json`), fall back to the project lookup
+ // and use project's rust-analyzer if it's the only one.
+ .or_else(|| {
+ let rust_analyzer_servers = project
+ .lsp_store()
+ .read(cx)
+ .language_server_statuses
+ .iter()
+ .filter_map(|(server_id, server_status)| {
+ if server_status.name == RUST_ANALYZER_NAME {
+ Some(*server_id)
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>();
+ if rust_analyzer_servers.len() == 1 {
+ rust_analyzer_servers.first().copied()
+ } else {
+ None
+ }
+ })
+ })
+ .ok()?
+}