flycheck: initial implementation of $saved_file

If the custom command has a $saved_file placeholder, and we know the
file being saved, replace the placeholder and then run a check command.

If there's a placeholder and we don't know the saved file, do nothing.
This commit is contained in:
Wilfred Hughes 2023-10-04 10:34:34 -04:00 committed by Lukas Wirth
parent 47b4dd7273
commit cdbf54f4bd
6 changed files with 66 additions and 18 deletions

View file

@ -14,7 +14,7 @@ use std::{
use command_group::{CommandGroup, GroupChild};
use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
use paths::AbsPathBuf;
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;
use serde::Deserialize;
use stdx::process::streaming_output;
@ -102,13 +102,15 @@ impl FlycheckHandle {
}
/// Schedule a re-start of the cargo check worker to do a workspace wide check.
pub fn restart_workspace(&self) {
self.sender.send(StateChange::Restart(None)).unwrap();
pub fn restart_workspace(&self, saved_file: Option<AbsPathBuf>) {
self.sender.send(StateChange::Restart { package: None, saved_file }).unwrap();
}
/// Schedule a re-start of the cargo check worker to do a package wide check.
pub fn restart_for_package(&self, package: String) {
self.sender.send(StateChange::Restart(Some(package))).unwrap();
self.sender
.send(StateChange::Restart { package: Some(package), saved_file: None })
.unwrap();
}
/// Stop this cargo check worker.
@ -159,7 +161,7 @@ pub enum Progress {
}
enum StateChange {
Restart(Option<String>),
Restart { package: Option<String>, saved_file: Option<AbsPathBuf> },
Cancel,
}
@ -186,6 +188,8 @@ enum Event {
CheckEvent(Option<CargoMessage>),
}
const SAVED_FILE_PLACEHOLDER: &str = "$saved_file";
impl FlycheckActor {
fn new(
id: usize,
@ -221,7 +225,7 @@ impl FlycheckActor {
tracing::debug!(flycheck_id = self.id, "flycheck cancelled");
self.cancel_check_process();
}
Event::RequestStateChange(StateChange::Restart(package)) => {
Event::RequestStateChange(StateChange::Restart { package, saved_file }) => {
// Cancel the previously spawned process
self.cancel_check_process();
while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) {
@ -231,7 +235,11 @@ impl FlycheckActor {
}
}
let command = self.check_command(package.as_deref());
let command =
match self.check_command(package.as_deref(), saved_file.as_deref()) {
Some(c) => c,
None => continue,
};
let formatted_command = format!("{:?}", command);
tracing::debug!(?command, "will restart flycheck");
@ -305,7 +313,14 @@ impl FlycheckActor {
}
}
fn check_command(&self, package: Option<&str>) -> Command {
/// Construct a `Command` object for checking the user's code. If the user
/// has specified a custom command with placeholders that we cannot fill,
/// return None.
fn check_command(
&self,
package: Option<&str>,
saved_file: Option<&AbsPath>,
) -> Option<Command> {
let (mut cmd, args) = match &self.config {
FlycheckConfig::CargoCommand {
command,
@ -358,7 +373,7 @@ impl FlycheckActor {
cmd.arg("--target-dir").arg(target_dir);
}
cmd.envs(extra_env);
(cmd, extra_args)
(cmd, extra_args.clone())
}
FlycheckConfig::CustomCommand {
command,
@ -387,12 +402,34 @@ impl FlycheckActor {
}
}
(cmd, args)
if args.contains(&SAVED_FILE_PLACEHOLDER.to_owned()) {
// If the custom command has a $saved_file placeholder, and
// we're saving a file, replace the placeholder in the arguments.
if let Some(saved_file) = saved_file {
let args = args
.iter()
.map(|arg| {
if arg == SAVED_FILE_PLACEHOLDER {
saved_file.to_string()
} else {
arg.clone()
}
})
.collect();
(cmd, args)
} else {
// The custom command has a $saved_file placeholder,
// but we had an IDE event that wasn't a file save. Do nothing.
return None;
}
} else {
(cmd, args.clone())
}
}
};
cmd.args(args);
cmd
Some(cmd)
}
fn send(&self, check_task: Message) {