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.toml2
-rw-r--r--crates/ra_lsp_server/src/caps.rs2
-rw-r--r--crates/ra_lsp_server/src/conv.rs61
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs1
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs73
-rw-r--r--crates/ra_lsp_server/src/req.rs22
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs23
7 files changed, 113 insertions, 71 deletions
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index 6c3aeaf13..8bd4caa53 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -10,7 +10,7 @@ threadpool = "1.7.1"
10relative-path = "0.4.0" 10relative-path = "0.4.0"
11failure = "0.1.4" 11failure = "0.1.4"
12failure_derive = "0.1.4" 12failure_derive = "0.1.4"
13serde_json = "1.0.24" 13serde_json = "1.0.34"
14serde = "1.0.83" 14serde = "1.0.83"
15drop_bomb = "0.1.0" 15drop_bomb = "0.1.0"
16crossbeam-channel = "0.3.5" 16crossbeam-channel = "0.3.5"
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index 8d508a3ba..a74f9f27b 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -28,7 +28,7 @@ pub fn server_capabilities() -> ServerCapabilities {
28 type_definition_provider: None, 28 type_definition_provider: None,
29 implementation_provider: None, 29 implementation_provider: None,
30 references_provider: Some(true), 30 references_provider: Some(true),
31 document_highlight_provider: None, 31 document_highlight_provider: Some(true),
32 document_symbol_provider: Some(true), 32 document_symbol_provider: Some(true),
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)),
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 0d6e62727..7230fb101 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -1,11 +1,16 @@
1use languageserver_types::{ 1use languageserver_types::{
2 self, Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, 2 self, CreateFile, DocumentChangeOperation, DocumentChanges, InsertTextFormat, Location,
3 TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, InsertTextFormat, 3 Position, Range, RenameFile, ResourceOp, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
4 TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier,
5 WorkspaceEdit,
4}; 6};
5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition,FileRange, CompletionItem, CompletionItemKind, InsertText}; 7use ra_analysis::{
6use ra_editor::{LineCol, LineIndex, translate_offset_with_edit}; 8 CompletionItem, CompletionItemKind, FileId, FilePosition, FileRange, FileSystemEdit,
7use ra_text_edit::{AtomTextEdit, TextEdit}; 9 InsertText, NavigationTarget, SourceChange, SourceFileEdit,
10};
11use ra_editor::{translate_offset_with_edit, LineCol, LineIndex};
8use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 12use ra_syntax::{SyntaxKind, TextRange, TextUnit};
13use ra_text_edit::{AtomTextEdit, TextEdit};
9 14
10use crate::{req, server_world::ServerWorld, Result}; 15use crate::{req, server_world::ServerWorld, Result};
11 16
@@ -49,7 +54,7 @@ impl Conv for CompletionItemKind {
49 type Output = ::languageserver_types::CompletionItemKind; 54 type Output = ::languageserver_types::CompletionItemKind;
50 55
51 fn conv(self) -> <Self as Conv>::Output { 56 fn conv(self) -> <Self as Conv>::Output {
52 use ::languageserver_types::CompletionItemKind::*; 57 use languageserver_types::CompletionItemKind::*;
53 match self { 58 match self {
54 CompletionItemKind::Keyword => Keyword, 59 CompletionItemKind::Keyword => Keyword,
55 CompletionItemKind::Snippet => Snippet, 60 CompletionItemKind::Snippet => Snippet,
@@ -82,7 +87,6 @@ impl Conv for CompletionItem {
82 InsertText::Snippet { text } => { 87 InsertText::Snippet { text } => {
83 res.insert_text = Some(text); 88 res.insert_text = Some(text);
84 res.insert_text_format = Some(InsertTextFormat::Snippet); 89 res.insert_text_format = Some(InsertTextFormat::Snippet);
85 res.kind = Some(languageserver_types::CompletionItemKind::Keyword);
86 } 90 }
87 } 91 }
88 res 92 res
@@ -267,12 +271,20 @@ impl TryConvWith for SourceChange {
267 }) 271 })
268 } 272 }
269 }; 273 };
270 let source_file_edits = self.source_file_edits.try_conv_with(world)?; 274 let mut document_changes: Vec<DocumentChangeOperation> = Vec::new();
271 let file_system_edits = self.file_system_edits.try_conv_with(world)?; 275 for resource_op in self.file_system_edits.try_conv_with(world)? {
276 document_changes.push(DocumentChangeOperation::Op(resource_op));
277 }
278 for text_document_edit in self.source_file_edits.try_conv_with(world)? {
279 document_changes.push(DocumentChangeOperation::Edit(text_document_edit));
280 }
281 let workspace_edit = WorkspaceEdit {
282 changes: None,
283 document_changes: Some(DocumentChanges::Operations(document_changes)),
284 };
272 Ok(req::SourceChange { 285 Ok(req::SourceChange {
273 label: self.label, 286 label: self.label,
274 source_file_edits, 287 workspace_edit,
275 file_system_edits,
276 cursor_position, 288 cursor_position,
277 }) 289 })
278 } 290 }
@@ -302,27 +314,40 @@ impl TryConvWith for SourceFileEdit {
302 314
303impl TryConvWith for FileSystemEdit { 315impl TryConvWith for FileSystemEdit {
304 type Ctx = ServerWorld; 316 type Ctx = ServerWorld;
305 type Output = req::FileSystemEdit; 317 type Output = ResourceOp;
306 fn try_conv_with(self, world: &ServerWorld) -> Result<req::FileSystemEdit> { 318 fn try_conv_with(self, world: &ServerWorld) -> Result<ResourceOp> {
307 let res = match self { 319 let res = match self {
308 FileSystemEdit::CreateFile { source_root, path } => { 320 FileSystemEdit::CreateFile { source_root, path } => {
309 let uri = world.path_to_uri(source_root, &path)?; 321 let uri = world.path_to_uri(source_root, &path)?.to_string();
310 req::FileSystemEdit::CreateFile { uri } 322 ResourceOp::Create(CreateFile { uri, options: None })
311 } 323 }
312 FileSystemEdit::MoveFile { 324 FileSystemEdit::MoveFile {
313 src, 325 src,
314 dst_source_root, 326 dst_source_root,
315 dst_path, 327 dst_path,
316 } => { 328 } => {
317 let src = world.file_id_to_uri(src)?; 329 let old_uri = world.file_id_to_uri(src)?.to_string();
318 let dst = world.path_to_uri(dst_source_root, &dst_path)?; 330 let new_uri = world.path_to_uri(dst_source_root, &dst_path)?.to_string();
319 req::FileSystemEdit::MoveFile { src, dst } 331 ResourceOp::Rename(RenameFile {
332 old_uri,
333 new_uri,
334 options: None,
335 })
320 } 336 }
321 }; 337 };
322 Ok(res) 338 Ok(res)
323 } 339 }
324} 340}
325 341
342impl TryConvWith for &NavigationTarget {
343 type Ctx = ServerWorld;
344 type Output = Location;
345 fn try_conv_with(self, world: &ServerWorld) -> Result<Location> {
346 let line_index = world.analysis().file_line_index(self.file_id());
347 to_location(self.file_id(), self.range(), &world, &line_index)
348 }
349}
350
326pub fn to_location( 351pub fn to_location(
327 file_id: FileId, 352 file_id: FileId,
328 range: TextRange, 353 range: TextRange,
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index d425b6733..06dd373c0 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -300,6 +300,7 @@ fn on_request(
300 .on::<req::Rename>(handlers::handle_rename)? 300 .on::<req::Rename>(handlers::handle_rename)?
301 .on::<req::References>(handlers::handle_references)? 301 .on::<req::References>(handlers::handle_references)?
302 .on::<req::Formatting>(handlers::handle_formatting)? 302 .on::<req::Formatting>(handlers::handle_formatting)?
303 .on::<req::DocumentHighlightRequest>(handlers::handle_document_highlight)?
303 .finish(); 304 .finish();
304 match req { 305 match req {
305 Ok(id) => { 306 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 3b7a14a5c..b5792f3b8 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -6,9 +6,8 @@ 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 Range, WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover,
10 WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, HoverContents, 10 HoverContents, DocumentFormattingParams, DocumentHighlight,
11 DocumentFormattingParams,
12}; 11};
13use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FileRange, FilePosition, Severity}; 12use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FileRange, FilePosition, Severity};
14use ra_syntax::{TextUnit, text_utils::intersect}; 13use ra_syntax::{TextUnit, text_utils::intersect};
@@ -189,12 +188,11 @@ pub fn handle_workspace_symbol(
189 188
190 fn exec_query(world: &ServerWorld, query: Query) -> Result<Vec<SymbolInformation>> { 189 fn exec_query(world: &ServerWorld, query: Query) -> Result<Vec<SymbolInformation>> {
191 let mut res = Vec::new(); 190 let mut res = Vec::new();
192 for (file_id, symbol) in world.analysis().symbol_search(query)? { 191 for nav in world.analysis().symbol_search(query)? {
193 let line_index = world.analysis().file_line_index(file_id);
194 let info = SymbolInformation { 192 let info = SymbolInformation {
195 name: symbol.name.to_string(), 193 name: nav.name().to_string(),
196 kind: symbol.kind.conv(), 194 kind: nav.kind().conv(),
197 location: to_location(file_id, symbol.node_range, world, &line_index)?, 195 location: nav.try_conv_with(world)?,
198 container_name: None, 196 container_name: None,
199 deprecated: None, 197 deprecated: None,
200 }; 198 };
@@ -213,12 +211,11 @@ pub fn handle_goto_definition(
213 None => return Ok(None), 211 None => return Ok(None),
214 Some(it) => it, 212 Some(it) => it,
215 }; 213 };
216 let mut res = Vec::new(); 214 let res = rr
217 for (file_id, symbol) in rr.resolves_to { 215 .resolves_to
218 let line_index = world.analysis().file_line_index(file_id); 216 .into_iter()
219 let location = to_location(file_id, symbol.node_range, &world, &line_index)?; 217 .map(|nav| nav.try_conv_with(&world))
220 res.push(location) 218 .collect::<Result<Vec<_>>>()?;
221 }
222 Ok(Some(req::GotoDefinitionResponse::Array(res))) 219 Ok(Some(req::GotoDefinitionResponse::Array(res)))
223} 220}
224 221
@@ -227,13 +224,12 @@ pub fn handle_parent_module(
227 params: req::TextDocumentPositionParams, 224 params: req::TextDocumentPositionParams,
228) -> Result<Vec<Location>> { 225) -> Result<Vec<Location>> {
229 let position = params.try_conv_with(&world)?; 226 let position = params.try_conv_with(&world)?;
230 let mut res = Vec::new(); 227 world
231 for (file_id, symbol) in world.analysis().parent_module(position)? { 228 .analysis()
232 let line_index = world.analysis().file_line_index(file_id); 229 .parent_module(position)?
233 let location = to_location(file_id, symbol.node_range, &world, &line_index)?; 230 .into_iter()
234 res.push(location); 231 .map(|nav| nav.try_conv_with(&world))
235 } 232 .collect::<Result<Vec<_>>>()
236 Ok(res)
237} 233}
238 234
239pub fn handle_runnables( 235pub fn handle_runnables(
@@ -257,6 +253,7 @@ pub fn handle_runnables(
257 range: runnable.range.conv_with(&line_index), 253 range: runnable.range.conv_with(&line_index),
258 label: match &runnable.kind { 254 label: match &runnable.kind {
259 RunnableKind::Test { name } => format!("test {}", name), 255 RunnableKind::Test { name } => format!("test {}", name),
256 RunnableKind::TestMod { path } => format!("test-mod {}", path),
260 RunnableKind::Bin => "run binary".to_string(), 257 RunnableKind::Bin => "run binary".to_string(),
261 }, 258 },
262 bin: "cargo".to_string(), 259 bin: "cargo".to_string(),
@@ -308,6 +305,15 @@ pub fn handle_runnables(
308 res.push(name.to_string()); 305 res.push(name.to_string());
309 res.push("--nocapture".to_string()); 306 res.push("--nocapture".to_string());
310 } 307 }
308 RunnableKind::TestMod { path } => {
309 res.push("test".to_string());
310 if let Some(spec) = spec {
311 spec.push_to(&mut res);
312 }
313 res.push("--".to_string());
314 res.push(path.to_string());
315 res.push("--nocapture".to_string());
316 }
311 RunnableKind::Bin => { 317 RunnableKind::Bin => {
312 res.push("run".to_string()); 318 res.push("run".to_string());
313 if let Some(spec) = spec { 319 if let Some(spec) = spec {
@@ -508,8 +514,8 @@ pub fn handle_hover(
508 Some(it) => it, 514 Some(it) => it,
509 }; 515 };
510 let mut result = Vec::new(); 516 let mut result = Vec::new();
511 for (file_id, symbol) in rr.resolves_to { 517 for nav in rr.resolves_to {
512 if let Some(docs) = world.analysis().doc_text_for(file_id, symbol)? { 518 if let Some(docs) = world.analysis().doc_text_for(nav)? {
513 result.push(docs); 519 result.push(docs);
514 } 520 }
515 } 521 }
@@ -668,6 +674,27 @@ pub fn handle_code_action(
668 Ok(Some(CodeActionResponse::Commands(res))) 674 Ok(Some(CodeActionResponse::Commands(res)))
669} 675}
670 676
677pub fn handle_document_highlight(
678 world: ServerWorld,
679 params: req::TextDocumentPositionParams,
680) -> Result<Option<Vec<DocumentHighlight>>> {
681 let file_id = params.text_document.try_conv_with(&world)?;
682 let line_index = world.analysis().file_line_index(file_id);
683
684 let refs = world
685 .analysis()
686 .find_all_refs(params.try_conv_with(&world)?)?;
687
688 Ok(Some(
689 refs.into_iter()
690 .map(|r| DocumentHighlight {
691 range: r.1.conv_with(&line_index),
692 kind: None,
693 })
694 .collect(),
695 ))
696}
697
671pub fn publish_diagnostics( 698pub fn publish_diagnostics(
672 world: &ServerWorld, 699 world: &ServerWorld,
673 file_id: FileId, 700 file_id: FileId,
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index 747ab8a8c..b41e90328 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -1,6 +1,6 @@
1use serde::{Serialize, Deserialize};
2use languageserver_types::{Location, Position, Range, TextDocumentIdentifier, Url}; 1use languageserver_types::{Location, Position, Range, TextDocumentIdentifier, Url};
3use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
3use serde::{Deserialize, Serialize};
4use url_serde; 4use url_serde;
5 5
6pub use languageserver_types::{ 6pub use languageserver_types::{
@@ -8,7 +8,7 @@ pub use languageserver_types::{
8 CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, 8 CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams,
9 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, 9 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult,
10 PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit, 10 PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit,
11 TextDocumentPositionParams, TextEdit, WorkspaceSymbolParams, 11 TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams,
12}; 12};
13 13
14pub enum SyntaxTree {} 14pub enum SyntaxTree {}
@@ -151,26 +151,10 @@ pub struct Runnable {
151#[serde(rename_all = "camelCase")] 151#[serde(rename_all = "camelCase")]
152pub struct SourceChange { 152pub struct SourceChange {
153 pub label: String, 153 pub label: String,
154 pub source_file_edits: Vec<TextDocumentEdit>, 154 pub workspace_edit: WorkspaceEdit,
155 pub file_system_edits: Vec<FileSystemEdit>,
156 pub cursor_position: Option<TextDocumentPositionParams>, 155 pub cursor_position: Option<TextDocumentPositionParams>,
157} 156}
158 157
159#[derive(Serialize, Debug)]
160#[serde(tag = "type", rename_all = "camelCase")]
161pub enum FileSystemEdit {
162 CreateFile {
163 #[serde(with = "url_serde")]
164 uri: Url,
165 },
166 MoveFile {
167 #[serde(with = "url_serde")]
168 src: Url,
169 #[serde(with = "url_serde")]
170 dst: Url,
171 },
172}
173
174pub enum InternalFeedback {} 158pub enum InternalFeedback {}
175 159
176impl Notification for InternalFeedback { 160impl Notification for InternalFeedback {
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index b0e1e65b6..4cae44eab 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/main.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs
@@ -1,8 +1,12 @@
1mod support; 1mod support;
2 2
3use languageserver_types::{
4 CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range,
5};
6use ra_lsp_server::req::{
7 CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams,
8};
3use serde_json::json; 9use serde_json::json;
4use ra_lsp_server::req::{Runnables, RunnablesParams, CodeActionRequest, CodeActionParams, Formatting};
5use languageserver_types::{Position, Range, CodeActionContext, DocumentFormattingParams, FormattingOptions};
6 10
7use crate::support::project; 11use crate::support::project;
8 12
@@ -203,14 +207,15 @@ fn main() {}
203 "arguments": [ 207 "arguments": [
204 { 208 {
205 "cursorPosition": null, 209 "cursorPosition": null,
206 "fileSystemEdits": [ 210 "workspaceEdit": {
207 { 211 "documentChanges": [
208 "type": "createFile", 212 {
213 "kind": "create",
209 "uri": "file:///[..]/src/bar.rs" 214 "uri": "file:///[..]/src/bar.rs"
210 } 215 }
211 ], 216 ]
212 "label": "create module", 217 },
213 "sourceFileEdits": [] 218 "label": "create module"
214 } 219 }
215 ], 220 ],
216 "command": "ra-lsp.applySourceChange", 221 "command": "ra-lsp.applySourceChange",