aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server/src/main_loop
diff options
context:
space:
mode:
authorRyan Cumming <[email protected]>2019-06-26 22:52:19 +0100
committerRyan Cumming <[email protected]>2019-06-26 23:08:26 +0100
commite052ca9d614e946a6cea4875ae50c68d77088257 (patch)
treec71ae4c1757f53786150f6ea638d3641ea82fdb2 /crates/ra_lsp_server/src/main_loop
parent5536a249145fc67c415ad48738e62fc2a9e848ff (diff)
Swallow expected `rustfmt` errors
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.
Diffstat (limited to 'crates/ra_lsp_server/src/main_loop')
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs35
1 files changed, 25 insertions, 10 deletions
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 6373240d5..47222cd0a 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -621,17 +621,32 @@ pub fn handle_formatting(
621 621
622 let output = rustfmt.wait_with_output()?; 622 let output = rustfmt.wait_with_output()?;
623 let captured_stdout = String::from_utf8(output.stdout)?; 623 let captured_stdout = String::from_utf8(output.stdout)?;
624
624 if !output.status.success() { 625 if !output.status.success() {
625 return Err(LspError::new( 626 match output.status.code() {
626 -32900, 627 Some(1) => {
627 format!( 628 // While `rustfmt` doesn't have a specific exit code for parse errors this is the
628 r#"rustfmt exited with: 629 // likely cause exiting with 1. Most Language Servers swallow parse errors on
629 Status: {} 630 // formatting because otherwise an error is surfaced to the user on top of the
630 stdout: {}"#, 631 // syntax error diagnostics they're already receiving. This is especially jarring
631 output.status, captured_stdout, 632 // if they have format on save enabled.
632 ), 633 log::info!("rustfmt exited with status 1, assuming parse error and ignoring");
633 ) 634 return Ok(None);
634 .into()); 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 }
635 } 650 }
636 651
637 Ok(Some(vec![TextEdit { 652 Ok(Some(vec![TextEdit {