Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #13785 - Veykril:run-flycheck, r=Veykril
Add command for manually running flychecks Closes https://github.com/rust-lang/rust-analyzer/issues/13125
bors 2022-12-17
parent 19c2ede · parent a04feb9 · commit e0aa5af
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs13
-rw-r--r--crates/rust-analyzer/src/main_loop.rs173
-rw-r--r--docs/dev/lsp-extensions.md2
-rw-r--r--editors/code/package.json5
-rw-r--r--editors/code/src/commands.ts15
-rw-r--r--editors/code/src/lsp_ext.ts4
-rw-r--r--editors/code/src/main.ts1
7 files changed, 133 insertions, 80 deletions
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index a1df0b6d7d..a2d539cf6c 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -138,6 +138,19 @@ impl Request for CancelFlycheck {
const METHOD: &'static str = "rust-analyzer/cancelFlycheck";
}
+pub enum RunFlycheck {}
+
+impl Notification for RunFlycheck {
+ type Params = RunFlycheckParams;
+ const METHOD: &'static str = "rust-analyzer/runFlycheck";
+}
+
+#[derive(Deserialize, Serialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct RunFlycheckParams {
+ pub text_document: Option<TextDocumentIdentifier>,
+}
+
pub enum MatchingBrace {}
impl Request for MatchingBrace {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 274588ce0e..d979317b21 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -703,6 +703,88 @@ impl GlobalState {
/// Handles an incoming notification.
fn on_notification(&mut self, not: Notification) -> Result<()> {
+ // FIXME: Move these implementations out into a module similar to on_request
+ fn run_flycheck(this: &mut GlobalState, vfs_path: VfsPath) -> bool {
+ let file_id = this.vfs.read().0.file_id(&vfs_path);
+ if let Some(file_id) = file_id {
+ let world = this.snapshot();
+ let mut updated = false;
+ let task = move || -> std::result::Result<(), ide::Cancelled> {
+ // Trigger flychecks for all workspaces that depend on the saved file
+ // Crates containing or depending on the saved file
+ let crate_ids: Vec<_> = world
+ .analysis
+ .crates_for(file_id)?
+ .into_iter()
+ .flat_map(|id| world.analysis.transitive_rev_deps(id))
+ .flatten()
+ .sorted()
+ .unique()
+ .collect();
+
+ let crate_root_paths: Vec<_> = crate_ids
+ .iter()
+ .filter_map(|&crate_id| {
+ world
+ .analysis
+ .crate_root(crate_id)
+ .map(|file_id| {
+ world
+ .file_id_to_file_path(file_id)
+ .as_path()
+ .map(ToOwned::to_owned)
+ })
+ .transpose()
+ })
+ .collect::<ide::Cancellable<_>>()?;
+ let crate_root_paths: Vec<_> =
+ crate_root_paths.iter().map(Deref::deref).collect();
+
+ // Find all workspaces that have at least one target containing the saved file
+ let workspace_ids =
+ world.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
+ project_model::ProjectWorkspace::Cargo { cargo, .. } => {
+ cargo.packages().any(|pkg| {
+ cargo[pkg].targets.iter().any(|&it| {
+ crate_root_paths.contains(&cargo[it].root.as_path())
+ })
+ })
+ }
+ project_model::ProjectWorkspace::Json { project, .. } => project
+ .crates()
+ .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)),
+ project_model::ProjectWorkspace::DetachedFiles { .. } => false,
+ });
+
+ // Find and trigger corresponding flychecks
+ for flycheck in world.flycheck.iter() {
+ for (id, _) in workspace_ids.clone() {
+ if id == flycheck.id() {
+ updated = true;
+ flycheck.restart();
+ continue;
+ }
+ }
+ }
+ // No specific flycheck was triggered, so let's trigger all of them.
+ if !updated {
+ for flycheck in world.flycheck.iter() {
+ flycheck.restart();
+ }
+ }
+ Ok(())
+ };
+ this.task_pool.handle.spawn_with_sender(move |_| {
+ if let Err(e) = std::panic::catch_unwind(task) {
+ tracing::error!("flycheck task panicked: {e:?}")
+ }
+ });
+ true
+ } else {
+ false
+ }
+ }
+
NotificationDispatcher { not: Some(not), global_state: self }
.on::<lsp_types::notification::Cancel>(|this, params| {
let id: lsp_server::RequestId = match params.id {
@@ -782,6 +864,20 @@ impl GlobalState {
}
Ok(())
})?
+ .on::<lsp_ext::RunFlycheck>(|this, params| {
+ if let Some(text_document) = params.text_document {
+ if let Ok(vfs_path) = from_proto::vfs_path(&text_document.uri) {
+ if run_flycheck(this, vfs_path) {
+ return Ok(());
+ }
+ }
+ }
+ // No specific flycheck was triggered, so let's trigger all of them.
+ for flycheck in this.flycheck.iter() {
+ flycheck.restart();
+ }
+ Ok(())
+ })?
.on::<lsp_types::notification::DidSaveTextDocument>(|this, params| {
if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
// Re-fetch workspaces if a workspace related file has changed
@@ -792,82 +888,7 @@ impl GlobalState {
}
}
- let file_id = this.vfs.read().0.file_id(&vfs_path);
- if let Some(file_id) = file_id {
- let world = this.snapshot();
- let mut updated = false;
- let task = move || -> std::result::Result<(), ide::Cancelled> {
- // Trigger flychecks for all workspaces that depend on the saved file
- // Crates containing or depending on the saved file
- let crate_ids: Vec<_> = world
- .analysis
- .crates_for(file_id)?
- .into_iter()
- .flat_map(|id| world.analysis.transitive_rev_deps(id))
- .flatten()
- .sorted()
- .unique()
- .collect();
-
- let crate_root_paths: Vec<_> = crate_ids
- .iter()
- .filter_map(|&crate_id| {
- world
- .analysis
- .crate_root(crate_id)
- .map(|file_id| {
- world
- .file_id_to_file_path(file_id)
- .as_path()
- .map(ToOwned::to_owned)
- })
- .transpose()
- })
- .collect::<ide::Cancellable<_>>()?;
- let crate_root_paths: Vec<_> =
- crate_root_paths.iter().map(Deref::deref).collect();
-
- // Find all workspaces that have at least one target containing the saved file
- let workspace_ids =
- world.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
- project_model::ProjectWorkspace::Cargo { cargo, .. } => {
- cargo.packages().any(|pkg| {
- cargo[pkg].targets.iter().any(|&it| {
- crate_root_paths.contains(&cargo[it].root.as_path())
- })
- })
- }
- project_model::ProjectWorkspace::Json { project, .. } => {
- project.crates().any(|(c, _)| {
- crate_ids.iter().any(|&crate_id| crate_id == c)
- })
- }
- project_model::ProjectWorkspace::DetachedFiles { .. } => false,
- });
-
- // Find and trigger corresponding flychecks
- for flycheck in world.flycheck.iter() {
- for (id, _) in workspace_ids.clone() {
- if id == flycheck.id() {
- updated = true;
- flycheck.restart();
- continue;
- }
- }
- }
- // No specific flycheck was triggered, so let's trigger all of them.
- if !updated {
- for flycheck in world.flycheck.iter() {
- flycheck.restart();
- }
- }
- Ok(())
- };
- this.task_pool.handle.spawn_with_sender(move |_| {
- if let Err(e) = std::panic::catch_unwind(task) {
- tracing::error!("DidSaveTextDocument flycheck task panicked: {e:?}")
- }
- });
+ if run_flycheck(this, vfs_path) {
return Ok(());
}
}
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 5aced035d5..308a92bebe 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
<!---
-lsp_ext.rs hash: 61fe425627f9baaa
+lsp_ext.rs hash: 1cb29d3afa36e743
If you need to change the above hash to make the test pass, please check if you
need to adjust this doc as well and ping this issue:
diff --git a/editors/code/package.json b/editors/code/package.json
index 5b83701a68..bfaad1edce 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -246,6 +246,11 @@
"command": "rust-analyzer.cancelFlycheck",
"title": "Cancel running flychecks",
"category": "rust-analyzer"
+ },
+ {
+ "command": "rust-analyzer.runFlycheck",
+ "title": "Run flycheck",
+ "category": "rust-analyzer"
}
],
"keybindings": [
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 312087e4cf..e0b4bb63c3 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -788,8 +788,17 @@ export function openDocs(ctx: CtxInit): Cmd {
export function cancelFlycheck(ctx: CtxInit): Cmd {
return async () => {
+ await ctx.client.sendRequest(ra.cancelFlycheck);
+ };
+}
+
+export function runFlycheck(ctx: CtxInit): Cmd {
+ return async () => {
+ const editor = ctx.activeRustEditor;
const client = ctx.client;
- await client.sendRequest(ra.cancelFlycheck);
+ const params = editor ? { uri: editor.document.uri.toString() } : null;
+
+ await client.sendNotification(ra.runFlycheck, { textDocument: params });
};
}
@@ -797,12 +806,12 @@ export function resolveCodeAction(ctx: CtxInit): Cmd {
return async (params: lc.CodeAction) => {
const client = ctx.client;
params.command = undefined;
- const item = await client?.sendRequest(lc.CodeActionResolveRequest.type, params);
+ const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params);
if (!item?.edit) {
return;
}
const itemEdit = item.edit;
- const edit = await client?.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
+ const edit = await client.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
// filter out all text edits and recreate the WorkspaceEdit without them so we can apply
// snippet edits on our own
const lcFileSystemEdit = {
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index 875261c48a..78da4e959c 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -81,6 +81,10 @@ export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, Te
export const cancelFlycheck = new lc.RequestType0<void, void>("rust-analyzer/cancelFlycheck");
+export const runFlycheck = new lc.NotificationType<{
+ textDocument: lc.TextDocumentIdentifier | null;
+}>("rust-analyzer/runFlycheck");
+
// Experimental extensions
export interface SsrParams {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 01a1a2db7f..c5fc44b4f9 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -150,6 +150,7 @@ function createCommands(): Record<string, CommandFactory> {
moveItemUp: { enabled: commands.moveItemUp },
moveItemDown: { enabled: commands.moveItemDown },
cancelFlycheck: { enabled: commands.cancelFlycheck },
+ runFlycheck: { enabled: commands.runFlycheck },
ssr: { enabled: commands.ssr },
serverVersion: { enabled: commands.serverVersion },
// Internal commands which are invoked by the server.