Skip to content

Commit e0aa5af

Browse files
committed
Auto merge of #13785 - Veykril:run-flycheck, r=Veykril
Add command for manually running flychecks Closes #13125
2 parents 19c2ede + a04feb9 commit e0aa5af

File tree

7 files changed

+133
-80
lines changed

7 files changed

+133
-80
lines changed

crates/rust-analyzer/src/lsp_ext.rs

+13
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,19 @@ impl Request for CancelFlycheck {
138138
const METHOD: &'static str = "rust-analyzer/cancelFlycheck";
139139
}
140140

141+
pub enum RunFlycheck {}
142+
143+
impl Notification for RunFlycheck {
144+
type Params = RunFlycheckParams;
145+
const METHOD: &'static str = "rust-analyzer/runFlycheck";
146+
}
147+
148+
#[derive(Deserialize, Serialize, Debug)]
149+
#[serde(rename_all = "camelCase")]
150+
pub struct RunFlycheckParams {
151+
pub text_document: Option<TextDocumentIdentifier>,
152+
}
153+
141154
pub enum MatchingBrace {}
142155

143156
impl Request for MatchingBrace {

crates/rust-analyzer/src/main_loop.rs

+97-76
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,88 @@ impl GlobalState {
703703

704704
/// Handles an incoming notification.
705705
fn on_notification(&mut self, not: Notification) -> Result<()> {
706+
// FIXME: Move these implementations out into a module similar to on_request
707+
fn run_flycheck(this: &mut GlobalState, vfs_path: VfsPath) -> bool {
708+
let file_id = this.vfs.read().0.file_id(&vfs_path);
709+
if let Some(file_id) = file_id {
710+
let world = this.snapshot();
711+
let mut updated = false;
712+
let task = move || -> std::result::Result<(), ide::Cancelled> {
713+
// Trigger flychecks for all workspaces that depend on the saved file
714+
// Crates containing or depending on the saved file
715+
let crate_ids: Vec<_> = world
716+
.analysis
717+
.crates_for(file_id)?
718+
.into_iter()
719+
.flat_map(|id| world.analysis.transitive_rev_deps(id))
720+
.flatten()
721+
.sorted()
722+
.unique()
723+
.collect();
724+
725+
let crate_root_paths: Vec<_> = crate_ids
726+
.iter()
727+
.filter_map(|&crate_id| {
728+
world
729+
.analysis
730+
.crate_root(crate_id)
731+
.map(|file_id| {
732+
world
733+
.file_id_to_file_path(file_id)
734+
.as_path()
735+
.map(ToOwned::to_owned)
736+
})
737+
.transpose()
738+
})
739+
.collect::<ide::Cancellable<_>>()?;
740+
let crate_root_paths: Vec<_> =
741+
crate_root_paths.iter().map(Deref::deref).collect();
742+
743+
// Find all workspaces that have at least one target containing the saved file
744+
let workspace_ids =
745+
world.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
746+
project_model::ProjectWorkspace::Cargo { cargo, .. } => {
747+
cargo.packages().any(|pkg| {
748+
cargo[pkg].targets.iter().any(|&it| {
749+
crate_root_paths.contains(&cargo[it].root.as_path())
750+
})
751+
})
752+
}
753+
project_model::ProjectWorkspace::Json { project, .. } => project
754+
.crates()
755+
.any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)),
756+
project_model::ProjectWorkspace::DetachedFiles { .. } => false,
757+
});
758+
759+
// Find and trigger corresponding flychecks
760+
for flycheck in world.flycheck.iter() {
761+
for (id, _) in workspace_ids.clone() {
762+
if id == flycheck.id() {
763+
updated = true;
764+
flycheck.restart();
765+
continue;
766+
}
767+
}
768+
}
769+
// No specific flycheck was triggered, so let's trigger all of them.
770+
if !updated {
771+
for flycheck in world.flycheck.iter() {
772+
flycheck.restart();
773+
}
774+
}
775+
Ok(())
776+
};
777+
this.task_pool.handle.spawn_with_sender(move |_| {
778+
if let Err(e) = std::panic::catch_unwind(task) {
779+
tracing::error!("flycheck task panicked: {e:?}")
780+
}
781+
});
782+
true
783+
} else {
784+
false
785+
}
786+
}
787+
706788
NotificationDispatcher { not: Some(not), global_state: self }
707789
.on::<lsp_types::notification::Cancel>(|this, params| {
708790
let id: lsp_server::RequestId = match params.id {
@@ -782,6 +864,20 @@ impl GlobalState {
782864
}
783865
Ok(())
784866
})?
867+
.on::<lsp_ext::RunFlycheck>(|this, params| {
868+
if let Some(text_document) = params.text_document {
869+
if let Ok(vfs_path) = from_proto::vfs_path(&text_document.uri) {
870+
if run_flycheck(this, vfs_path) {
871+
return Ok(());
872+
}
873+
}
874+
}
875+
// No specific flycheck was triggered, so let's trigger all of them.
876+
for flycheck in this.flycheck.iter() {
877+
flycheck.restart();
878+
}
879+
Ok(())
880+
})?
785881
.on::<lsp_types::notification::DidSaveTextDocument>(|this, params| {
786882
if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
787883
// Re-fetch workspaces if a workspace related file has changed
@@ -792,82 +888,7 @@ impl GlobalState {
792888
}
793889
}
794890

795-
let file_id = this.vfs.read().0.file_id(&vfs_path);
796-
if let Some(file_id) = file_id {
797-
let world = this.snapshot();
798-
let mut updated = false;
799-
let task = move || -> std::result::Result<(), ide::Cancelled> {
800-
// Trigger flychecks for all workspaces that depend on the saved file
801-
// Crates containing or depending on the saved file
802-
let crate_ids: Vec<_> = world
803-
.analysis
804-
.crates_for(file_id)?
805-
.into_iter()
806-
.flat_map(|id| world.analysis.transitive_rev_deps(id))
807-
.flatten()
808-
.sorted()
809-
.unique()
810-
.collect();
811-
812-
let crate_root_paths: Vec<_> = crate_ids
813-
.iter()
814-
.filter_map(|&crate_id| {
815-
world
816-
.analysis
817-
.crate_root(crate_id)
818-
.map(|file_id| {
819-
world
820-
.file_id_to_file_path(file_id)
821-
.as_path()
822-
.map(ToOwned::to_owned)
823-
})
824-
.transpose()
825-
})
826-
.collect::<ide::Cancellable<_>>()?;
827-
let crate_root_paths: Vec<_> =
828-
crate_root_paths.iter().map(Deref::deref).collect();
829-
830-
// Find all workspaces that have at least one target containing the saved file
831-
let workspace_ids =
832-
world.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
833-
project_model::ProjectWorkspace::Cargo { cargo, .. } => {
834-
cargo.packages().any(|pkg| {
835-
cargo[pkg].targets.iter().any(|&it| {
836-
crate_root_paths.contains(&cargo[it].root.as_path())
837-
})
838-
})
839-
}
840-
project_model::ProjectWorkspace::Json { project, .. } => {
841-
project.crates().any(|(c, _)| {
842-
crate_ids.iter().any(|&crate_id| crate_id == c)
843-
})
844-
}
845-
project_model::ProjectWorkspace::DetachedFiles { .. } => false,
846-
});
847-
848-
// Find and trigger corresponding flychecks
849-
for flycheck in world.flycheck.iter() {
850-
for (id, _) in workspace_ids.clone() {
851-
if id == flycheck.id() {
852-
updated = true;
853-
flycheck.restart();
854-
continue;
855-
}
856-
}
857-
}
858-
// No specific flycheck was triggered, so let's trigger all of them.
859-
if !updated {
860-
for flycheck in world.flycheck.iter() {
861-
flycheck.restart();
862-
}
863-
}
864-
Ok(())
865-
};
866-
this.task_pool.handle.spawn_with_sender(move |_| {
867-
if let Err(e) = std::panic::catch_unwind(task) {
868-
tracing::error!("DidSaveTextDocument flycheck task panicked: {e:?}")
869-
}
870-
});
891+
if run_flycheck(this, vfs_path) {
871892
return Ok(());
872893
}
873894
}

docs/dev/lsp-extensions.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!---
2-
lsp_ext.rs hash: 61fe425627f9baaa
2+
lsp_ext.rs hash: 1cb29d3afa36e743
33
44
If you need to change the above hash to make the test pass, please check if you
55
need to adjust this doc as well and ping this issue:

editors/code/package.json

+5
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,11 @@
246246
"command": "rust-analyzer.cancelFlycheck",
247247
"title": "Cancel running flychecks",
248248
"category": "rust-analyzer"
249+
},
250+
{
251+
"command": "rust-analyzer.runFlycheck",
252+
"title": "Run flycheck",
253+
"category": "rust-analyzer"
249254
}
250255
],
251256
"keybindings": [

editors/code/src/commands.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -788,21 +788,30 @@ export function openDocs(ctx: CtxInit): Cmd {
788788

789789
export function cancelFlycheck(ctx: CtxInit): Cmd {
790790
return async () => {
791+
await ctx.client.sendRequest(ra.cancelFlycheck);
792+
};
793+
}
794+
795+
export function runFlycheck(ctx: CtxInit): Cmd {
796+
return async () => {
797+
const editor = ctx.activeRustEditor;
791798
const client = ctx.client;
792-
await client.sendRequest(ra.cancelFlycheck);
799+
const params = editor ? { uri: editor.document.uri.toString() } : null;
800+
801+
await client.sendNotification(ra.runFlycheck, { textDocument: params });
793802
};
794803
}
795804

796805
export function resolveCodeAction(ctx: CtxInit): Cmd {
797806
return async (params: lc.CodeAction) => {
798807
const client = ctx.client;
799808
params.command = undefined;
800-
const item = await client?.sendRequest(lc.CodeActionResolveRequest.type, params);
809+
const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params);
801810
if (!item?.edit) {
802811
return;
803812
}
804813
const itemEdit = item.edit;
805-
const edit = await client?.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
814+
const edit = await client.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
806815
// filter out all text edits and recreate the WorkspaceEdit without them so we can apply
807816
// snippet edits on our own
808817
const lcFileSystemEdit = {

editors/code/src/lsp_ext.ts

+4
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, Te
8181

8282
export const cancelFlycheck = new lc.RequestType0<void, void>("rust-analyzer/cancelFlycheck");
8383

84+
export const runFlycheck = new lc.NotificationType<{
85+
textDocument: lc.TextDocumentIdentifier | null;
86+
}>("rust-analyzer/runFlycheck");
87+
8488
// Experimental extensions
8589

8690
export interface SsrParams {

editors/code/src/main.ts

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ function createCommands(): Record<string, CommandFactory> {
150150
moveItemUp: { enabled: commands.moveItemUp },
151151
moveItemDown: { enabled: commands.moveItemDown },
152152
cancelFlycheck: { enabled: commands.cancelFlycheck },
153+
runFlycheck: { enabled: commands.runFlycheck },
153154
ssr: { enabled: commands.ssr },
154155
serverVersion: { enabled: commands.serverVersion },
155156
// Internal commands which are invoked by the server.

0 commit comments

Comments
 (0)