diff options
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r-- | crates/ra_lsp_server/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main.rs | 17 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 79 |
3 files changed, 65 insertions, 39 deletions
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs index 1208c1343..a3464a5a3 100644 --- a/crates/ra_lsp_server/src/lib.rs +++ b/crates/ra_lsp_server/src/lib.rs | |||
@@ -31,6 +31,8 @@ mod config; | |||
31 | mod world; | 31 | mod world; |
32 | mod diagnostics; | 32 | mod diagnostics; |
33 | 33 | ||
34 | use serde::de::DeserializeOwned; | ||
35 | |||
34 | pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; | 36 | pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; |
35 | pub use crate::{ | 37 | pub use crate::{ |
36 | caps::server_capabilities, | 38 | caps::server_capabilities, |
@@ -38,3 +40,9 @@ pub use crate::{ | |||
38 | main_loop::LspError, | 40 | main_loop::LspError, |
39 | main_loop::{main_loop, show_message}, | 41 | main_loop::{main_loop, show_message}, |
40 | }; | 42 | }; |
43 | |||
44 | pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> { | ||
45 | let res = T::deserialize(&json) | ||
46 | .map_err(|e| format!("Failed to deserialize {}: {}; {}", what, e, json))?; | ||
47 | Ok(res) | ||
48 | } | ||
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs index 3879eeff2..c8a017c5c 100644 --- a/crates/ra_lsp_server/src/main.rs +++ b/crates/ra_lsp_server/src/main.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! `ra_lsp_server` binary | 1 | //! `ra_lsp_server` binary |
2 | 2 | ||
3 | use lsp_server::Connection; | 3 | use lsp_server::Connection; |
4 | use ra_lsp_server::{show_message, Result, ServerConfig}; | 4 | use ra_lsp_server::{from_json, show_message, Result, ServerConfig}; |
5 | use ra_prof; | 5 | use ra_prof; |
6 | 6 | ||
7 | fn main() -> Result<()> { | 7 | fn main() -> Result<()> { |
@@ -45,7 +45,8 @@ fn run_server() -> Result<()> { | |||
45 | let server_capabilities = serde_json::to_value(ra_lsp_server::server_capabilities()).unwrap(); | 45 | let server_capabilities = serde_json::to_value(ra_lsp_server::server_capabilities()).unwrap(); |
46 | 46 | ||
47 | let initialize_params = connection.initialize(server_capabilities)?; | 47 | let initialize_params = connection.initialize(server_capabilities)?; |
48 | let initialize_params: lsp_types::InitializeParams = serde_json::from_value(initialize_params)?; | 48 | let initialize_params = |
49 | from_json::<lsp_types::InitializeParams>("InitializeParams", initialize_params)?; | ||
49 | 50 | ||
50 | if let Some(client_info) = initialize_params.client_info { | 51 | if let Some(client_info) = initialize_params.client_info { |
51 | log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); | 52 | log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); |
@@ -62,17 +63,13 @@ fn run_server() -> Result<()> { | |||
62 | .filter(|workspaces| !workspaces.is_empty()) | 63 | .filter(|workspaces| !workspaces.is_empty()) |
63 | .unwrap_or_else(|| vec![root]); | 64 | .unwrap_or_else(|| vec![root]); |
64 | 65 | ||
65 | let server_config: ServerConfig = initialize_params | 66 | let server_config = initialize_params |
66 | .initialization_options | 67 | .initialization_options |
67 | .and_then(|v| { | 68 | .and_then(|v| { |
68 | serde_json::from_value(v) | 69 | from_json::<ServerConfig>("config", v) |
69 | .map_err(|e| { | 70 | .map_err(|e| { |
70 | log::error!("failed to deserialize config: {}", e); | 71 | log::error!("{}", e); |
71 | show_message( | 72 | show_message(lsp_types::MessageType::Error, e.to_string(), &connection.sender); |
72 | lsp_types::MessageType::Error, | ||
73 | format!("failed to deserialize config: {}", e), | ||
74 | &connection.sender, | ||
75 | ); | ||
76 | }) | 73 | }) |
77 | .ok() | 74 | .ok() |
78 | }) | 75 | }) |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 282f6e8fc..59c86bbfa 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -2,20 +2,21 @@ | |||
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::{ | 4 | use std::{ |
5 | collections::hash_map::Entry, | ||
5 | fmt::Write as _, | 6 | fmt::Write as _, |
6 | io::Write as _, | 7 | io::Write as _, |
7 | process::{self, Stdio}, | 8 | process::{self, Stdio}, |
8 | }; | 9 | }; |
9 | 10 | ||
10 | use either::Either; | ||
11 | use lsp_server::ErrorCode; | 11 | use lsp_server::ErrorCode; |
12 | use lsp_types::{ | 12 | use lsp_types::{ |
13 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, | 13 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, |
14 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, | 14 | CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, |
15 | CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic, | 15 | CodeAction, CodeActionOrCommand, CodeActionResponse, CodeLens, Command, CompletionItem, |
16 | DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, | 16 | Diagnostic, DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, |
17 | Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, PrepareRenameResponse, | 17 | FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, |
18 | Range, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, WorkspaceEdit, | 18 | PrepareRenameResponse, Range, RenameParams, SymbolInformation, TextDocumentIdentifier, |
19 | TextEdit, WorkspaceEdit, | ||
19 | }; | 20 | }; |
20 | use ra_ide::{ | 21 | use ra_ide::{ |
21 | AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, | 22 | AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, |
@@ -34,6 +35,7 @@ use crate::{ | |||
34 | TryConvWithToVec, | 35 | TryConvWithToVec, |
35 | }, | 36 | }, |
36 | diagnostics::DiagnosticTask, | 37 | diagnostics::DiagnosticTask, |
38 | from_json, | ||
37 | req::{self, Decoration, InlayHint, InlayHintsParams, InlayKind}, | 39 | req::{self, Decoration, InlayHint, InlayHintsParams, InlayKind}, |
38 | world::WorldSnapshot, | 40 | world::WorldSnapshot, |
39 | LspError, Result, | 41 | LspError, Result, |
@@ -685,34 +687,53 @@ pub fn handle_code_action( | |||
685 | res.push(fix.action.clone()); | 687 | res.push(fix.action.clone()); |
686 | } | 688 | } |
687 | 689 | ||
690 | let mut groups = FxHashMap::default(); | ||
688 | for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() { | 691 | for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() { |
689 | let title = assist.label.clone(); | 692 | let arg = to_value(assist.source_change.try_conv_with(&world)?)?; |
693 | |||
694 | let (command, title, arg) = match assist.group_label { | ||
695 | None => ("rust-analyzer.applySourceChange", assist.label.clone(), arg), | ||
696 | |||
697 | // Group all assists with the same `group_label` into a single CodeAction. | ||
698 | Some(group_label) => { | ||
699 | match groups.entry(group_label.clone()) { | ||
700 | Entry::Occupied(entry) => { | ||
701 | let idx: usize = *entry.get(); | ||
702 | match &mut res[idx] { | ||
703 | CodeActionOrCommand::CodeAction(CodeAction { | ||
704 | command: Some(Command { arguments: Some(arguments), .. }), | ||
705 | .. | ||
706 | }) => match arguments.as_mut_slice() { | ||
707 | [serde_json::Value::Array(arguments)] => arguments.push(arg), | ||
708 | _ => panic!("invalid group"), | ||
709 | }, | ||
710 | _ => panic!("invalid group"), | ||
711 | } | ||
712 | continue; | ||
713 | } | ||
714 | Entry::Vacant(entry) => { | ||
715 | entry.insert(res.len()); | ||
716 | } | ||
717 | } | ||
718 | ("rust-analyzer.selectAndApplySourceChange", group_label, to_value(vec![arg])?) | ||
719 | } | ||
720 | }; | ||
690 | 721 | ||
691 | let command = match assist.change_data { | 722 | let command = Command { |
692 | Either::Left(change) => Command { | 723 | title: assist.label.clone(), |
693 | title, | 724 | command: command.to_string(), |
694 | command: "rust-analyzer.applySourceChange".to_string(), | 725 | arguments: Some(vec![arg]), |
695 | arguments: Some(vec![to_value(change.try_conv_with(&world)?)?]), | 726 | }; |
696 | }, | 727 | |
697 | Either::Right(changes) => Command { | 728 | let kind = match assist.id { |
698 | title, | 729 | AssistId("introduce_variable") => Some("refactor.extract.variable".to_string()), |
699 | command: "rust-analyzer.selectAndApplySourceChange".to_string(), | 730 | AssistId("add_custom_impl") => Some("refactor.rewrite.add_custom_impl".to_string()), |
700 | arguments: Some(vec![to_value( | 731 | _ => None, |
701 | changes | ||
702 | .into_iter() | ||
703 | .map(|change| change.try_conv_with(&world)) | ||
704 | .collect::<Result<Vec<_>>>()?, | ||
705 | )?]), | ||
706 | }, | ||
707 | }; | 732 | }; |
708 | 733 | ||
709 | let action = CodeAction { | 734 | let action = CodeAction { |
710 | title: command.title.clone(), | 735 | title, |
711 | kind: match assist.id { | 736 | kind, |
712 | AssistId("introduce_variable") => Some("refactor.extract.variable".to_string()), | ||
713 | AssistId("add_custom_impl") => Some("refactor.rewrite.add_custom_impl".to_string()), | ||
714 | _ => None, | ||
715 | }, | ||
716 | diagnostics: None, | 737 | diagnostics: None, |
717 | edit: None, | 738 | edit: None, |
718 | command: Some(command), | 739 | command: Some(command), |
@@ -791,7 +812,7 @@ enum CodeLensResolveData { | |||
791 | pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result<CodeLens> { | 812 | pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result<CodeLens> { |
792 | let _p = profile("handle_code_lens_resolve"); | 813 | let _p = profile("handle_code_lens_resolve"); |
793 | let data = code_lens.data.unwrap(); | 814 | let data = code_lens.data.unwrap(); |
794 | let resolve = serde_json::from_value(data)?; | 815 | let resolve = from_json::<Option<CodeLensResolveData>>("CodeLensResolveData", data)?; |
795 | match resolve { | 816 | match resolve { |
796 | Some(CodeLensResolveData::Impls(lens_params)) => { | 817 | Some(CodeLensResolveData::Impls(lens_params)) => { |
797 | let locations: Vec<Location> = | 818 | let locations: Vec<Location> = |