Skip to content

Commit b13a217

Browse files
bors[bot]etaoins
andcommitted
Merge #1449
1449: Swallow expected `rustfmt` errors r=matklad a=etaoins My workflow in Visual Studio Code + Rust Analyzer has become: 1. Make a change to Rust source code using all the analysis magic 2. Save the file to trigger `cargo watch`. I have format on save enabled for all file types so this also runs `rustfmt` 3. Fix any diagnostics that `cargo watch` finds Unfortunately if the Rust source has any syntax errors the act of saving will pop up a scary "command has failed" message and will switch to the "Output" tab to show the `rustfmt` error and exit code. I did a quick survey of what other Language Servers do in this case. Both the JSON and TypeScript servers will swallow the error and return success. This is consistent with how I remember my workflow in those languages. The syntax error will show up as a diagnostic so it should be clear why the file isn't formatting. I checked the `rustfmt` source code and while it does distinguish "parse errors" from "operational errors" internally they both result in exit status of 1. However, more catastrophic errors (missing `rustfmt`, SIGSEGV, etc) will return 127+ error codes which we can distinguish from a normal failure. This changes our handler to log an info message and feign success if `rustfmt` exits with status 1. Another option I considered was only swallowing the error if the formatting request came from format-on-save. However, the Language Server Protocol doesn't seem to distinguish those cases. Co-authored-by: Ryan Cumming <[email protected]>
2 parents 04a211f + e052ca9 commit b13a217

File tree

1 file changed

+25
-10
lines changed

1 file changed

+25
-10
lines changed

crates/ra_lsp_server/src/main_loop/handlers.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -621,17 +621,32 @@ pub fn handle_formatting(
621621

622622
let output = rustfmt.wait_with_output()?;
623623
let captured_stdout = String::from_utf8(output.stdout)?;
624+
624625
if !output.status.success() {
625-
return Err(LspError::new(
626-
-32900,
627-
format!(
628-
r#"rustfmt exited with:
629-
Status: {}
630-
stdout: {}"#,
631-
output.status, captured_stdout,
632-
),
633-
)
634-
.into());
626+
match output.status.code() {
627+
Some(1) => {
628+
// While `rustfmt` doesn't have a specific exit code for parse errors this is the
629+
// likely cause exiting with 1. Most Language Servers swallow parse errors on
630+
// formatting because otherwise an error is surfaced to the user on top of the
631+
// syntax error diagnostics they're already receiving. This is especially jarring
632+
// if they have format on save enabled.
633+
log::info!("rustfmt exited with status 1, assuming parse error and ignoring");
634+
return Ok(None);
635+
}
636+
_ => {
637+
// Something else happened - e.g. `rustfmt` is missing or caught a signal
638+
return Err(LspError::new(
639+
-32900,
640+
format!(
641+
r#"rustfmt exited with:
642+
Status: {}
643+
stdout: {}"#,
644+
output.status, captured_stdout,
645+
),
646+
)
647+
.into());
648+
}
649+
}
635650
}
636651

637652
Ok(Some(vec![TextEdit {

0 commit comments

Comments
 (0)