@@ -5,10 +5,10 @@ use crate::{
5
5
ast:: {
6
6
self , ArgNames , AssignName , AssignmentKind , BitArraySegmentTruncation , BoundVariable ,
7
7
CallArg , CustomType , FunctionLiteralKind , ImplicitCallArgOrigin , Import , PIPE_PRECEDENCE ,
8
- Pattern , PatternUnusedArguments , PipelineAssignmentKind , RecordConstructor , SrcSpan ,
9
- TodoKind , TypedArg , TypedAssignment , TypedClauseGuard , TypedExpr , TypedModuleConstant ,
10
- TypedPattern , TypedPipelineAssignment , TypedRecordConstructor , TypedStatement , TypedUse ,
11
- visit:: Visit as _,
8
+ Pattern , PatternUnusedArguments , PipelineAssignmentKind , Publicity , RecordConstructor ,
9
+ SrcSpan , TodoKind , TypedArg , TypedAssignment , TypedClauseGuard , TypedExpr ,
10
+ TypedModuleConstant , TypedPattern , TypedPipelineAssignment , TypedRecordConstructor ,
11
+ TypedStatement , TypedUse , visit:: Visit as _,
12
12
} ,
13
13
build:: { Located , Module } ,
14
14
config:: PackageConfig ,
@@ -3690,7 +3690,7 @@ impl<'ast> ast::visit::Visit<'ast> for GenerateDynamicDecoder<'ast> {
3690
3690
} ;
3691
3691
3692
3692
let decoder_type = self . printer . print_type ( & Type :: Named {
3693
- publicity : ast :: Publicity :: Public ,
3693
+ publicity : Publicity :: Public ,
3694
3694
package : STDLIB_PACKAGE_NAME . into ( ) ,
3695
3695
module : DECODE_MODULE . into ( ) ,
3696
3696
name : "Decoder" . into ( ) ,
@@ -4089,7 +4089,7 @@ impl<'ast> ast::visit::Visit<'ast> for GenerateJsonEncoder<'ast> {
4089
4089
} ;
4090
4090
4091
4091
let json_type = self . printer . print_type ( & Type :: Named {
4092
- publicity : ast :: Publicity :: Public ,
4092
+ publicity : Publicity :: Public ,
4093
4093
package : JSON_PACKAGE_NAME . into ( ) ,
4094
4094
module : JSON_MODULE . into ( ) ,
4095
4095
name : "Json" . into ( ) ,
@@ -4934,13 +4934,15 @@ fn pretty_constructor_name(
4934
4934
///
4935
4935
pub struct GenerateFunction < ' a > {
4936
4936
module : & ' a Module ,
4937
+ modules : & ' a std:: collections:: HashMap < EcoString , Module > ,
4937
4938
params : & ' a CodeActionParams ,
4938
4939
edits : TextEdits < ' a > ,
4939
4940
last_visited_function_end : Option < u32 > ,
4940
4941
function_to_generate : Option < FunctionToGenerate < ' a > > ,
4941
4942
}
4942
4943
4943
4944
struct FunctionToGenerate < ' a > {
4945
+ module : Option < & ' a str > ,
4944
4946
name : & ' a str ,
4945
4947
arguments_types : Vec < Arc < Type > > ,
4946
4948
@@ -4956,11 +4958,13 @@ struct FunctionToGenerate<'a> {
4956
4958
impl < ' a > GenerateFunction < ' a > {
4957
4959
pub fn new (
4958
4960
module : & ' a Module ,
4961
+ modules : & ' a std:: collections:: HashMap < EcoString , Module > ,
4959
4962
line_numbers : & ' a LineNumbers ,
4960
4963
params : & ' a CodeActionParams ,
4961
4964
) -> Self {
4962
4965
Self {
4963
4966
module,
4967
+ modules,
4964
4968
params,
4965
4969
edits : TextEdits :: new ( line_numbers) ,
4966
4970
last_visited_function_end : None ,
@@ -4971,16 +4975,53 @@ impl<'a> GenerateFunction<'a> {
4971
4975
pub fn code_actions ( mut self ) -> Vec < CodeAction > {
4972
4976
self . visit_typed_module ( & self . module . ast ) ;
4973
4977
4974
- let Some ( FunctionToGenerate {
4978
+ let Some (
4979
+ function_to_generate @ FunctionToGenerate {
4980
+ module,
4981
+ previous_function_end : Some ( insert_at) ,
4982
+ ..
4983
+ } ,
4984
+ ) = self . function_to_generate . take ( )
4985
+ else {
4986
+ return vec ! [ ] ;
4987
+ } ;
4988
+
4989
+ if let Some ( module) = module {
4990
+ if let Some ( module) = self . modules . get ( module) {
4991
+ let insert_at = if module. code . is_empty ( ) {
4992
+ 0
4993
+ } else {
4994
+ ( module. code . len ( ) - 1 ) as u32
4995
+ } ;
4996
+ self . code_action_for_module (
4997
+ module,
4998
+ Publicity :: Public ,
4999
+ function_to_generate,
5000
+ insert_at,
5001
+ )
5002
+ } else {
5003
+ Vec :: new ( )
5004
+ }
5005
+ } else {
5006
+ let module = self . module ;
5007
+ self . code_action_for_module ( module, Publicity :: Private , function_to_generate, insert_at)
5008
+ }
5009
+ }
5010
+
5011
+ fn code_action_for_module (
5012
+ mut self ,
5013
+ module : & Module ,
5014
+ publicity : Publicity ,
5015
+ function_to_generate : FunctionToGenerate < ' a > ,
5016
+ insert_at : u32 ,
5017
+ ) -> Vec < CodeAction > {
5018
+ let FunctionToGenerate {
4975
5019
name,
4976
5020
arguments_types,
4977
5021
given_arguments,
4978
- previous_function_end : Some ( insert_at) ,
4979
5022
return_type,
4980
- } ) = self . function_to_generate
4981
- else {
4982
- return vec ! [ ] ;
4983
- } ;
5023
+ ..
5024
+ } = function_to_generate;
4984
5025
4985
5026
// Labels do not share the same namespace as argument so we use two separate
4986
5027
// generators to avoid renaming a label in case it shares a name with an argument.
@@ -4989,7 +5030,7 @@ impl<'a> GenerateFunction<'a> {
4989
5030
4990
5031
// Since we are generating a new function, type variables from other
4991
5032
// functions and constants are irrelevant to the types we print.
4992
- let mut printer = Printer :: new_without_type_variables ( & self . module . ast . names ) ;
5033
+ let mut printer = Printer :: new_without_type_variables ( & module. ast . names ) ;
4993
5034
let arguments = arguments_types
4994
5035
. iter ( )
4995
5036
. enumerate ( )
@@ -5009,15 +5050,20 @@ impl<'a> GenerateFunction<'a> {
5009
5050
5010
5051
let return_type = printer. print_type ( & return_type) ;
5011
5052
5053
+ let publicity = if publicity. is_public ( ) { "pub " } else { "" } ;
5054
+
5012
5055
self . edits . insert (
5013
5056
insert_at,
5014
- format ! ( "\n \n fn {name}({arguments}) -> {return_type} {{\n todo\n }}" ) ,
5057
+ format ! ( "\n \n {publicity}fn {name}({arguments}) -> {return_type} {{\n todo\n }}" ) ,
5015
5058
) ;
5016
5059
5060
+ let Some ( uri) = url_from_path ( module. input_path . as_str ( ) ) else {
5061
+ return Vec :: new ( ) ;
5062
+ } ;
5017
5063
let mut action = Vec :: with_capacity ( 1 ) ;
5018
5064
CodeActionBuilder :: new ( "Generate function" )
5019
5065
. kind ( CodeActionKind :: QUICKFIX )
5020
- . changes ( self . params . text_document . uri . clone ( ) , self . edits . edits )
5066
+ . changes ( uri, self . edits . edits )
5021
5067
. preferred ( true )
5022
5068
. push_to ( & mut action) ;
5023
5069
action
@@ -5041,10 +5087,32 @@ impl<'a> GenerateFunction<'a> {
5041
5087
given_arguments,
5042
5088
return_type,
5043
5089
previous_function_end : self . last_visited_function_end ,
5090
+ module : None ,
5044
5091
} )
5045
5092
}
5046
5093
}
5047
5094
}
5095
+
5096
+ fn try_save_function_from_other_module (
5097
+ & mut self ,
5098
+ module : & ' a str ,
5099
+ name : & ' a str ,
5100
+ function_type : & Arc < Type > ,
5101
+ given_arguments : Option < & ' a [ TypedCallArg ] > ,
5102
+ ) {
5103
+ if let Some ( ( arguments_types, return_type) ) = function_type. fn_types ( )
5104
+ && is_valid_lowercase_name ( name)
5105
+ {
5106
+ self . function_to_generate = Some ( FunctionToGenerate {
5107
+ name,
5108
+ arguments_types,
5109
+ given_arguments,
5110
+ return_type,
5111
+ previous_function_end : self . last_visited_function_end ,
5112
+ module : Some ( module) ,
5113
+ } )
5114
+ }
5115
+ }
5048
5116
}
5049
5117
5050
5118
impl < ' ast > ast:: visit:: Visit < ' ast > for GenerateFunction < ' ast > {
@@ -5062,6 +5130,27 @@ impl<'ast> ast::visit::Visit<'ast> for GenerateFunction<'ast> {
5062
5130
ast:: visit:: visit_typed_expr_invalid ( self , location, type_) ;
5063
5131
}
5064
5132
5133
+ fn visit_typed_expr_module_select (
5134
+ & mut self ,
5135
+ _location : & ' ast SrcSpan ,
5136
+ _field_start : & ' ast u32 ,
5137
+ type_ : & ' ast Arc < Type > ,
5138
+ label : & ' ast EcoString ,
5139
+ module_name : & ' ast EcoString ,
5140
+ _module_alias : & ' ast EcoString ,
5141
+ constructor : & ' ast ModuleValueConstructor ,
5142
+ ) {
5143
+ match constructor {
5144
+ // Invalid module selects leave the `name` field blank
5145
+ ModuleValueConstructor :: Fn { name, .. } if name == "" => {
5146
+ self . try_save_function_from_other_module ( module_name, label, type_, None ) ;
5147
+ }
5148
+ ModuleValueConstructor :: Fn { .. }
5149
+ | ModuleValueConstructor :: Record { .. }
5150
+ | ModuleValueConstructor :: Constant { .. } => { }
5151
+ }
5152
+ }
5153
+
5065
5154
fn visit_typed_expr_call (
5066
5155
& mut self ,
5067
5156
location : & ' ast SrcSpan ,
@@ -5073,13 +5162,34 @@ impl<'ast> ast::visit::Visit<'ast> for GenerateFunction<'ast> {
5073
5162
// function that has the proper labels.
5074
5163
let fun_range = self . edits . src_span_to_lsp_range ( fun. location ( ) ) ;
5075
5164
5076
- if within ( self . params . range , fun_range) && fun. is_invalid ( ) {
5077
- if labels_are_correct ( arguments) {
5078
- self . try_save_function_to_generate ( fun. location ( ) , & fun. type_ ( ) , Some ( arguments) ) ;
5165
+ if within ( self . params . range , fun_range) {
5166
+ if !labels_are_correct ( arguments) {
5167
+ return ;
5168
+ }
5169
+
5170
+ match fun {
5171
+ TypedExpr :: Invalid { type_, location } => {
5172
+ return self . try_save_function_to_generate ( * location, type_, Some ( arguments) ) ;
5173
+ }
5174
+ TypedExpr :: ModuleSelect {
5175
+ module_name,
5176
+ label,
5177
+ type_,
5178
+ constructor : ModuleValueConstructor :: Fn { name, .. } ,
5179
+ ..
5180
+ } if name == "" => {
5181
+ return self . try_save_function_from_other_module (
5182
+ module_name,
5183
+ label,
5184
+ type_,
5185
+ Some ( arguments) ,
5186
+ ) ;
5187
+ }
5188
+ _ => { }
5079
5189
}
5080
- } else {
5081
- ast:: visit:: visit_typed_expr_call ( self , location, type_, fun, arguments) ;
5082
5190
}
5191
+
5192
+ ast:: visit:: visit_typed_expr_call ( self , location, type_, fun, arguments) ;
5083
5193
}
5084
5194
}
5085
5195
0 commit comments