aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server/src/main_loop
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_lsp_server/src/main_loop')
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs87
-rw-r--r--crates/ra_lsp_server/src/main_loop/mod.rs31
2 files changed, 58 insertions, 60 deletions
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 20cb5f772..c853ff653 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -1,15 +1,16 @@
1use std::collections::HashMap; 1use std::collections::HashMap;
2 2
3use rustc_hash::FxHashMap; 3use gen_lsp_server::ErrorCode;
4use languageserver_types::{ 4use languageserver_types::{
5 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic, 5 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic,
6 DiagnosticSeverity, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams, 6 DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind,
7 InsertTextFormat, Location, Position, SymbolInformation, TextDocumentIdentifier, TextEdit, 7 FoldingRangeParams, InsertTextFormat, Location, MarkupContent, MarkupKind, Position,
8 RenameParams, WorkspaceEdit, PrepareRenameResponse, Documentation, MarkupContent, MarkupKind 8 PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit,
9 WorkspaceEdit,
9}; 10};
10use gen_lsp_server::ErrorCode;
11use ra_analysis::{FileId, FoldKind, Query, RunnableKind}; 11use ra_analysis::{FileId, FoldKind, Query, RunnableKind};
12use ra_syntax::text_utils::contains_offset_nonstrict; 12use ra_syntax::text_utils::contains_offset_nonstrict;
13use rustc_hash::FxHashMap;
13use serde_json::to_value; 14use serde_json::to_value;
14 15
15use crate::{ 16use crate::{
@@ -17,13 +18,10 @@ use crate::{
17 project_model::TargetKind, 18 project_model::TargetKind,
18 req::{self, Decoration}, 19 req::{self, Decoration},
19 server_world::ServerWorld, 20 server_world::ServerWorld,
20 Result, LspError 21 LspError, Result,
21}; 22};
22 23
23pub fn handle_syntax_tree( 24pub fn handle_syntax_tree(world: ServerWorld, params: req::SyntaxTreeParams) -> Result<String> {
24 world: ServerWorld,
25 params: req::SyntaxTreeParams,
26) -> Result<String> {
27 let id = params.text_document.try_conv_with(&world)?; 25 let id = params.text_document.try_conv_with(&world)?;
28 let res = world.analysis().syntax_tree(id); 26 let res = world.analysis().syntax_tree(id);
29 Ok(res) 27 Ok(res)
@@ -182,10 +180,7 @@ pub fn handle_workspace_symbol(
182 180
183 return Ok(Some(res)); 181 return Ok(Some(res));
184 182
185 fn exec_query( 183 fn exec_query(world: &ServerWorld, query: Query) -> Result<Vec<SymbolInformation>> {
186 world: &ServerWorld,
187 query: Query,
188 ) -> Result<Vec<SymbolInformation>> {
189 let mut res = Vec::new(); 184 let mut res = Vec::new();
190 for (file_id, symbol) in world.analysis().symbol_search(query)? { 185 for (file_id, symbol) in world.analysis().symbol_search(query)? {
191 let line_index = world.analysis().file_line_index(file_id); 186 let line_index = world.analysis().file_line_index(file_id);
@@ -290,7 +285,11 @@ pub fn handle_runnables(
290 }); 285 });
291 return Ok(res); 286 return Ok(res);
292 287
293 fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Result<Vec<String>> { 288 fn runnable_args(
289 world: &ServerWorld,
290 file_id: FileId,
291 kind: &RunnableKind,
292 ) -> Result<Vec<String>> {
294 let spec = CargoTargetSpec::for_file(world, file_id)?; 293 let spec = CargoTargetSpec::for_file(world, file_id)?;
295 let mut res = Vec::new(); 294 let mut res = Vec::new();
296 match kind { 295 match kind {
@@ -327,18 +326,15 @@ pub fn handle_runnables(
327 }; 326 };
328 let file_id = world.analysis().crate_root(crate_id)?; 327 let file_id = world.analysis().crate_root(crate_id)?;
329 let path = world.path_map.get_path(file_id); 328 let path = world.path_map.get_path(file_id);
330 let res = world 329 let res = world.workspaces.iter().find_map(|ws| {
331 .workspaces 330 let tgt = ws.target_by_root(path)?;
332 .iter() 331 let res = CargoTargetSpec {
333 .find_map(|ws| { 332 package: tgt.package(ws).name(ws).to_string(),
334 let tgt = ws.target_by_root(path)?; 333 target: tgt.name(ws).to_string(),
335 let res = CargoTargetSpec { 334 target_kind: tgt.kind(ws),
336 package: tgt.package(ws).name(ws).to_string(), 335 };
337 target: tgt.name(ws).to_string(), 336 Some(res)
338 target_kind: tgt.kind(ws), 337 });
339 };
340 Some(res)
341 });
342 Ok(res) 338 Ok(res)
343 } 339 }
344 340
@@ -367,7 +363,6 @@ pub fn handle_runnables(
367 } 363 }
368 TargetKind::Other => (), 364 TargetKind::Other => (),
369 } 365 }
370
371 } 366 }
372 } 367 }
373} 368}
@@ -453,9 +448,7 @@ pub fn handle_signature_help(
453 let line_index = world.analysis().file_line_index(file_id); 448 let line_index = world.analysis().file_line_index(file_id);
454 let offset = params.position.conv_with(&line_index); 449 let offset = params.position.conv_with(&line_index);
455 450
456 if let Some((descriptor, active_param)) = 451 if let Some((descriptor, active_param)) = world.analysis().resolve_callable(file_id, offset)? {
457 world.analysis().resolve_callable(file_id, offset)?
458 {
459 let parameters: Vec<ParameterInformation> = descriptor 452 let parameters: Vec<ParameterInformation> = descriptor
460 .params 453 .params
461 .iter() 454 .iter()
@@ -468,7 +461,7 @@ pub fn handle_signature_help(
468 let documentation = if let Some(doc) = descriptor.doc { 461 let documentation = if let Some(doc) = descriptor.doc {
469 Some(Documentation::MarkupContent(MarkupContent { 462 Some(Documentation::MarkupContent(MarkupContent {
470 kind: MarkupKind::Markdown, 463 kind: MarkupKind::Markdown,
471 value: doc 464 value: doc,
472 })) 465 }))
473 } else { 466 } else {
474 None 467 None
@@ -511,16 +504,17 @@ pub fn handle_prepare_rename(
511 Ok(Some(PrepareRenameResponse::Range(loc.range))) 504 Ok(Some(PrepareRenameResponse::Range(loc.range)))
512} 505}
513 506
514pub fn handle_rename( 507pub fn handle_rename(world: ServerWorld, params: RenameParams) -> Result<Option<WorkspaceEdit>> {
515 world: ServerWorld,
516 params: RenameParams,
517) -> Result<Option<WorkspaceEdit>> {
518 let file_id = params.text_document.try_conv_with(&world)?; 508 let file_id = params.text_document.try_conv_with(&world)?;
519 let line_index = world.analysis().file_line_index(file_id); 509 let line_index = world.analysis().file_line_index(file_id);
520 let offset = params.position.conv_with(&line_index); 510 let offset = params.position.conv_with(&line_index);
521 511
522 if params.new_name.is_empty() { 512 if params.new_name.is_empty() {
523 return Err(LspError::new(ErrorCode::InvalidParams as i32, "New Name cannot be empty".into()).into()); 513 return Err(LspError::new(
514 ErrorCode::InvalidParams as i32,
515 "New Name cannot be empty".into(),
516 )
517 .into());
524 } 518 }
525 519
526 let refs = world.analysis().find_all_refs(file_id, offset)?; 520 let refs = world.analysis().find_all_refs(file_id, offset)?;
@@ -531,11 +525,10 @@ pub fn handle_rename(
531 let mut changes = HashMap::new(); 525 let mut changes = HashMap::new();
532 for r in refs { 526 for r in refs {
533 if let Ok(loc) = to_location(r.0, r.1, &world, &line_index) { 527 if let Ok(loc) = to_location(r.0, r.1, &world, &line_index) {
534 changes.entry(loc.uri).or_insert(Vec::new()).push( 528 changes.entry(loc.uri).or_insert(Vec::new()).push(TextEdit {
535 TextEdit { 529 range: loc.range,
536 range: loc.range, 530 new_text: params.new_name.clone(),
537 new_text: params.new_name.clone() 531 });
538 });
539 } 532 }
540 } 533 }
541 534
@@ -543,7 +536,7 @@ pub fn handle_rename(
543 changes: Some(changes), 536 changes: Some(changes),
544 537
545 // TODO: return this instead if client/server support it. See #144 538 // TODO: return this instead if client/server support it. See #144
546 document_changes : None, 539 document_changes: None,
547 })) 540 }))
548} 541}
549 542
@@ -557,9 +550,11 @@ pub fn handle_references(
557 550
558 let refs = world.analysis().find_all_refs(file_id, offset)?; 551 let refs = world.analysis().find_all_refs(file_id, offset)?;
559 552
560 Ok(Some(refs.into_iter() 553 Ok(Some(
561 .filter_map(|r| to_location(r.0, r.1, &world, &line_index).ok()) 554 refs.into_iter()
562 .collect())) 555 .filter_map(|r| to_location(r.0, r.1, &world, &line_index).ok())
556 .collect(),
557 ))
563} 558}
564 559
565pub fn handle_code_action( 560pub fn handle_code_action(
diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop/mod.rs
index 9ddc3fd0b..c568706bd 100644
--- a/crates/ra_lsp_server/src/main_loop/mod.rs
+++ b/crates/ra_lsp_server/src/main_loop/mod.rs
@@ -24,7 +24,10 @@ use crate::{
24}; 24};
25 25
26#[derive(Debug, Fail)] 26#[derive(Debug, Fail)]
27#[fail(display = "Language Server request failed with {}. ({})", code, message)] 27#[fail(
28 display = "Language Server request failed with {}. ({})",
29 code, message
30)]
28pub struct LspError { 31pub struct LspError {
29 pub code: i32, 32 pub code: i32,
30 pub message: String, 33 pub message: String,
@@ -32,7 +35,7 @@ pub struct LspError {
32 35
33impl LspError { 36impl LspError {
34 pub fn new(code: i32, message: String) -> LspError { 37 pub fn new(code: i32, message: String) -> LspError {
35 LspError {code, message} 38 LspError { code, message }
36 } 39 }
37} 40}
38 41
@@ -214,11 +217,7 @@ fn main_loop_inner(
214 } 217 }
215} 218}
216 219
217fn on_task( 220fn on_task(task: Task, msg_sender: &Sender<RawMessage>, pending_requests: &mut FxHashSet<u64>) {
218 task: Task,
219 msg_sender: &Sender<RawMessage>,
220 pending_requests: &mut FxHashSet<u64>,
221) {
222 match task { 221 match task {
223 Task::Respond(response) => { 222 Task::Respond(response) => {
224 if pending_requests.remove(&response.id) { 223 if pending_requests.remove(&response.id) {
@@ -373,12 +372,16 @@ impl<'a> PoolDispatcher<'a> {
373 self.pool.spawn(move || { 372 self.pool.spawn(move || {
374 let resp = match f(world, params) { 373 let resp = match f(world, params) {
375 Ok(resp) => RawResponse::ok::<R>(id, &resp), 374 Ok(resp) => RawResponse::ok::<R>(id, &resp),
376 Err(e) => { 375 Err(e) => match e.downcast::<LspError>() {
377 match e.downcast::<LspError>() { 376 Ok(lsp_error) => {
378 Ok(lsp_error) => RawResponse::err(id, lsp_error.code, lsp_error.message), 377 RawResponse::err(id, lsp_error.code, lsp_error.message)
379 Err(e) => RawResponse::err(id, ErrorCode::InternalError as i32, format!("{}\n{}", e, e.backtrace()))
380 } 378 }
381 } 379 Err(e) => RawResponse::err(
380 id,
381 ErrorCode::InternalError as i32,
382 format!("{}\n{}", e, e.backtrace()),
383 ),
384 },
382 }; 385 };
383 let task = Task::Respond(resp); 386 let task = Task::Respond(resp);
384 sender.send(task); 387 sender.send(task);
@@ -412,7 +415,7 @@ fn update_file_notifications_on_threadpool(
412 if !is_canceled(&e) { 415 if !is_canceled(&e) {
413 error!("failed to compute diagnostics: {:?}", e); 416 error!("failed to compute diagnostics: {:?}", e);
414 } 417 }
415 }, 418 }
416 Ok(params) => { 419 Ok(params) => {
417 let not = RawNotification::new::<req::PublishDiagnostics>(&params); 420 let not = RawNotification::new::<req::PublishDiagnostics>(&params);
418 sender.send(Task::Notify(not)); 421 sender.send(Task::Notify(not));
@@ -423,7 +426,7 @@ fn update_file_notifications_on_threadpool(
423 if !is_canceled(&e) { 426 if !is_canceled(&e) {
424 error!("failed to compute decorations: {:?}", e); 427 error!("failed to compute decorations: {:?}", e);
425 } 428 }
426 }, 429 }
427 Ok(params) => { 430 Ok(params) => {
428 let not = RawNotification::new::<req::PublishDecorations>(&params); 431 let not = RawNotification::new::<req::PublishDecorations>(&params);
429 sender.send(Task::Notify(not)) 432 sender.send(Task::Notify(not))