diff options
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 7 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/auto_import.rs | 7 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 125 |
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 | ||
5 | use std::{ | 5 | use 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; | |||
13 | use lsp_types::{ | 12 | use 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 | }; |
23 | use ra_ide::{ | 22 | use 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 | }; |
27 | use ra_prof::profile; | 26 | use ra_prof::profile; |
@@ -649,6 +648,31 @@ pub fn handle_formatting( | |||
649 | }])) | 648 | }])) |
650 | } | 649 | } |
651 | 650 | ||
651 | fn 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 | |||
652 | pub fn handle_code_action( | 676 | pub 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)) |