diff options
Diffstat (limited to 'crates/ra_lsp_server/src/main_loop')
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 121 |
1 files changed, 60 insertions, 61 deletions
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 8e43f0575..65e8bc856 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -1,17 +1,22 @@ | |||
1 | //! This module is responsible for implementing handlers for Lanuage Server Protocol. | 1 | //! This module is responsible for implementing handlers for Lanuage Server Protocol. |
2 | //! The majority of requests are fulfilled by calling into the `ra_ide` crate. | 2 | //! The majority of requests are fulfilled by calling into the `ra_ide` crate. |
3 | 3 | ||
4 | use std::{fmt::Write as _, io::Write as _}; | 4 | use std::{ |
5 | collections::hash_map::Entry, | ||
6 | fmt::Write as _, | ||
7 | io::Write as _, | ||
8 | process::{self, Stdio}, | ||
9 | }; | ||
5 | 10 | ||
6 | use either::Either; | ||
7 | use lsp_server::ErrorCode; | 11 | use lsp_server::ErrorCode; |
8 | use lsp_types::{ | 12 | use lsp_types::{ |
9 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, | 13 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, |
10 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, | 14 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, |
11 | CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic, | 15 | CodeAction, CodeActionOrCommand, CodeActionResponse, CodeLens, Command, CompletionItem, |
12 | DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, | 16 | Diagnostic, DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, |
13 | Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, PrepareRenameResponse, | 17 | FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, |
14 | Range, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, WorkspaceEdit, | 18 | PrepareRenameResponse, Range, RenameParams, SymbolInformation, TextDocumentIdentifier, |
19 | TextEdit, WorkspaceEdit, | ||
15 | }; | 20 | }; |
16 | use ra_ide::{ | 21 | use ra_ide::{ |
17 | AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, | 22 | AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, |
@@ -29,6 +34,7 @@ use crate::{ | |||
29 | to_call_hierarchy_item, to_location, Conv, ConvWith, FoldConvCtx, MapConvWith, TryConvWith, | 34 | to_call_hierarchy_item, to_location, Conv, ConvWith, FoldConvCtx, MapConvWith, TryConvWith, |
30 | TryConvWithToVec, | 35 | TryConvWithToVec, |
31 | }, | 36 | }, |
37 | diagnostics::DiagnosticTask, | ||
32 | req::{self, Decoration, InlayHint, InlayHintsParams, InlayKind}, | 38 | req::{self, Decoration, InlayHint, InlayHintsParams, InlayKind}, |
33 | world::WorldSnapshot, | 39 | world::WorldSnapshot, |
34 | LspError, Result, | 40 | LspError, Result, |
@@ -582,21 +588,19 @@ pub fn handle_formatting( | |||
582 | let file_line_index = world.analysis().file_line_index(file_id)?; | 588 | let file_line_index = world.analysis().file_line_index(file_id)?; |
583 | let end_position = TextUnit::of_str(&file).conv_with(&file_line_index); | 589 | let end_position = TextUnit::of_str(&file).conv_with(&file_line_index); |
584 | 590 | ||
585 | use std::process; | ||
586 | let mut rustfmt = process::Command::new("rustfmt"); | 591 | let mut rustfmt = process::Command::new("rustfmt"); |
587 | if let Some(&crate_id) = crate_ids.first() { | 592 | if let Some(&crate_id) = crate_ids.first() { |
588 | // Assume all crates are in the same edition | 593 | // Assume all crates are in the same edition |
589 | let edition = world.analysis().crate_edition(crate_id)?; | 594 | let edition = world.analysis().crate_edition(crate_id)?; |
590 | rustfmt.args(&["--edition", &edition.to_string()]); | 595 | rustfmt.args(&["--edition", &edition.to_string()]); |
591 | } | 596 | } |
592 | rustfmt.stdin(process::Stdio::piped()).stdout(process::Stdio::piped()); | ||
593 | 597 | ||
594 | if let Ok(path) = params.text_document.uri.to_file_path() { | 598 | if let Ok(path) = params.text_document.uri.to_file_path() { |
595 | if let Some(parent) = path.parent() { | 599 | if let Some(parent) = path.parent() { |
596 | rustfmt.current_dir(parent); | 600 | rustfmt.current_dir(parent); |
597 | } | 601 | } |
598 | } | 602 | } |
599 | let mut rustfmt = rustfmt.spawn()?; | 603 | let mut rustfmt = rustfmt.stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?; |
600 | 604 | ||
601 | rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?; | 605 | rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?; |
602 | 606 | ||
@@ -674,59 +678,61 @@ pub fn handle_code_action( | |||
674 | res.push(action.into()); | 678 | res.push(action.into()); |
675 | } | 679 | } |
676 | 680 | ||
677 | for fix in world.check_watcher.read().fixes_for(¶ms.text_document.uri).into_iter().flatten() | 681 | for fix in world.check_fixes.get(&file_id).into_iter().flatten() { |
678 | { | 682 | let fix_range = fix.range.conv_with(&line_index); |
679 | let fix_range = fix.location.range.conv_with(&line_index); | ||
680 | if fix_range.intersection(&range).is_none() { | 683 | if fix_range.intersection(&range).is_none() { |
681 | continue; | 684 | continue; |
682 | } | 685 | } |
686 | res.push(fix.action.clone()); | ||
687 | } | ||
683 | 688 | ||
684 | let edit = { | 689 | let mut groups = FxHashMap::default(); |
685 | let edits = vec![TextEdit::new(fix.location.range, fix.replacement.clone())]; | 690 | for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() { |
686 | let mut edit_map = std::collections::HashMap::new(); | 691 | let arg = to_value(assist.source_change.try_conv_with(&world)?)?; |
687 | edit_map.insert(fix.location.uri.clone(), edits); | 692 | |
688 | WorkspaceEdit::new(edit_map) | 693 | let (command, title, arg) = match assist.group_label { |
694 | None => ("rust-analyzer.applySourceChange", assist.label.clone(), arg), | ||
695 | |||
696 | // Group all assists with the same `group_label` into a single CodeAction. | ||
697 | Some(group_label) => { | ||
698 | match groups.entry(group_label.clone()) { | ||
699 | Entry::Occupied(entry) => { | ||
700 | let idx: usize = *entry.get(); | ||
701 | match &mut res[idx] { | ||
702 | CodeActionOrCommand::CodeAction(CodeAction { | ||
703 | command: Some(Command { arguments: Some(arguments), .. }), | ||
704 | .. | ||
705 | }) => match arguments.as_mut_slice() { | ||
706 | [serde_json::Value::Array(arguments)] => arguments.push(arg), | ||
707 | _ => panic!("invalid group"), | ||
708 | }, | ||
709 | _ => panic!("invalid group"), | ||
710 | } | ||
711 | continue; | ||
712 | } | ||
713 | Entry::Vacant(entry) => { | ||
714 | entry.insert(res.len()); | ||
715 | } | ||
716 | } | ||
717 | ("rust-analyzer.selectAndApplySourceChange", group_label, to_value(vec![arg])?) | ||
718 | } | ||
689 | }; | 719 | }; |
690 | 720 | ||
691 | let action = CodeAction { | 721 | let command = Command { |
692 | title: fix.title.clone(), | 722 | title: assist.label.clone(), |
693 | kind: Some("quickfix".to_string()), | 723 | command: command.to_string(), |
694 | diagnostics: Some(fix.diagnostics.clone()), | 724 | arguments: Some(vec![arg]), |
695 | edit: Some(edit), | ||
696 | command: None, | ||
697 | is_preferred: None, | ||
698 | }; | 725 | }; |
699 | res.push(action.into()); | ||
700 | } | ||
701 | 726 | ||
702 | for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() { | 727 | let kind = match assist.id { |
703 | let title = assist.label.clone(); | 728 | AssistId("introduce_variable") => Some("refactor.extract.variable".to_string()), |
704 | 729 | AssistId("add_custom_impl") => Some("refactor.rewrite.add_custom_impl".to_string()), | |
705 | let command = match assist.change_data { | 730 | _ => None, |
706 | Either::Left(change) => Command { | ||
707 | title, | ||
708 | command: "rust-analyzer.applySourceChange".to_string(), | ||
709 | arguments: Some(vec![to_value(change.try_conv_with(&world)?)?]), | ||
710 | }, | ||
711 | Either::Right(changes) => Command { | ||
712 | title, | ||
713 | command: "rust-analyzer.selectAndApplySourceChange".to_string(), | ||
714 | arguments: Some(vec![to_value( | ||
715 | changes | ||
716 | .into_iter() | ||
717 | .map(|change| change.try_conv_with(&world)) | ||
718 | .collect::<Result<Vec<_>>>()?, | ||
719 | )?]), | ||
720 | }, | ||
721 | }; | 731 | }; |
722 | 732 | ||
723 | let action = CodeAction { | 733 | let action = CodeAction { |
724 | title: command.title.clone(), | 734 | title, |
725 | kind: match assist.id { | 735 | kind, |
726 | AssistId("introduce_variable") => Some("refactor.extract.variable".to_string()), | ||
727 | AssistId("add_custom_impl") => Some("refactor.rewrite.add_custom_impl".to_string()), | ||
728 | _ => None, | ||
729 | }, | ||
730 | diagnostics: None, | 736 | diagnostics: None, |
731 | edit: None, | 737 | edit: None, |
732 | command: Some(command), | 738 | command: Some(command), |
@@ -874,14 +880,10 @@ pub fn handle_document_highlight( | |||
874 | )) | 880 | )) |
875 | } | 881 | } |
876 | 882 | ||
877 | pub fn publish_diagnostics( | 883 | pub fn publish_diagnostics(world: &WorldSnapshot, file_id: FileId) -> Result<DiagnosticTask> { |
878 | world: &WorldSnapshot, | ||
879 | file_id: FileId, | ||
880 | ) -> Result<req::PublishDiagnosticsParams> { | ||
881 | let _p = profile("publish_diagnostics"); | 884 | let _p = profile("publish_diagnostics"); |
882 | let uri = world.file_id_to_uri(file_id)?; | ||
883 | let line_index = world.analysis().file_line_index(file_id)?; | 885 | let line_index = world.analysis().file_line_index(file_id)?; |
884 | let mut diagnostics: Vec<Diagnostic> = world | 886 | let diagnostics: Vec<Diagnostic> = world |
885 | .analysis() | 887 | .analysis() |
886 | .diagnostics(file_id)? | 888 | .diagnostics(file_id)? |
887 | .into_iter() | 889 | .into_iter() |
@@ -895,10 +897,7 @@ pub fn publish_diagnostics( | |||
895 | tags: None, | 897 | tags: None, |
896 | }) | 898 | }) |
897 | .collect(); | 899 | .collect(); |
898 | if let Some(check_diags) = world.check_watcher.read().diagnostics_for(&uri) { | 900 | Ok(DiagnosticTask::SetNative(file_id, diagnostics)) |
899 | diagnostics.extend(check_diags.iter().cloned()); | ||
900 | } | ||
901 | Ok(req::PublishDiagnosticsParams { uri, diagnostics, version: None }) | ||
902 | } | 901 | } |
903 | 902 | ||
904 | pub fn publish_decorations( | 903 | pub fn publish_decorations( |