Skip to content

fix: ensure rustfmt runs when configured with ./ #15600

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 6, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion crates/rust-analyzer/src/handlers/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use std::{
fs,
io::Write as _,
path::PathBuf,
process::{self, Stdio},
};

Expand Down Expand Up @@ -1995,14 +1996,52 @@ fn run_rustfmt(
cmd
}
RustfmtConfig::CustomCommand { command, args } => {
let mut cmd = process::Command::new(command);
let cmd = PathBuf::from(&command);
let mut components = cmd.components();

// to support rustc's suggested, default configuration
let mut cmd = match components.next() {
Some(std::path::Component::CurDir) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably work with build/host/rustfmt as well; special-casing the leading ./ sounds very fragile.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ye, we can just Path::join the rustfmt path onto the base here. If the path is absolute it'll replace the base, otherwise it"ll append which is exactly the semantics we want to have here.

let rest = components.as_path();

let roots = snap
.workspaces
.iter()
.flat_map(|ws| ws.workspace_definition_path())
.collect::<Vec<&AbsPath>>();

let abs: Option<AbsPathBuf> = roots.into_iter().find_map(|base| {
let abs = base.join(rest);
std::fs::metadata(&abs).ok().map(|_| abs)
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of this approach, but I can't find a better way to determine what workspace a TextDocument is a part of.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take a look at CargoTargetSpec::for_file, that function has to solve the same problem of relating a file to its workspace(s)


let command = match abs {
Some(cmd) => cmd,
None => {
tracing::error!(
rustfmt = ?command,
"Unable to make the format command an absolute path"
);
anyhow::bail!(
"Unable to make the format command an absolute path: {}",
command
);
}
};

process::Command::new(&command.as_os_str())
}
_ => process::Command::new(command),
};

cmd.envs(snap.config.extra_env());
cmd.args(args);
cmd
}
};

tracing::debug!(?command, "created format command");

// try to chdir to the file so we can respect `rustfmt.toml`
// FIXME: use `rustfmt --config-path` once
// https://github.com/rust-lang/rustfmt/issues/4660 gets fixed
Expand Down