mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-27 20:35:09 +00:00
Add command for manually running flychecks
This commit is contained in:
parent
ba3e3282da
commit
a04feb915a
7 changed files with 133 additions and 80 deletions
|
@ -138,6 +138,19 @@ impl Request for CancelFlycheck {
|
||||||
const METHOD: &'static str = "rust-analyzer/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 {}
|
pub enum MatchingBrace {}
|
||||||
|
|
||||||
impl Request for MatchingBrace {
|
impl Request for MatchingBrace {
|
||||||
|
|
|
@ -703,6 +703,88 @@ impl GlobalState {
|
||||||
|
|
||||||
/// Handles an incoming notification.
|
/// Handles an incoming notification.
|
||||||
fn on_notification(&mut self, not: Notification) -> Result<()> {
|
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 }
|
NotificationDispatcher { not: Some(not), global_state: self }
|
||||||
.on::<lsp_types::notification::Cancel>(|this, params| {
|
.on::<lsp_types::notification::Cancel>(|this, params| {
|
||||||
let id: lsp_server::RequestId = match params.id {
|
let id: lsp_server::RequestId = match params.id {
|
||||||
|
@ -782,6 +864,20 @@ impl GlobalState {
|
||||||
}
|
}
|
||||||
Ok(())
|
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| {
|
.on::<lsp_types::notification::DidSaveTextDocument>(|this, params| {
|
||||||
if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) {
|
if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) {
|
||||||
// Re-fetch workspaces if a workspace related file has changed
|
// 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 run_flycheck(this, 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:?}")
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
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:
|
need to adjust this doc as well and ping this issue:
|
||||||
|
|
|
@ -246,6 +246,11 @@
|
||||||
"command": "rust-analyzer.cancelFlycheck",
|
"command": "rust-analyzer.cancelFlycheck",
|
||||||
"title": "Cancel running flychecks",
|
"title": "Cancel running flychecks",
|
||||||
"category": "rust-analyzer"
|
"category": "rust-analyzer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "rust-analyzer.runFlycheck",
|
||||||
|
"title": "Run flycheck",
|
||||||
|
"category": "rust-analyzer"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"keybindings": [
|
"keybindings": [
|
||||||
|
|
|
@ -788,8 +788,17 @@ export function openDocs(ctx: CtxInit): Cmd {
|
||||||
|
|
||||||
export function cancelFlycheck(ctx: CtxInit): Cmd {
|
export function cancelFlycheck(ctx: CtxInit): Cmd {
|
||||||
return async () => {
|
return async () => {
|
||||||
|
await ctx.client.sendRequest(ra.cancelFlycheck);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runFlycheck(ctx: CtxInit): Cmd {
|
||||||
|
return async () => {
|
||||||
|
const editor = ctx.activeRustEditor;
|
||||||
const client = ctx.client;
|
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) => {
|
return async (params: lc.CodeAction) => {
|
||||||
const client = ctx.client;
|
const client = ctx.client;
|
||||||
params.command = undefined;
|
params.command = undefined;
|
||||||
const item = await client?.sendRequest(lc.CodeActionResolveRequest.type, params);
|
const item = await client.sendRequest(lc.CodeActionResolveRequest.type, params);
|
||||||
if (!item?.edit) {
|
if (!item?.edit) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const itemEdit = item.edit;
|
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
|
// filter out all text edits and recreate the WorkspaceEdit without them so we can apply
|
||||||
// snippet edits on our own
|
// snippet edits on our own
|
||||||
const lcFileSystemEdit = {
|
const lcFileSystemEdit = {
|
||||||
|
|
|
@ -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 cancelFlycheck = new lc.RequestType0<void, void>("rust-analyzer/cancelFlycheck");
|
||||||
|
|
||||||
|
export const runFlycheck = new lc.NotificationType<{
|
||||||
|
textDocument: lc.TextDocumentIdentifier | null;
|
||||||
|
}>("rust-analyzer/runFlycheck");
|
||||||
|
|
||||||
// Experimental extensions
|
// Experimental extensions
|
||||||
|
|
||||||
export interface SsrParams {
|
export interface SsrParams {
|
||||||
|
|
|
@ -150,6 +150,7 @@ function createCommands(): Record<string, CommandFactory> {
|
||||||
moveItemUp: { enabled: commands.moveItemUp },
|
moveItemUp: { enabled: commands.moveItemUp },
|
||||||
moveItemDown: { enabled: commands.moveItemDown },
|
moveItemDown: { enabled: commands.moveItemDown },
|
||||||
cancelFlycheck: { enabled: commands.cancelFlycheck },
|
cancelFlycheck: { enabled: commands.cancelFlycheck },
|
||||||
|
runFlycheck: { enabled: commands.runFlycheck },
|
||||||
ssr: { enabled: commands.ssr },
|
ssr: { enabled: commands.ssr },
|
||||||
serverVersion: { enabled: commands.serverVersion },
|
serverVersion: { enabled: commands.serverVersion },
|
||||||
// Internal commands which are invoked by the server.
|
// Internal commands which are invoked by the server.
|
||||||
|
|
Loading…
Reference in a new issue