33//! `ra_ide` crate.
44
55use std:: {
6- collections:: hash_map:: Entry ,
76 fmt:: Write as _,
87 io:: Write as _,
98 process:: { self , Stdio } ,
@@ -13,15 +12,15 @@ use lsp_server::ErrorCode;
1312use lsp_types:: {
1413 CallHierarchyIncomingCall , CallHierarchyIncomingCallsParams , CallHierarchyItem ,
1514 CallHierarchyOutgoingCall , CallHierarchyOutgoingCallsParams , CallHierarchyPrepareParams ,
16- CodeAction , CodeActionOrCommand , CodeActionResponse , CodeLens , Command , CompletionItem ,
17- Diagnostic , DocumentFormattingParams , DocumentHighlight , DocumentSymbol , FoldingRange ,
18- FoldingRangeParams , Hover , HoverContents , Location , MarkupContent , MarkupKind , Position ,
19- PrepareRenameResponse , Range , RenameParams , SemanticTokens , SemanticTokensParams ,
20- SemanticTokensRangeParams , SemanticTokensRangeResult , SemanticTokensResult , SymbolInformation ,
21- TextDocumentIdentifier , TextEdit , WorkspaceEdit ,
15+ CodeAction , CodeActionResponse , CodeLens , Command , CompletionItem , Diagnostic ,
16+ DocumentFormattingParams , DocumentHighlight , DocumentSymbol , FoldingRange , FoldingRangeParams ,
17+ Hover , HoverContents , Location , MarkupContent , MarkupKind , Position , PrepareRenameResponse ,
18+ Range , RenameParams , SemanticTokens , SemanticTokensParams , SemanticTokensRangeParams ,
19+ SemanticTokensRangeResult , SemanticTokensResult , SymbolInformation , TextDocumentIdentifier ,
20+ TextEdit , WorkspaceEdit ,
2221} ;
2322use ra_ide:: {
24- AssistId , FileId , FilePosition , FileRange , Query , RangeInfo , Runnable , RunnableKind ,
23+ Assist , AssistId , FileId , FilePosition , FileRange , Query , RangeInfo , Runnable , RunnableKind ,
2524 SearchScope ,
2625} ;
2726use ra_prof:: profile;
@@ -649,6 +648,31 @@ pub fn handle_formatting(
649648 } ] ) )
650649}
651650
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+
652676pub fn handle_code_action (
653677 world : WorldSnapshot ,
654678 params : req:: CodeActionParams ,
@@ -695,59 +719,44 @@ pub fn handle_code_action(
695719 res. push ( fix. action . clone ( ) ) ;
696720 }
697721
698- let mut groups = FxHashMap :: default ( ) ;
722+ let mut grouped_assists : FxHashMap < String , Vec < Assist > > = FxHashMap :: default ( ) ;
699723 for assist in world. analysis ( ) . assists ( FileRange { file_id, range } ) ?. into_iter ( ) {
700- let arg = to_value ( assist. source_change . try_conv_with ( & world) ?) ?;
701-
702- let ( command, title, arg) = match assist. group_label {
703- None => ( "rust-analyzer.applySourceChange" , assist. label . clone ( ) , arg) ,
704-
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- } ;
724+ match & assist. group_label {
725+ Some ( label) => grouped_assists. entry ( label. to_owned ( ) ) . or_default ( ) . push ( assist) ,
726+ None => res. push ( create_single_code_action ( assist, & world) ?. into ( ) ) ,
727+ }
728+ }
735729
736- let kind = match assist. id {
737- AssistId ( "introduce_variable" ) => Some ( "refactor.extract.variable" . to_string ( ) ) ,
738- AssistId ( "add_custom_impl" ) => Some ( "refactor.rewrite.add_custom_impl" . to_string ( ) ) ,
739- _ => None ,
740- } ;
730+ for ( group_label, assists) in grouped_assists {
731+ if assists. len ( ) == 1 {
732+ res. push (
733+ create_single_code_action ( assists. into_iter ( ) . next ( ) . unwrap ( ) , & world) ?. into ( ) ,
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+ }
741742
742- let action = CodeAction {
743- title,
744- kind,
745- diagnostics : None ,
746- edit : None ,
747- command : Some ( command) ,
748- is_preferred : None ,
749- } ;
750- res. push ( action. into ( ) ) ;
743+ let command = Some ( Command {
744+ title : title. clone ( ) ,
745+ command : "rust-analyzer.selectAndApplySourceChange" . to_string ( ) ,
746+ arguments : Some ( vec ! [ serde_json:: Value :: Array ( arguments) ] ) ,
747+ } ) ;
748+ res. push (
749+ CodeAction {
750+ title,
751+ kind : None ,
752+ diagnostics : None ,
753+ edit : None ,
754+ command,
755+ is_preferred : None ,
756+ }
757+ . into ( ) ,
758+ ) ;
759+ }
751760 }
752761
753762 Ok ( Some ( res) )
0 commit comments