aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/assist_ctx.rs7
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs7
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs125
3 files changed, 73 insertions, 66 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index c25d2e323..62182cf03 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -166,8 +166,11 @@ impl<'a> AssistGroup<'a> {
166 } 166 }
167 167
168 pub(crate) fn finish(self) -> Option<Assist> { 168 pub(crate) fn finish(self) -> Option<Assist> {
169 assert!(!self.assists.is_empty()); 169 if self.assists.is_empty() {
170 Some(Assist(self.assists)) 170 None
171 } else {
172 Some(Assist(self.assists))
173 }
171 } 174 }
172} 175}
173 176
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs
index c8bf181f9..4b62aac48 100644
--- a/crates/ra_assists/src/handlers/auto_import.rs
+++ b/crates/ra_assists/src/handlers/auto_import.rs
@@ -42,12 +42,7 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
42 return None; 42 return None;
43 } 43 }
44 44
45 let assist_group_name = if proposed_imports.len() == 1 { 45 let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message());
46 format!("Import `{}`", proposed_imports.iter().next().unwrap())
47 } else {
48 auto_import_assets.get_import_group_message()
49 };
50 let mut group = ctx.add_assist_group(assist_group_name);
51 for import in proposed_imports { 46 for import in proposed_imports {
52 group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| { 47 group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| {
53 edit.target(auto_import_assets.syntax_under_caret.text_range()); 48 edit.target(auto_import_assets.syntax_under_caret.text_range());
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index f51263f22..b5db1fd38 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -3,7 +3,6 @@
3//! `ra_ide` crate. 3//! `ra_ide` crate.
4 4
5use std::{ 5use std::{
6 collections::hash_map::Entry,
7 fmt::Write as _, 6 fmt::Write as _,
8 io::Write as _, 7 io::Write as _,
9 process::{self, Stdio}, 8 process::{self, Stdio},
@@ -13,15 +12,15 @@ use lsp_server::ErrorCode;
13use lsp_types::{ 12use lsp_types::{
14 CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, 13 CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
15 CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, 14 CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
16 CodeAction, CodeActionOrCommand, CodeActionResponse, CodeLens, Command, CompletionItem, 15 CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic,
17 Diagnostic, DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, 16 DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams,
18 FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, 17 Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, PrepareRenameResponse,
19 PrepareRenameResponse, Range, RenameParams, SemanticTokens, SemanticTokensParams, 18 Range, RenameParams, SemanticTokens, SemanticTokensParams, SemanticTokensRangeParams,
20 SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, 19 SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, TextDocumentIdentifier,
21 TextDocumentIdentifier, TextEdit, WorkspaceEdit, 20 TextEdit, WorkspaceEdit,
22}; 21};
23use ra_ide::{ 22use ra_ide::{
24 AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, 23 Assist, AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind,
25 SearchScope, 24 SearchScope,
26}; 25};
27use ra_prof::profile; 26use ra_prof::profile;
@@ -649,6 +648,31 @@ pub fn handle_formatting(
649 }])) 648 }]))
650} 649}
651 650
651fn create_single_code_action(assist: Assist, world: &WorldSnapshot) -> Result<CodeAction> {
652 let arg = to_value(assist.source_change.try_conv_with(world)?)?;
653 let title = assist.label;
654 let command = Command {
655 title: title.clone(),
656 command: "rust-analyzer.applySourceChange".to_string(),
657 arguments: Some(vec![arg]),
658 };
659
660 let kind = match assist.id {
661 AssistId("introduce_variable") => Some("refactor.extract.variable".to_string()),
662 AssistId("add_custom_impl") => Some("refactor.rewrite.add_custom_impl".to_string()),
663 _ => None,
664 };
665
666 Ok(CodeAction {
667 title,
668 kind,
669 diagnostics: None,
670 edit: None,
671 command: Some(command),
672 is_preferred: None,
673 })
674}
675
652pub fn handle_code_action( 676pub fn handle_code_action(
653 world: WorldSnapshot, 677 world: WorldSnapshot,
654 params: req::CodeActionParams, 678 params: req::CodeActionParams,
@@ -695,59 +719,44 @@ pub fn handle_code_action(
695 res.push(fix.action.clone()); 719 res.push(fix.action.clone());
696 } 720 }
697 721
698 let mut groups = FxHashMap::default(); 722 let mut grouped_assists: FxHashMap<String, Vec<Assist>> = FxHashMap::default();
699 for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() { 723 for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() {
700 let arg = to_value(assist.source_change.try_conv_with(&world)?)?; 724 match &assist.group_label {
701 725 Some(label) => grouped_assists.entry(label.to_owned()).or_default().push(assist),
702 let (command, title, arg) = match assist.group_label { 726 None => res.push(create_single_code_action(assist, &world)?.into()),
703 None => ("rust-analyzer.applySourceChange", assist.label.clone(), arg), 727 }
704 728 }
705 // Group all assists with the same `group_label` into a single CodeAction.
706 Some(group_label) => {
707 match groups.entry(group_label.clone()) {
708 Entry::Occupied(entry) => {
709 let idx: usize = *entry.get();
710 match &mut res[idx] {
711 CodeActionOrCommand::CodeAction(CodeAction {
712 command: Some(Command { arguments: Some(arguments), .. }),
713 ..
714 }) => match arguments.as_mut_slice() {
715 [serde_json::Value::Array(arguments)] => arguments.push(arg),
716 _ => panic!("invalid group"),
717 },
718 _ => panic!("invalid group"),
719 }
720 continue;
721 }
722 Entry::Vacant(entry) => {
723 entry.insert(res.len());
724 }
725 }
726 ("rust-analyzer.selectAndApplySourceChange", group_label, to_value(vec![arg])?)
727 }
728 };
729
730 let command = Command {
731 title: assist.label.clone(),
732 command: command.to_string(),
733 arguments: Some(vec![arg]),
734 };
735 729
736 let kind = match assist.id { 730 for (group_label, assists) in grouped_assists {
737 AssistId("introduce_variable") => Some("refactor.extract.variable".to_string()), 731 if assists.len() == 1 {
738 AssistId("add_custom_impl") => Some("refactor.rewrite.add_custom_impl".to_string()), 732 res.push(
739 _ => None, 733 create_single_code_action(assists.into_iter().next().unwrap(), &world)?.into(),
740 }; 734 );
735 } else {
736 let title = group_label;
737
738 let mut arguments = Vec::with_capacity(assists.len());
739 for assist in assists {
740 arguments.push(to_value(assist.source_change.try_conv_with(&world)?)?);
741 }
741 742
742 let action = CodeAction { 743 let command = Some(Command {
743 title, 744 title: title.clone(),
744 kind, 745 command: "rust-analyzer.selectAndApplySourceChange".to_string(),
745 diagnostics: None, 746 arguments: Some(vec![serde_json::Value::Array(arguments)]),
746 edit: None, 747 });
747 command: Some(command), 748 res.push(
748 is_preferred: None, 749 CodeAction {
749 }; 750 title,
750 res.push(action.into()); 751 kind: None,
752 diagnostics: None,
753 edit: None,
754 command,
755 is_preferred: None,
756 }
757 .into(),
758 );
759 }
751 } 760 }
752 761
753 Ok(Some(res)) 762 Ok(Some(res))