aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server
diff options
context:
space:
mode:
authorAleksander Vognild Burkow <[email protected]>2018-12-29 19:09:42 +0000
committerAleksander Vognild Burkow <[email protected]>2018-12-29 20:57:46 +0000
commit8b24f158f75e4496cfc7f8edf9aa41b10dbac9b3 (patch)
treeadd7a233ed590a2f66d0e702e968a4011c9d859e /crates/ra_lsp_server
parent2aac6b0e34ad22374c87435cf125ed4833e9f6fc (diff)
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.
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r--crates/ra_lsp_server/src/caps.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs1
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs33
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs56
4 files changed, 89 insertions, 3 deletions
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 {
33 workspace_symbol_provider: Some(true), 33 workspace_symbol_provider: Some(true),
34 code_action_provider: Some(CodeActionProviderCapability::Simple(true)), 34 code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
35 code_lens_provider: None, 35 code_lens_provider: None,
36 document_formatting_provider: None, 36 document_formatting_provider: Some(true),
37 document_range_formatting_provider: None, 37 document_range_formatting_provider: None,
38 document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { 38 document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
39 first_trigger_character: "=".to_string(), 39 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(
295 .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)? 295 .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)?
296 .on::<req::Rename>(handlers::handle_rename)? 296 .on::<req::Rename>(handlers::handle_rename)?
297 .on::<req::References>(handlers::handle_references)? 297 .on::<req::References>(handlers::handle_references)?
298 .on::<req::Formatting>(handlers::handle_formatting)?
298 .finish(); 299 .finish();
299 match req { 300 match req {
300 Ok(id) => { 301 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::{
6 DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, 6 DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind,
7 FoldingRangeParams, Location, MarkupContent, MarkupKind, MarkedString, Position, 7 FoldingRangeParams, Location, MarkupContent, MarkupKind, MarkedString, Position,
8 PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, 8 PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit,
9 Range,
9 WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, HoverContents, 10 WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, HoverContents,
11 DocumentFormattingParams,
10}; 12};
11use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FileRange, FilePosition, Severity}; 13use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FileRange, FilePosition, Severity};
12use ra_syntax::{TextUnit, text_utils::intersect}; 14use ra_syntax::{TextUnit, text_utils::intersect};
13use ra_text_edit::text_utils::contains_offset_nonstrict; 15use ra_text_edit::text_utils::contains_offset_nonstrict;
14use rustc_hash::FxHashMap; 16use rustc_hash::FxHashMap;
15use serde_json::to_value; 17use serde_json::to_value;
18use std::io::Write;
16 19
17use crate::{ 20use crate::{
18 conv::{to_location, Conv, ConvWith, MapConvWith, TryConvWith}, 21 conv::{to_location, Conv, ConvWith, MapConvWith, TryConvWith},
@@ -601,6 +604,36 @@ pub fn handle_references(
601 )) 604 ))
602} 605}
603 606
607pub fn handle_formatting(
608 world: ServerWorld,
609 params: DocumentFormattingParams,
610) -> Result<Option<Vec<TextEdit>>> {
611 let file_id = params.text_document.try_conv_with(&world)?;
612 let file = world.analysis().file_text(file_id);
613
614 let file_line_index = world.analysis().file_line_index(file_id);
615 let end_position = TextUnit::of_str(&file).conv_with(&file_line_index);
616
617 use std::process;
618 let mut rustfmt = process::Command::new("rustfmt")
619 .stdin(process::Stdio::piped())
620 .stdout(process::Stdio::piped())
621 .spawn()?;
622
623 rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?;
624
625 let output = rustfmt.wait_with_output()?;
626 let captured_stdout = String::from_utf8(output.stdout)?;
627 if !output.status.success() {
628 return Err(failure::err_msg(captured_stdout));
629 }
630
631 Ok(Some(vec![TextEdit {
632 range: Range::new(Position::new(0, 0), end_position),
633 new_text: captured_stdout,
634 }]))
635}
636
604pub fn handle_code_action( 637pub fn handle_code_action(
605 world: ServerWorld, 638 world: ServerWorld,
606 params: req::CodeActionParams, 639 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 @@
1mod support; 1mod support;
2 2
3use serde_json::json; 3use serde_json::json;
4use ra_lsp_server::req::{Runnables, RunnablesParams, CodeActionRequest, CodeActionParams}; 4use ra_lsp_server::req::{Runnables, RunnablesParams, CodeActionRequest, CodeActionParams, Formatting};
5use languageserver_types::{Position, Range, CodeActionContext}; 5use languageserver_types::{Position, Range, CodeActionContext, DocumentFormattingParams, FormattingOptions};
6 6
7use crate::support::project; 7use crate::support::project;
8 8
@@ -118,6 +118,58 @@ fn test_eggs() {}
118 ); 118 );
119} 119}
120 120
121use std::collections::HashMap;
122#[test]
123fn test_format_document() {
124 let server = project(
125 r#"
126[package]
127name = "foo"
128version = "0.0.0"
129
130//- src/lib.rs
131mod bar;
132
133fn main() {
134}
135
136pub use std::collections::HashMap;
137"#,
138 );
139 server.wait_for_feedback("workspace loaded");
140
141 server.request::<Formatting>(
142 DocumentFormattingParams {
143 text_document: server.doc_id("src/lib.rs"),
144 options: FormattingOptions {
145 tab_size: 4,
146 insert_spaces: false,
147 properties: HashMap::new(),
148 },
149 },
150 json!([
151 {
152 "newText": r#"mod bar;
153
154fn main() {}
155
156pub use std::collections::HashMap;
157"#,
158 "range": {
159 "end": {
160 "character": 0,
161 "line": 6
162 },
163 "start": {
164 "character": 0,
165 "line": 0
166 }
167 }
168 }
169 ]),
170 );
171}
172
121#[test] 173#[test]
122fn test_missing_module_code_action() { 174fn test_missing_module_code_action() {
123 let server = project( 175 let server = project(