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/src/caps.rs8
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs140
-rw-r--r--crates/ra_lsp_server/src/main_loop/mod.rs41
-rw-r--r--crates/ra_lsp_server/src/path_map.rs4
-rw-r--r--crates/ra_lsp_server/src/project_model.rs4
-rw-r--r--crates/ra_lsp_server/src/req.rs2
-rw-r--r--crates/ra_lsp_server/src/thread_watcher.rs5
7 files changed, 132 insertions, 72 deletions
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index 1dd495791..b6436b646 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -2,7 +2,7 @@ use languageserver_types::{
2 CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions, 2 CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions,
3 ExecuteCommandOptions, FoldingRangeProviderCapability, ServerCapabilities, 3 ExecuteCommandOptions, FoldingRangeProviderCapability, ServerCapabilities,
4 SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, 4 SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
5 TextDocumentSyncOptions, 5 TextDocumentSyncOptions, RenameProviderCapability, RenameOptions
6}; 6};
7 7
8pub fn server_capabilities() -> ServerCapabilities { 8pub fn server_capabilities() -> ServerCapabilities {
@@ -27,7 +27,7 @@ pub fn server_capabilities() -> ServerCapabilities {
27 definition_provider: Some(true), 27 definition_provider: Some(true),
28 type_definition_provider: None, 28 type_definition_provider: None,
29 implementation_provider: None, 29 implementation_provider: None,
30 references_provider: None, 30 references_provider: Some(true),
31 document_highlight_provider: None, 31 document_highlight_provider: None,
32 document_symbol_provider: Some(true), 32 document_symbol_provider: Some(true),
33 workspace_symbol_provider: Some(true), 33 workspace_symbol_provider: Some(true),
@@ -40,7 +40,9 @@ pub fn server_capabilities() -> ServerCapabilities {
40 more_trigger_character: None, 40 more_trigger_character: None,
41 }), 41 }),
42 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), 42 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
43 rename_provider: None, 43 rename_provider: Some(RenameProviderCapability::Options(RenameOptions{
44 prepare_provider: Some(true)
45 })),
44 color_provider: None, 46 color_provider: None,
45 execute_command_provider: Some(ExecuteCommandOptions { 47 execute_command_provider: Some(ExecuteCommandOptions {
46 commands: vec!["apply_code_action".to_string()], 48 commands: vec!["apply_code_action".to_string()],
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 3e58e6f54..11f34eb93 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -1,11 +1,13 @@
1use rustc_hash::FxHashMap; 1use std::collections::HashMap;
2 2
3use rustc_hash::FxHashMap;
3use languageserver_types::{ 4use languageserver_types::{
4 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic, 5 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic,
5 DiagnosticSeverity, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams, 6 DiagnosticSeverity, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams,
6 InsertTextFormat, Location, Position, SymbolInformation, TextDocumentIdentifier, TextEdit, 7 InsertTextFormat, Location, Position, SymbolInformation, TextDocumentIdentifier, TextEdit,
8 RenameParams, WorkspaceEdit, PrepareRenameResponse
7}; 9};
8use ra_analysis::{FileId, FoldKind, JobToken, Query, RunnableKind}; 10use ra_analysis::{FileId, FoldKind, Query, RunnableKind};
9use ra_syntax::text_utils::contains_offset_nonstrict; 11use ra_syntax::text_utils::contains_offset_nonstrict;
10use serde_json::to_value; 12use serde_json::to_value;
11 13
@@ -20,7 +22,6 @@ use crate::{
20pub fn handle_syntax_tree( 22pub fn handle_syntax_tree(
21 world: ServerWorld, 23 world: ServerWorld,
22 params: req::SyntaxTreeParams, 24 params: req::SyntaxTreeParams,
23 _token: JobToken,
24) -> Result<String> { 25) -> Result<String> {
25 let id = params.text_document.try_conv_with(&world)?; 26 let id = params.text_document.try_conv_with(&world)?;
26 let res = world.analysis().syntax_tree(id); 27 let res = world.analysis().syntax_tree(id);
@@ -30,7 +31,6 @@ pub fn handle_syntax_tree(
30pub fn handle_extend_selection( 31pub fn handle_extend_selection(
31 world: ServerWorld, 32 world: ServerWorld,
32 params: req::ExtendSelectionParams, 33 params: req::ExtendSelectionParams,
33 _token: JobToken,
34) -> Result<req::ExtendSelectionResult> { 34) -> Result<req::ExtendSelectionResult> {
35 let file_id = params.text_document.try_conv_with(&world)?; 35 let file_id = params.text_document.try_conv_with(&world)?;
36 let file = world.analysis().file_syntax(file_id); 36 let file = world.analysis().file_syntax(file_id);
@@ -48,7 +48,6 @@ pub fn handle_extend_selection(
48pub fn handle_find_matching_brace( 48pub fn handle_find_matching_brace(
49 world: ServerWorld, 49 world: ServerWorld,
50 params: req::FindMatchingBraceParams, 50 params: req::FindMatchingBraceParams,
51 _token: JobToken,
52) -> Result<Vec<Position>> { 51) -> Result<Vec<Position>> {
53 let file_id = params.text_document.try_conv_with(&world)?; 52 let file_id = params.text_document.try_conv_with(&world)?;
54 let file = world.analysis().file_syntax(file_id); 53 let file = world.analysis().file_syntax(file_id);
@@ -71,7 +70,6 @@ pub fn handle_find_matching_brace(
71pub fn handle_join_lines( 70pub fn handle_join_lines(
72 world: ServerWorld, 71 world: ServerWorld,
73 params: req::JoinLinesParams, 72 params: req::JoinLinesParams,
74 _token: JobToken,
75) -> Result<req::SourceChange> { 73) -> Result<req::SourceChange> {
76 let file_id = params.text_document.try_conv_with(&world)?; 74 let file_id = params.text_document.try_conv_with(&world)?;
77 let line_index = world.analysis().file_line_index(file_id); 75 let line_index = world.analysis().file_line_index(file_id);
@@ -85,7 +83,6 @@ pub fn handle_join_lines(
85pub fn handle_on_enter( 83pub fn handle_on_enter(
86 world: ServerWorld, 84 world: ServerWorld,
87 params: req::TextDocumentPositionParams, 85 params: req::TextDocumentPositionParams,
88 _token: JobToken,
89) -> Result<Option<req::SourceChange>> { 86) -> Result<Option<req::SourceChange>> {
90 let file_id = params.text_document.try_conv_with(&world)?; 87 let file_id = params.text_document.try_conv_with(&world)?;
91 let line_index = world.analysis().file_line_index(file_id); 88 let line_index = world.analysis().file_line_index(file_id);
@@ -99,7 +96,6 @@ pub fn handle_on_enter(
99pub fn handle_on_type_formatting( 96pub fn handle_on_type_formatting(
100 world: ServerWorld, 97 world: ServerWorld,
101 params: req::DocumentOnTypeFormattingParams, 98 params: req::DocumentOnTypeFormattingParams,
102 _token: JobToken,
103) -> Result<Option<Vec<TextEdit>>> { 99) -> Result<Option<Vec<TextEdit>>> {
104 if params.ch != "=" { 100 if params.ch != "=" {
105 return Ok(None); 101 return Ok(None);
@@ -119,7 +115,6 @@ pub fn handle_on_type_formatting(
119pub fn handle_document_symbol( 115pub fn handle_document_symbol(
120 world: ServerWorld, 116 world: ServerWorld,
121 params: req::DocumentSymbolParams, 117 params: req::DocumentSymbolParams,
122 _token: JobToken,
123) -> Result<Option<req::DocumentSymbolResponse>> { 118) -> Result<Option<req::DocumentSymbolResponse>> {
124 let file_id = params.text_document.try_conv_with(&world)?; 119 let file_id = params.text_document.try_conv_with(&world)?;
125 let line_index = world.analysis().file_line_index(file_id); 120 let line_index = world.analysis().file_line_index(file_id);
@@ -158,7 +153,6 @@ pub fn handle_document_symbol(
158pub fn handle_workspace_symbol( 153pub fn handle_workspace_symbol(
159 world: ServerWorld, 154 world: ServerWorld,
160 params: req::WorkspaceSymbolParams, 155 params: req::WorkspaceSymbolParams,
161 token: JobToken,
162) -> Result<Option<Vec<SymbolInformation>>> { 156) -> Result<Option<Vec<SymbolInformation>>> {
163 let all_symbols = params.query.contains('#'); 157 let all_symbols = params.query.contains('#');
164 let libs = params.query.contains('*'); 158 let libs = params.query.contains('*');
@@ -178,11 +172,11 @@ pub fn handle_workspace_symbol(
178 q.limit(128); 172 q.limit(128);
179 q 173 q
180 }; 174 };
181 let mut res = exec_query(&world, query, &token)?; 175 let mut res = exec_query(&world, query)?;
182 if res.is_empty() && !all_symbols { 176 if res.is_empty() && !all_symbols {
183 let mut query = Query::new(params.query); 177 let mut query = Query::new(params.query);
184 query.limit(128); 178 query.limit(128);
185 res = exec_query(&world, query, &token)?; 179 res = exec_query(&world, query)?;
186 } 180 }
187 181
188 return Ok(Some(res)); 182 return Ok(Some(res));
@@ -190,10 +184,9 @@ pub fn handle_workspace_symbol(
190 fn exec_query( 184 fn exec_query(
191 world: &ServerWorld, 185 world: &ServerWorld,
192 query: Query, 186 query: Query,
193 token: &JobToken,
194 ) -> Result<Vec<SymbolInformation>> { 187 ) -> Result<Vec<SymbolInformation>> {
195 let mut res = Vec::new(); 188 let mut res = Vec::new();
196 for (file_id, symbol) in world.analysis().symbol_search(query, token) { 189 for (file_id, symbol) in world.analysis().symbol_search(query)? {
197 let line_index = world.analysis().file_line_index(file_id); 190 let line_index = world.analysis().file_line_index(file_id);
198 let info = SymbolInformation { 191 let info = SymbolInformation {
199 name: symbol.name.to_string(), 192 name: symbol.name.to_string(),
@@ -211,7 +204,6 @@ pub fn handle_workspace_symbol(
211pub fn handle_goto_definition( 204pub fn handle_goto_definition(
212 world: ServerWorld, 205 world: ServerWorld,
213 params: req::TextDocumentPositionParams, 206 params: req::TextDocumentPositionParams,
214 token: JobToken,
215) -> Result<Option<req::GotoDefinitionResponse>> { 207) -> Result<Option<req::GotoDefinitionResponse>> {
216 let file_id = params.text_document.try_conv_with(&world)?; 208 let file_id = params.text_document.try_conv_with(&world)?;
217 let line_index = world.analysis().file_line_index(file_id); 209 let line_index = world.analysis().file_line_index(file_id);
@@ -219,7 +211,7 @@ pub fn handle_goto_definition(
219 let mut res = Vec::new(); 211 let mut res = Vec::new();
220 for (file_id, symbol) in world 212 for (file_id, symbol) in world
221 .analysis() 213 .analysis()
222 .approximately_resolve_symbol(file_id, offset, &token) 214 .approximately_resolve_symbol(file_id, offset)?
223 { 215 {
224 let line_index = world.analysis().file_line_index(file_id); 216 let line_index = world.analysis().file_line_index(file_id);
225 let location = to_location(file_id, symbol.node_range, &world, &line_index)?; 217 let location = to_location(file_id, symbol.node_range, &world, &line_index)?;
@@ -231,11 +223,10 @@ pub fn handle_goto_definition(
231pub fn handle_parent_module( 223pub fn handle_parent_module(
232 world: ServerWorld, 224 world: ServerWorld,
233 params: TextDocumentIdentifier, 225 params: TextDocumentIdentifier,
234 _token: JobToken,
235) -> Result<Vec<Location>> { 226) -> Result<Vec<Location>> {
236 let file_id = params.try_conv_with(&world)?; 227 let file_id = params.try_conv_with(&world)?;
237 let mut res = Vec::new(); 228 let mut res = Vec::new();
238 for (file_id, symbol) in world.analysis().parent_module(file_id) { 229 for (file_id, symbol) in world.analysis().parent_module(file_id)? {
239 let line_index = world.analysis().file_line_index(file_id); 230 let line_index = world.analysis().file_line_index(file_id);
240 let location = to_location(file_id, symbol.node_range, &world, &line_index)?; 231 let location = to_location(file_id, symbol.node_range, &world, &line_index)?;
241 res.push(location); 232 res.push(location);
@@ -246,20 +237,19 @@ pub fn handle_parent_module(
246pub fn handle_runnables( 237pub fn handle_runnables(
247 world: ServerWorld, 238 world: ServerWorld,
248 params: req::RunnablesParams, 239 params: req::RunnablesParams,
249 _token: JobToken,
250) -> Result<Vec<req::Runnable>> { 240) -> Result<Vec<req::Runnable>> {
251 let file_id = params.text_document.try_conv_with(&world)?; 241 let file_id = params.text_document.try_conv_with(&world)?;
252 let line_index = world.analysis().file_line_index(file_id); 242 let line_index = world.analysis().file_line_index(file_id);
253 let offset = params.position.map(|it| it.conv_with(&line_index)); 243 let offset = params.position.map(|it| it.conv_with(&line_index));
254 let mut res = Vec::new(); 244 let mut res = Vec::new();
255 for runnable in world.analysis().runnables(file_id) { 245 for runnable in world.analysis().runnables(file_id)? {
256 if let Some(offset) = offset { 246 if let Some(offset) = offset {
257 if !contains_offset_nonstrict(runnable.range, offset) { 247 if !contains_offset_nonstrict(runnable.range, offset) {
258 continue; 248 continue;
259 } 249 }
260 } 250 }
261 251
262 let args = runnable_args(&world, file_id, &runnable.kind); 252 let args = runnable_args(&world, file_id, &runnable.kind)?;
263 253
264 let r = req::Runnable { 254 let r = req::Runnable {
265 range: runnable.range.conv_with(&line_index), 255 range: runnable.range.conv_with(&line_index),
@@ -279,9 +269,9 @@ pub fn handle_runnables(
279 } 269 }
280 return Ok(res); 270 return Ok(res);
281 271
282 fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Vec<String> { 272 fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Result<Vec<String>> {
283 let spec = if let Some(&crate_id) = world.analysis().crate_for(file_id).first() { 273 let spec = if let Some(&crate_id) = world.analysis().crate_for(file_id)?.first() {
284 let file_id = world.analysis().crate_root(crate_id); 274 let file_id = world.analysis().crate_root(crate_id)?;
285 let path = world.path_map.get_path(file_id); 275 let path = world.path_map.get_path(file_id);
286 world 276 world
287 .workspaces 277 .workspaces
@@ -316,7 +306,7 @@ pub fn handle_runnables(
316 } 306 }
317 } 307 }
318 } 308 }
319 res 309 Ok(res)
320 } 310 }
321 311
322 fn spec_args(pkg_name: &str, tgt_name: &str, tgt_kind: TargetKind, buf: &mut Vec<String>) { 312 fn spec_args(pkg_name: &str, tgt_name: &str, tgt_kind: TargetKind, buf: &mut Vec<String>) {
@@ -350,21 +340,19 @@ pub fn handle_runnables(
350pub fn handle_decorations( 340pub fn handle_decorations(
351 world: ServerWorld, 341 world: ServerWorld,
352 params: TextDocumentIdentifier, 342 params: TextDocumentIdentifier,
353 _token: JobToken,
354) -> Result<Vec<Decoration>> { 343) -> Result<Vec<Decoration>> {
355 let file_id = params.try_conv_with(&world)?; 344 let file_id = params.try_conv_with(&world)?;
356 Ok(highlight(&world, file_id)) 345 highlight(&world, file_id)
357} 346}
358 347
359pub fn handle_completion( 348pub fn handle_completion(
360 world: ServerWorld, 349 world: ServerWorld,
361 params: req::CompletionParams, 350 params: req::CompletionParams,
362 _token: JobToken,
363) -> Result<Option<req::CompletionResponse>> { 351) -> Result<Option<req::CompletionResponse>> {
364 let file_id = params.text_document.try_conv_with(&world)?; 352 let file_id = params.text_document.try_conv_with(&world)?;
365 let line_index = world.analysis().file_line_index(file_id); 353 let line_index = world.analysis().file_line_index(file_id);
366 let offset = params.position.conv_with(&line_index); 354 let offset = params.position.conv_with(&line_index);
367 let items = match world.analysis().completions(file_id, offset) { 355 let items = match world.analysis().completions(file_id, offset)? {
368 None => return Ok(None), 356 None => return Ok(None),
369 Some(items) => items, 357 Some(items) => items,
370 }; 358 };
@@ -391,7 +379,6 @@ pub fn handle_completion(
391pub fn handle_folding_range( 379pub fn handle_folding_range(
392 world: ServerWorld, 380 world: ServerWorld,
393 params: FoldingRangeParams, 381 params: FoldingRangeParams,
394 _token: JobToken,
395) -> Result<Option<Vec<FoldingRange>>> { 382) -> Result<Option<Vec<FoldingRange>>> {
396 let file_id = params.text_document.try_conv_with(&world)?; 383 let file_id = params.text_document.try_conv_with(&world)?;
397 let line_index = world.analysis().file_line_index(file_id); 384 let line_index = world.analysis().file_line_index(file_id);
@@ -424,7 +411,6 @@ pub fn handle_folding_range(
424pub fn handle_signature_help( 411pub fn handle_signature_help(
425 world: ServerWorld, 412 world: ServerWorld,
426 params: req::TextDocumentPositionParams, 413 params: req::TextDocumentPositionParams,
427 token: JobToken,
428) -> Result<Option<req::SignatureHelp>> { 414) -> Result<Option<req::SignatureHelp>> {
429 use languageserver_types::{ParameterInformation, SignatureInformation}; 415 use languageserver_types::{ParameterInformation, SignatureInformation};
430 416
@@ -433,7 +419,7 @@ pub fn handle_signature_help(
433 let offset = params.position.conv_with(&line_index); 419 let offset = params.position.conv_with(&line_index);
434 420
435 if let Some((descriptor, active_param)) = 421 if let Some((descriptor, active_param)) =
436 world.analysis().resolve_callable(file_id, offset, &token) 422 world.analysis().resolve_callable(file_id, offset)?
437 { 423 {
438 let parameters: Vec<ParameterInformation> = descriptor 424 let parameters: Vec<ParameterInformation> = descriptor
439 .params 425 .params
@@ -460,19 +446,90 @@ pub fn handle_signature_help(
460 } 446 }
461} 447}
462 448
449pub fn handle_prepare_rename(
450 world: ServerWorld,
451 params: req::TextDocumentPositionParams,
452) -> Result<Option<PrepareRenameResponse>> {
453 let file_id = params.text_document.try_conv_with(&world)?;
454 let line_index = world.analysis().file_line_index(file_id);
455 let offset = params.position.conv_with(&line_index);
456
457 // We support renaming references like handle_rename does.
458 // In the future we may want to reject the renaming of things like keywords here too.
459 let refs = world.analysis().find_all_refs(file_id, offset)?;
460 if refs.is_empty() {
461 return Ok(None);
462 }
463
464 let r = refs.first().unwrap();
465 let loc = to_location(r.0, r.1, &world, &line_index)?;
466
467 Ok(Some(PrepareRenameResponse::Range(loc.range)))
468}
469
470pub fn handle_rename(
471 world: ServerWorld,
472 params: RenameParams,
473) -> Result<Option<WorkspaceEdit>> {
474 let file_id = params.text_document.try_conv_with(&world)?;
475 let line_index = world.analysis().file_line_index(file_id);
476 let offset = params.position.conv_with(&line_index);
477
478 if params.new_name.is_empty() {
479 return Ok(None);
480 }
481
482 let refs = world.analysis().find_all_refs(file_id, offset)?;
483 if refs.is_empty() {
484 return Ok(None);
485 }
486
487 let mut changes = HashMap::new();
488 for r in refs {
489 if let Ok(loc) = to_location(r.0, r.1, &world, &line_index) {
490 changes.entry(loc.uri).or_insert(Vec::new()).push(
491 TextEdit {
492 range: loc.range,
493 new_text: params.new_name.clone()
494 });
495 }
496 }
497
498 Ok(Some(WorkspaceEdit {
499 changes: Some(changes),
500
501 // TODO: return this instead if client/server support it. See #144
502 document_changes : None,
503 }))
504}
505
506pub fn handle_references(
507 world: ServerWorld,
508 params: req::ReferenceParams,
509) -> Result<Option<Vec<Location>>> {
510 let file_id = params.text_document.try_conv_with(&world)?;
511 let line_index = world.analysis().file_line_index(file_id);
512 let offset = params.position.conv_with(&line_index);
513
514 let refs = world.analysis().find_all_refs(file_id, offset)?;
515
516 Ok(Some(refs.into_iter()
517 .filter_map(|r| to_location(r.0, r.1, &world, &line_index).ok())
518 .collect()))
519}
520
463pub fn handle_code_action( 521pub fn handle_code_action(
464 world: ServerWorld, 522 world: ServerWorld,
465 params: req::CodeActionParams, 523 params: req::CodeActionParams,
466 _token: JobToken,
467) -> Result<Option<CodeActionResponse>> { 524) -> Result<Option<CodeActionResponse>> {
468 let file_id = params.text_document.try_conv_with(&world)?; 525 let file_id = params.text_document.try_conv_with(&world)?;
469 let line_index = world.analysis().file_line_index(file_id); 526 let line_index = world.analysis().file_line_index(file_id);
470 let range = params.range.conv_with(&line_index); 527 let range = params.range.conv_with(&line_index);
471 528
472 let assists = world.analysis().assists(file_id, range).into_iter(); 529 let assists = world.analysis().assists(file_id, range)?.into_iter();
473 let fixes = world 530 let fixes = world
474 .analysis() 531 .analysis()
475 .diagnostics(file_id) 532 .diagnostics(file_id)?
476 .into_iter() 533 .into_iter()
477 .filter_map(|d| Some((d.range, d.fix?))) 534 .filter_map(|d| Some((d.range, d.fix?)))
478 .filter(|(range, _fix)| contains_offset_nonstrict(*range, range.start())) 535 .filter(|(range, _fix)| contains_offset_nonstrict(*range, range.start()))
@@ -501,7 +558,7 @@ pub fn publish_diagnostics(
501 let line_index = world.analysis().file_line_index(file_id); 558 let line_index = world.analysis().file_line_index(file_id);
502 let diagnostics = world 559 let diagnostics = world
503 .analysis() 560 .analysis()
504 .diagnostics(file_id) 561 .diagnostics(file_id)?
505 .into_iter() 562 .into_iter()
506 .map(|d| Diagnostic { 563 .map(|d| Diagnostic {
507 range: d.range.conv_with(&line_index), 564 range: d.range.conv_with(&line_index),
@@ -522,19 +579,20 @@ pub fn publish_decorations(
522 let uri = world.file_id_to_uri(file_id)?; 579 let uri = world.file_id_to_uri(file_id)?;
523 Ok(req::PublishDecorationsParams { 580 Ok(req::PublishDecorationsParams {
524 uri, 581 uri,
525 decorations: highlight(&world, file_id), 582 decorations: highlight(&world, file_id)?,
526 }) 583 })
527} 584}
528 585
529fn highlight(world: &ServerWorld, file_id: FileId) -> Vec<Decoration> { 586fn highlight(world: &ServerWorld, file_id: FileId) -> Result<Vec<Decoration>> {
530 let line_index = world.analysis().file_line_index(file_id); 587 let line_index = world.analysis().file_line_index(file_id);
531 world 588 let res = world
532 .analysis() 589 .analysis()
533 .highlight(file_id) 590 .highlight(file_id)?
534 .into_iter() 591 .into_iter()
535 .map(|h| Decoration { 592 .map(|h| Decoration {
536 range: h.range.conv_with(&line_index), 593 range: h.range.conv_with(&line_index),
537 tag: h.tag, 594 tag: h.tag,
538 }) 595 })
539 .collect() 596 .collect();
597 Ok(res)
540} 598}
diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop/mod.rs
index a11baf4aa..b35ebd38b 100644
--- a/crates/ra_lsp_server/src/main_loop/mod.rs
+++ b/crates/ra_lsp_server/src/main_loop/mod.rs
@@ -8,9 +8,9 @@ use gen_lsp_server::{
8 handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, 8 handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse,
9}; 9};
10use languageserver_types::NumberOrString; 10use languageserver_types::NumberOrString;
11use ra_analysis::{FileId, JobHandle, JobToken, LibraryData}; 11use ra_analysis::{FileId, LibraryData};
12use rayon::{self, ThreadPool}; 12use rayon::{self, ThreadPool};
13use rustc_hash::FxHashMap; 13use rustc_hash::FxHashSet;
14use serde::{de::DeserializeOwned, Serialize}; 14use serde::{de::DeserializeOwned, Serialize};
15 15
16use crate::{ 16use crate::{
@@ -47,7 +47,7 @@ pub fn main_loop(
47 info!("server initialized, serving requests"); 47 info!("server initialized, serving requests");
48 let mut state = ServerWorldState::new(); 48 let mut state = ServerWorldState::new();
49 49
50 let mut pending_requests = FxHashMap::default(); 50 let mut pending_requests = FxHashSet::default();
51 let mut subs = Subscriptions::new(); 51 let mut subs = Subscriptions::new();
52 let main_res = main_loop_inner( 52 let main_res = main_loop_inner(
53 internal_mode, 53 internal_mode,
@@ -92,7 +92,7 @@ fn main_loop_inner(
92 fs_worker: Worker<PathBuf, (PathBuf, Vec<FileEvent>)>, 92 fs_worker: Worker<PathBuf, (PathBuf, Vec<FileEvent>)>,
93 ws_worker: Worker<PathBuf, Result<CargoWorkspace>>, 93 ws_worker: Worker<PathBuf, Result<CargoWorkspace>>,
94 state: &mut ServerWorldState, 94 state: &mut ServerWorldState,
95 pending_requests: &mut FxHashMap<u64, JobHandle>, 95 pending_requests: &mut FxHashSet<u64>,
96 subs: &mut Subscriptions, 96 subs: &mut Subscriptions,
97) -> Result<()> { 97) -> Result<()> {
98 let (libdata_sender, libdata_receiver) = unbounded(); 98 let (libdata_sender, libdata_receiver) = unbounded();
@@ -204,14 +204,13 @@ fn main_loop_inner(
204fn on_task( 204fn on_task(
205 task: Task, 205 task: Task,
206 msg_sender: &Sender<RawMessage>, 206 msg_sender: &Sender<RawMessage>,
207 pending_requests: &mut FxHashMap<u64, JobHandle>, 207 pending_requests: &mut FxHashSet<u64>,
208) { 208) {
209 match task { 209 match task {
210 Task::Respond(response) => { 210 Task::Respond(response) => {
211 if let Some(handle) = pending_requests.remove(&response.id) { 211 if pending_requests.remove(&response.id) {
212 assert!(handle.has_completed()); 212 msg_sender.send(RawMessage::Response(response))
213 } 213 }
214 msg_sender.send(RawMessage::Response(response))
215 } 214 }
216 Task::Notify(n) => msg_sender.send(RawMessage::Notification(n)), 215 Task::Notify(n) => msg_sender.send(RawMessage::Notification(n)),
217 } 216 }
@@ -219,7 +218,7 @@ fn on_task(
219 218
220fn on_request( 219fn on_request(
221 world: &mut ServerWorldState, 220 world: &mut ServerWorldState,
222 pending_requests: &mut FxHashMap<u64, JobHandle>, 221 pending_requests: &mut FxHashSet<u64>,
223 pool: &ThreadPool, 222 pool: &ThreadPool,
224 sender: &Sender<Task>, 223 sender: &Sender<Task>,
225 req: RawRequest, 224 req: RawRequest,
@@ -248,10 +247,13 @@ fn on_request(
248 .on::<req::CodeActionRequest>(handlers::handle_code_action)? 247 .on::<req::CodeActionRequest>(handlers::handle_code_action)?
249 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)? 248 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
250 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)? 249 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)?
250 .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)?
251 .on::<req::Rename>(handlers::handle_rename)?
252 .on::<req::References>(handlers::handle_references)?
251 .finish(); 253 .finish();
252 match req { 254 match req {
253 Ok((id, handle)) => { 255 Ok(id) => {
254 let inserted = pending_requests.insert(id, handle).is_none(); 256 let inserted = pending_requests.insert(id);
255 assert!(inserted, "duplicate request: {}", id); 257 assert!(inserted, "duplicate request: {}", id);
256 Ok(None) 258 Ok(None)
257 } 259 }
@@ -262,7 +264,7 @@ fn on_request(
262fn on_notification( 264fn on_notification(
263 msg_sender: &Sender<RawMessage>, 265 msg_sender: &Sender<RawMessage>,
264 state: &mut ServerWorldState, 266 state: &mut ServerWorldState,
265 pending_requests: &mut FxHashMap<u64, JobHandle>, 267 pending_requests: &mut FxHashSet<u64>,
266 subs: &mut Subscriptions, 268 subs: &mut Subscriptions,
267 not: RawNotification, 269 not: RawNotification,
268) -> Result<()> { 270) -> Result<()> {
@@ -274,9 +276,7 @@ fn on_notification(
274 panic!("string id's not supported: {:?}", id); 276 panic!("string id's not supported: {:?}", id);
275 } 277 }
276 }; 278 };
277 if let Some(handle) = pending_requests.remove(&id) { 279 pending_requests.remove(&id);
278 handle.cancel();
279 }
280 return Ok(()); 280 return Ok(());
281 } 281 }
282 Err(not) => not, 282 Err(not) => not,
@@ -333,7 +333,7 @@ fn on_notification(
333 333
334struct PoolDispatcher<'a> { 334struct PoolDispatcher<'a> {
335 req: Option<RawRequest>, 335 req: Option<RawRequest>,
336 res: Option<(u64, JobHandle)>, 336 res: Option<u64>,
337 pool: &'a ThreadPool, 337 pool: &'a ThreadPool,
338 world: &'a ServerWorldState, 338 world: &'a ServerWorldState,
339 sender: &'a Sender<Task>, 339 sender: &'a Sender<Task>,
@@ -342,7 +342,7 @@ struct PoolDispatcher<'a> {
342impl<'a> PoolDispatcher<'a> { 342impl<'a> PoolDispatcher<'a> {
343 fn on<'b, R>( 343 fn on<'b, R>(
344 &'b mut self, 344 &'b mut self,
345 f: fn(ServerWorld, R::Params, JobToken) -> Result<R::Result>, 345 f: fn(ServerWorld, R::Params) -> Result<R::Result>,
346 ) -> Result<&'b mut Self> 346 ) -> Result<&'b mut Self>
347 where 347 where
348 R: req::Request, 348 R: req::Request,
@@ -355,11 +355,10 @@ impl<'a> PoolDispatcher<'a> {
355 }; 355 };
356 match req.cast::<R>() { 356 match req.cast::<R>() {
357 Ok((id, params)) => { 357 Ok((id, params)) => {
358 let (handle, token) = JobHandle::new();
359 let world = self.world.snapshot(); 358 let world = self.world.snapshot();
360 let sender = self.sender.clone(); 359 let sender = self.sender.clone();
361 self.pool.spawn(move || { 360 self.pool.spawn(move || {
362 let resp = match f(world, params, token) { 361 let resp = match f(world, params) {
363 Ok(resp) => RawResponse::ok::<R>(id, &resp), 362 Ok(resp) => RawResponse::ok::<R>(id, &resp),
364 Err(e) => { 363 Err(e) => {
365 RawResponse::err(id, ErrorCode::InternalError as i32, e.to_string()) 364 RawResponse::err(id, ErrorCode::InternalError as i32, e.to_string())
@@ -368,14 +367,14 @@ impl<'a> PoolDispatcher<'a> {
368 let task = Task::Respond(resp); 367 let task = Task::Respond(resp);
369 sender.send(task); 368 sender.send(task);
370 }); 369 });
371 self.res = Some((id, handle)); 370 self.res = Some(id);
372 } 371 }
373 Err(req) => self.req = Some(req), 372 Err(req) => self.req = Some(req),
374 } 373 }
375 Ok(self) 374 Ok(self)
376 } 375 }
377 376
378 fn finish(&mut self) -> ::std::result::Result<(u64, JobHandle), RawRequest> { 377 fn finish(&mut self) -> ::std::result::Result<u64, RawRequest> {
379 match (self.res.take(), self.req.take()) { 378 match (self.res.take(), self.req.take()) {
380 (Some(res), None) => Ok(res), 379 (Some(res), None) => Ok(res),
381 (None, Some(req)) => Err(req), 380 (None, Some(req)) => Err(req),
diff --git a/crates/ra_lsp_server/src/path_map.rs b/crates/ra_lsp_server/src/path_map.rs
index 585013acd..d32829382 100644
--- a/crates/ra_lsp_server/src/path_map.rs
+++ b/crates/ra_lsp_server/src/path_map.rs
@@ -1,9 +1,9 @@
1use std::path::{Component, Path, PathBuf};
2
1use im; 3use im;
2use ra_analysis::{FileId, FileResolver}; 4use ra_analysis::{FileId, FileResolver};
3use relative_path::RelativePath; 5use relative_path::RelativePath;
4 6
5use std::path::{Component, Path, PathBuf};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)] 7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum Root { 8pub enum Root {
9 Workspace, 9 Workspace,
diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs
index cedb67bae..cabb336a3 100644
--- a/crates/ra_lsp_server/src/project_model.rs
+++ b/crates/ra_lsp_server/src/project_model.rs
@@ -1,9 +1,9 @@
1use std::path::{Path, PathBuf};
2
1use cargo_metadata::{metadata_run, CargoOpt}; 3use cargo_metadata::{metadata_run, CargoOpt};
2use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
3use rustc_hash::{FxHashMap, FxHashSet}; 5use rustc_hash::{FxHashMap, FxHashSet};
4 6
5use std::path::{Path, PathBuf};
6
7use crate::{ 7use crate::{
8 thread_watcher::{ThreadWatcher, Worker}, 8 thread_watcher::{ThreadWatcher, Worker},
9 Result, 9 Result,
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index b76bfbcbc..6cd04d84c 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -7,7 +7,7 @@ pub use languageserver_types::{
7 CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, 7 CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams,
8 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, 8 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult,
9 PublishDiagnosticsParams, SignatureHelp, TextDocumentEdit, TextDocumentPositionParams, 9 PublishDiagnosticsParams, SignatureHelp, TextDocumentEdit, TextDocumentPositionParams,
10 TextEdit, WorkspaceSymbolParams, 10 TextEdit, WorkspaceSymbolParams, ReferenceParams,
11}; 11};
12 12
13pub enum SyntaxTree {} 13pub enum SyntaxTree {}
diff --git a/crates/ra_lsp_server/src/thread_watcher.rs b/crates/ra_lsp_server/src/thread_watcher.rs
index 6cc586456..5143c77ae 100644
--- a/crates/ra_lsp_server/src/thread_watcher.rs
+++ b/crates/ra_lsp_server/src/thread_watcher.rs
@@ -1,8 +1,9 @@
1use crate::Result; 1use std::thread;
2
2use crossbeam_channel::{bounded, unbounded, Receiver, Sender}; 3use crossbeam_channel::{bounded, unbounded, Receiver, Sender};
3use drop_bomb::DropBomb; 4use drop_bomb::DropBomb;
4 5
5use std::thread; 6use crate::Result;
6 7
7pub struct Worker<I, O> { 8pub struct Worker<I, O> {
8 pub inp: Sender<I>, 9 pub inp: Sender<I>,