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/lib.rs8
-rw-r--r--crates/ra_lsp_server/src/main.rs17
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs79
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;
31mod world; 31mod world;
32mod diagnostics; 32mod diagnostics;
33 33
34use serde::de::DeserializeOwned;
35
34pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; 36pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
35pub use crate::{ 37pub 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
44pub 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
3use lsp_server::Connection; 3use lsp_server::Connection;
4use ra_lsp_server::{show_message, Result, ServerConfig}; 4use ra_lsp_server::{from_json, show_message, Result, ServerConfig};
5use ra_prof; 5use ra_prof;
6 6
7fn main() -> Result<()> { 7fn 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
4use std::{ 4use 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
10use either::Either;
11use lsp_server::ErrorCode; 11use lsp_server::ErrorCode;
12use lsp_types::{ 12use 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};
20use ra_ide::{ 21use 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 {
791pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result<CodeLens> { 812pub 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> =