From 2aac6b0e34ad22374c87435cf125ed4833e9f6fc Mon Sep 17 00:00:00 2001 From: Aleksander Vognild Burkow Date: Sat, 29 Dec 2018 20:09:36 +0100 Subject: Ignore intellij files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 76bc7bf57..68158e41c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ crates/*/target .idea/* .vscode/* *.log +*.iml -- cgit v1.2.3 From 8b24f158f75e4496cfc7f8edf9aa41b10dbac9b3 Mon Sep 17 00:00:00 2001 From: Aleksander Vognild Burkow Date: Sat, 29 Dec 2018 20:09:42 +0100 Subject: Add support for formatting entire document with rustfmt Attempting to format a document when rustfmt isn't installed will result in an error being returned to the frontend. An alternative implementation would be returning zero replacements. --- crates/ra_analysis/src/imp.rs | 3 ++ crates/ra_analysis/src/lib.rs | 3 ++ crates/ra_lsp_server/src/caps.rs | 2 +- crates/ra_lsp_server/src/main_loop.rs | 1 + crates/ra_lsp_server/src/main_loop/handlers.rs | 33 +++++++++++++++ crates/ra_lsp_server/tests/heavy_tests/main.rs | 56 +++++++++++++++++++++++++- 6 files changed, 95 insertions(+), 3 deletions(-) diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index fcb4cd957..bff2e00c9 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -140,6 +140,9 @@ impl fmt::Debug for AnalysisImpl { } impl AnalysisImpl { + pub fn file_text(&self, file_id: FileId) -> Arc { + self.db.file_text(file_id) + } pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode { self.db.source_file(file_id) } diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 67b1c1482..9f5e9f358 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -274,6 +274,9 @@ pub struct Analysis { } impl Analysis { + pub fn file_text(&self, file_id: FileId) -> Arc { + self.imp.file_text(file_id) + } pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode { self.imp.file_syntax(file_id).clone() } diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs index 5f7038f63..8d508a3ba 100644 --- a/crates/ra_lsp_server/src/caps.rs +++ b/crates/ra_lsp_server/src/caps.rs @@ -33,7 +33,7 @@ pub fn server_capabilities() -> ServerCapabilities { workspace_symbol_provider: Some(true), code_action_provider: Some(CodeActionProviderCapability::Simple(true)), code_lens_provider: None, - document_formatting_provider: None, + document_formatting_provider: Some(true), document_range_formatting_provider: None, document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { first_trigger_character: "=".to_string(), diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 1edb9fae4..97c1be778 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -295,6 +295,7 @@ fn on_request( .on::(handlers::handle_prepare_rename)? .on::(handlers::handle_rename)? .on::(handlers::handle_references)? + .on::(handlers::handle_formatting)? .finish(); match req { Ok(id) => { diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index d6f3dbe28..07579be12 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -6,13 +6,16 @@ use languageserver_types::{ DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, FoldingRangeParams, Location, MarkupContent, MarkupKind, MarkedString, Position, PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, + Range, WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, HoverContents, + DocumentFormattingParams, }; use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FileRange, FilePosition, Severity}; use ra_syntax::{TextUnit, text_utils::intersect}; use ra_text_edit::text_utils::contains_offset_nonstrict; use rustc_hash::FxHashMap; use serde_json::to_value; +use std::io::Write; use crate::{ conv::{to_location, Conv, ConvWith, MapConvWith, TryConvWith}, @@ -601,6 +604,36 @@ pub fn handle_references( )) } +pub fn handle_formatting( + world: ServerWorld, + params: DocumentFormattingParams, +) -> Result>> { + let file_id = params.text_document.try_conv_with(&world)?; + let file = world.analysis().file_text(file_id); + + let file_line_index = world.analysis().file_line_index(file_id); + let end_position = TextUnit::of_str(&file).conv_with(&file_line_index); + + use std::process; + let mut rustfmt = process::Command::new("rustfmt") + .stdin(process::Stdio::piped()) + .stdout(process::Stdio::piped()) + .spawn()?; + + rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?; + + let output = rustfmt.wait_with_output()?; + let captured_stdout = String::from_utf8(output.stdout)?; + if !output.status.success() { + return Err(failure::err_msg(captured_stdout)); + } + + Ok(Some(vec![TextEdit { + range: Range::new(Position::new(0, 0), end_position), + new_text: captured_stdout, + }])) +} + pub fn handle_code_action( world: ServerWorld, params: req::CodeActionParams, diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs index 1f5cc5e8b..e9f02a6e4 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/main.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs @@ -1,8 +1,8 @@ mod support; use serde_json::json; -use ra_lsp_server::req::{Runnables, RunnablesParams, CodeActionRequest, CodeActionParams}; -use languageserver_types::{Position, Range, CodeActionContext}; +use ra_lsp_server::req::{Runnables, RunnablesParams, CodeActionRequest, CodeActionParams, Formatting}; +use languageserver_types::{Position, Range, CodeActionContext, DocumentFormattingParams, FormattingOptions}; use crate::support::project; @@ -118,6 +118,58 @@ fn test_eggs() {} ); } +use std::collections::HashMap; +#[test] +fn test_format_document() { + let server = project( + r#" +[package] +name = "foo" +version = "0.0.0" + +//- src/lib.rs +mod bar; + +fn main() { +} + +pub use std::collections::HashMap; +"#, + ); + server.wait_for_feedback("workspace loaded"); + + server.request::( + DocumentFormattingParams { + text_document: server.doc_id("src/lib.rs"), + options: FormattingOptions { + tab_size: 4, + insert_spaces: false, + properties: HashMap::new(), + }, + }, + json!([ + { + "newText": r#"mod bar; + +fn main() {} + +pub use std::collections::HashMap; +"#, + "range": { + "end": { + "character": 0, + "line": 6 + }, + "start": { + "character": 0, + "line": 0 + } + } + } + ]), + ); +} + #[test] fn test_missing_module_code_action() { let server = project( -- cgit v1.2.3 From ee9fc3f99884e973283f987cf56876e2db334628 Mon Sep 17 00:00:00 2001 From: Aleksander Vognild Burkow Date: Sat, 29 Dec 2018 21:55:07 +0100 Subject: Document formatting capabilities --- editors/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/editors/README.md b/editors/README.md index ad2ce1695..a63ced725 100644 --- a/editors/README.md +++ b/editors/README.md @@ -45,6 +45,8 @@ It's better to remove existing Rust plugins to avoid interference. `#[test]`, this action runs this specific test. If the cursor is outside of the test function, this re-runs the last test. Do bind this to a shortcut! + - **Format document**. Formats the current file with rustfmt. + Rustfmt must be installed separately with `rustup component add rustfmt`. * Typing assists - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression. -- cgit v1.2.3 From 09c20c8fcfa555465d367d4c09ac9f89259d5cf5 Mon Sep 17 00:00:00 2001 From: Aleksander Vognild Burkow Date: Sat, 29 Dec 2018 22:19:43 +0100 Subject: Add better error message for Command failure --- crates/ra_lsp_server/src/main_loop/handlers.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 07579be12..ecfa42206 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -625,7 +625,10 @@ pub fn handle_formatting( let output = rustfmt.wait_with_output()?; let captured_stdout = String::from_utf8(output.stdout)?; if !output.status.success() { - return Err(failure::err_msg(captured_stdout)); + return Err(failure::err_msg(format!( + "rustfmt exited with error code {}: {}.", + output.status, captured_stdout + ))); } Ok(Some(vec![TextEdit { -- cgit v1.2.3 From ed47c93afe7f9dd2c27956905e7fb9fcf9d5baf2 Mon Sep 17 00:00:00 2001 From: Aleksander Vognild Burkow Date: Sat, 29 Dec 2018 22:19:35 +0100 Subject: Install rustfmt in rustfmt test --- Cargo.lock | 1 + crates/ra_lsp_server/Cargo.toml | 1 + crates/ra_lsp_server/tests/heavy_tests/main.rs | 2 ++ crates/tools/src/lib.rs | 2 +- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index fa3363bd2..0c29d491f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -790,6 +790,7 @@ dependencies = [ "text_unit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "thread_worker 0.1.0", "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tools 0.1.0", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index c53106a62..f8f91e5e7 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml @@ -33,6 +33,7 @@ ra_text_edit = { path = "../ra_text_edit" } ra_analysis = { path = "../ra_analysis" } gen_lsp_server = { path = "../gen_lsp_server" } ra_vfs = { path = "../ra_vfs" } +tools = { path = "../tools" } [dev-dependencies] tempdir = "0.3.7" diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs index e9f02a6e4..b0e1e65b6 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/main.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs @@ -121,6 +121,8 @@ fn test_eggs() {} use std::collections::HashMap; #[test] fn test_format_document() { + tools::install_rustfmt().unwrap(); + let server = project( r#" [package] diff --git a/crates/tools/src/lib.rs b/crates/tools/src/lib.rs index 6f96b8120..e5b32c25c 100644 --- a/crates/tools/src/lib.rs +++ b/crates/tools/src/lib.rs @@ -117,7 +117,7 @@ pub fn run_rustfmt(mode: Mode) -> Result<()> { Ok(()) } -fn install_rustfmt() -> Result<()> { +pub fn install_rustfmt() -> Result<()> { run(&format!("rustup install {}", TOOLCHAIN), ".")?; run( &format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), -- cgit v1.2.3 From 0cb270e75d9501dff9ac6633354ae12d9c0f4260 Mon Sep 17 00:00:00 2001 From: Aleksander Vognild Burkow Date: Sun, 30 Dec 2018 00:21:15 +0100 Subject: Simplify failure bail code --- crates/ra_lsp_server/src/main_loop/handlers.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index ecfa42206..a2c12a4c1 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -625,10 +625,11 @@ pub fn handle_formatting( let output = rustfmt.wait_with_output()?; let captured_stdout = String::from_utf8(output.stdout)?; if !output.status.success() { - return Err(failure::err_msg(format!( + failure::bail!( "rustfmt exited with error code {}: {}.", - output.status, captured_stdout - ))); + output.status, + captured_stdout, + ); } Ok(Some(vec![TextEdit { -- cgit v1.2.3