aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r--crates/ra_lsp_server/Cargo.toml5
-rw-r--r--crates/ra_lsp_server/src/caps.rs2
-rw-r--r--crates/ra_lsp_server/src/conv.rs14
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs1
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs57
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs58
6 files changed, 120 insertions, 17 deletions
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index 3c8c240cd..646df2497 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -11,13 +11,13 @@ relative-path = "0.4.0"
11failure = "0.1.2" 11failure = "0.1.2"
12failure_derive = "0.1.2" 12failure_derive = "0.1.2"
13serde_json = "1.0.24" 13serde_json = "1.0.24"
14serde = "1.0.71" 14serde = "1.0.83"
15drop_bomb = "0.1.0" 15drop_bomb = "0.1.0"
16crossbeam-channel = "0.2.4" 16crossbeam-channel = "0.2.4"
17flexi_logger = "0.10.0" 17flexi_logger = "0.10.0"
18log = "0.4.3" 18log = "0.4.3"
19url_serde = "0.2.0" 19url_serde = "0.2.0"
20languageserver-types = "0.53.0" 20languageserver-types = "0.53.1"
21walkdir = "2.2.7" 21walkdir = "2.2.7"
22im = "12.0.0" 22im = "12.0.0"
23cargo_metadata = "0.6.0" 23cargo_metadata = "0.6.0"
@@ -37,3 +37,4 @@ ra_vfs = { path = "../ra_vfs" }
37[dev-dependencies] 37[dev-dependencies]
38tempdir = "0.3.7" 38tempdir = "0.3.7"
39test_utils = { path = "../test_utils" } 39test_utils = { path = "../test_utils" }
40tools = { path = "../tools" }
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/conv.rs b/crates/ra_lsp_server/src/conv.rs
index d3670104e..0d6e62727 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -2,7 +2,7 @@ use languageserver_types::{
2 self, Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, 2 self, Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
3 TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, InsertTextFormat, 3 TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, InsertTextFormat,
4}; 4};
5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition, CompletionItem, CompletionItemKind, InsertText}; 5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition,FileRange, CompletionItem, CompletionItemKind, InsertText};
6use ra_editor::{LineCol, LineIndex, translate_offset_with_edit}; 6use ra_editor::{LineCol, LineIndex, translate_offset_with_edit};
7use ra_text_edit::{AtomTextEdit, TextEdit}; 7use ra_text_edit::{AtomTextEdit, TextEdit};
8use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 8use ra_syntax::{SyntaxKind, TextRange, TextUnit};
@@ -57,6 +57,7 @@ impl Conv for CompletionItemKind {
57 CompletionItemKind::Function => Function, 57 CompletionItemKind::Function => Function,
58 CompletionItemKind::Struct => Struct, 58 CompletionItemKind::Struct => Struct,
59 CompletionItemKind::Enum => Enum, 59 CompletionItemKind::Enum => Enum,
60 CompletionItemKind::EnumVariant => EnumMember,
60 CompletionItemKind::Binding => Variable, 61 CompletionItemKind::Binding => Variable,
61 CompletionItemKind::Field => Field, 62 CompletionItemKind::Field => Field,
62 } 63 }
@@ -218,6 +219,17 @@ impl<'a> TryConvWith for &'a TextDocumentPositionParams {
218 } 219 }
219} 220}
220 221
222impl<'a> TryConvWith for (&'a TextDocumentIdentifier, Range) {
223 type Ctx = ServerWorld;
224 type Output = FileRange;
225 fn try_conv_with(self, world: &ServerWorld) -> Result<FileRange> {
226 let file_id = self.0.try_conv_with(world)?;
227 let line_index = world.analysis().file_line_index(file_id);
228 let range = self.1.conv_with(&line_index);
229 Ok(FileRange { file_id, range })
230 }
231}
232
221impl<T: TryConvWith> TryConvWith for Vec<T> { 233impl<T: TryConvWith> TryConvWith for Vec<T> {
222 type Ctx = <T as TryConvWith>::Ctx; 234 type Ctx = <T as TryConvWith>::Ctx;
223 type Output = Vec<<T as TryConvWith>::Output>; 235 type Output = Vec<<T as TryConvWith>::Output>;
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 0e9a66a8a..a2c12a4c1 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, 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},
@@ -33,13 +36,13 @@ pub fn handle_extend_selection(
33 params: req::ExtendSelectionParams, 36 params: req::ExtendSelectionParams,
34) -> Result<req::ExtendSelectionResult> { 37) -> Result<req::ExtendSelectionResult> {
35 let file_id = params.text_document.try_conv_with(&world)?; 38 let file_id = params.text_document.try_conv_with(&world)?;
36 let file = world.analysis().file_syntax(file_id);
37 let line_index = world.analysis().file_line_index(file_id); 39 let line_index = world.analysis().file_line_index(file_id);
38 let selections = params 40 let selections = params
39 .selections 41 .selections
40 .into_iter() 42 .into_iter()
41 .map_conv_with(&line_index) 43 .map_conv_with(&line_index)
42 .map(|r| world.analysis().extend_selection(&file, r)) 44 .map(|range| FileRange { file_id, range })
45 .map(|frange| world.analysis().extend_selection(frange))
43 .map_conv_with(&line_index) 46 .map_conv_with(&line_index)
44 .collect(); 47 .collect();
45 Ok(req::ExtendSelectionResult { selections }) 48 Ok(req::ExtendSelectionResult { selections })
@@ -71,13 +74,8 @@ pub fn handle_join_lines(
71 world: ServerWorld, 74 world: ServerWorld,
72 params: req::JoinLinesParams, 75 params: req::JoinLinesParams,
73) -> Result<req::SourceChange> { 76) -> Result<req::SourceChange> {
74 let file_id = params.text_document.try_conv_with(&world)?; 77 let frange = (&params.text_document, params.range).try_conv_with(&world)?;
75 let line_index = world.analysis().file_line_index(file_id); 78 world.analysis().join_lines(frange).try_conv_with(&world)
76 let range = params.range.conv_with(&line_index);
77 world
78 .analysis()
79 .join_lines(file_id, range)
80 .try_conv_with(&world)
81} 79}
82 80
83pub fn handle_on_enter( 81pub fn handle_on_enter(
@@ -606,6 +604,40 @@ pub fn handle_references(
606 )) 604 ))
607} 605}
608 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 failure::bail!(
629 "rustfmt exited with error code {}: {}.",
630 output.status,
631 captured_stdout,
632 );
633 }
634
635 Ok(Some(vec![TextEdit {
636 range: Range::new(Position::new(0, 0), end_position),
637 new_text: captured_stdout,
638 }]))
639}
640
609pub fn handle_code_action( 641pub fn handle_code_action(
610 world: ServerWorld, 642 world: ServerWorld,
611 params: req::CodeActionParams, 643 params: req::CodeActionParams,
@@ -614,7 +646,10 @@ pub fn handle_code_action(
614 let line_index = world.analysis().file_line_index(file_id); 646 let line_index = world.analysis().file_line_index(file_id);
615 let range = params.range.conv_with(&line_index); 647 let range = params.range.conv_with(&line_index);
616 648
617 let assists = world.analysis().assists(file_id, range)?.into_iter(); 649 let assists = world
650 .analysis()
651 .assists(FileRange { file_id, range })?
652 .into_iter();
618 let fixes = world 653 let fixes = world
619 .analysis() 654 .analysis()
620 .diagnostics(file_id)? 655 .diagnostics(file_id)?
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index 1f5cc5e8b..b0e1e65b6 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,60 @@ fn test_eggs() {}
118 ); 118 );
119} 119}
120 120
121use std::collections::HashMap;
122#[test]
123fn test_format_document() {
124 tools::install_rustfmt().unwrap();
125
126 let server = project(
127 r#"
128[package]
129name = "foo"
130version = "0.0.0"
131
132//- src/lib.rs
133mod bar;
134
135fn main() {
136}
137
138pub use std::collections::HashMap;
139"#,
140 );
141 server.wait_for_feedback("workspace loaded");
142
143 server.request::<Formatting>(
144 DocumentFormattingParams {
145 text_document: server.doc_id("src/lib.rs"),
146 options: FormattingOptions {
147 tab_size: 4,
148 insert_spaces: false,
149 properties: HashMap::new(),
150 },
151 },
152 json!([
153 {
154 "newText": r#"mod bar;
155
156fn main() {}
157
158pub use std::collections::HashMap;
159"#,
160 "range": {
161 "end": {
162 "character": 0,
163 "line": 6
164 },
165 "start": {
166 "character": 0,
167 "line": 0
168 }
169 }
170 }
171 ]),
172 );
173}
174
121#[test] 175#[test]
122fn test_missing_module_code_action() { 176fn test_missing_module_code_action() {
123 let server = project( 177 let server = project(