@@ -4,14 +4,16 @@ use emmylua_code_analysis::{
44 FileId , InferGuard , LuaFunctionType , LuaMemberId , LuaMemberKey , LuaSemanticDeclId ,
55 LuaSignatureId , LuaType , RenderLevel , SemanticModel ,
66} ;
7+ use emmylua_parser:: LuaTokenKind ;
78use emmylua_parser:: {
89 LuaAst , LuaAstNode , LuaCallExpr , LuaClosureExpr , LuaExpr , LuaFuncStat , LuaIndexExpr ,
9- LuaLocalName , LuaSyntaxId , LuaVarExpr ,
10+ LuaLocalName , LuaStat , LuaSyntaxId , LuaVarExpr ,
1011} ;
1112use lsp_types:: { InlayHint , InlayHintKind , InlayHintLabel , InlayHintLabelPart , Location } ;
1213use rowan:: NodeOrToken ;
1314
1415use emmylua_code_analysis:: humanize_type;
16+ use rowan:: TokenAtOffset ;
1517
1618pub fn build_inlay_hints ( semantic_model : & SemanticModel ) -> Option < Vec < InlayHint > > {
1719 let mut result = Vec :: new ( ) ;
@@ -106,7 +108,7 @@ fn build_call_expr_param_hint(
106108 if !semantic_model. get_emmyrc ( ) . hint . param_hint {
107109 return Some ( ( ) ) ;
108110 }
109-
111+ let params_location = get_call_signature_param_location ( semantic_model , & call_expr ) ;
110112 let func = semantic_model. infer_call_expr_func ( call_expr. clone ( ) , None ) ?;
111113 let call_args_list = call_expr. get_args_list ( ) ?;
112114 let colon_call = call_expr. is_colon_call ( ) ;
@@ -116,11 +118,70 @@ fn build_call_expr_param_hint(
116118 call_args_list. get_args ( ) . collect ( ) ,
117119 colon_call,
118120 & func,
121+ params_location,
119122 ) ;
120123
121124 Some ( ( ) )
122125}
123126
127+ fn get_call_signature_param_location (
128+ semantic_model : & SemanticModel ,
129+ call_expr : & LuaCallExpr ,
130+ ) -> Option < HashMap < String , Location > > {
131+ let prefix_expr = call_expr. get_prefix_expr ( ) ?;
132+ let semantic_info =
133+ semantic_model. get_semantic_info ( NodeOrToken :: Node ( prefix_expr. syntax ( ) . clone ( ) ) ) ?;
134+ let mut document = None ;
135+ let closure = if let LuaType :: Signature ( signature_id) = & semantic_info. typ {
136+ let sig_file_id = signature_id. get_file_id ( ) ;
137+ let sig_position = signature_id. get_position ( ) ;
138+ document = semantic_model. get_document_by_file_id ( sig_file_id) ;
139+
140+ if let Some ( root) = semantic_model. get_root_by_file_id ( sig_file_id) {
141+ let token = match root. syntax ( ) . token_at_offset ( sig_position) {
142+ TokenAtOffset :: Single ( token) => token,
143+ TokenAtOffset :: Between ( left, right) => {
144+ if left. kind ( ) == LuaTokenKind :: TkName . into ( ) {
145+ left
146+ } else {
147+ right
148+ }
149+ }
150+ TokenAtOffset :: None => {
151+ return None ;
152+ }
153+ } ;
154+ let stat = token. parent_ancestors ( ) . find_map ( LuaStat :: cast) ?;
155+ match stat {
156+ LuaStat :: LocalFuncStat ( local_func_stat) => local_func_stat. get_closure ( ) ,
157+ LuaStat :: FuncStat ( func_stat) => func_stat. get_closure ( ) ,
158+ _ => None ,
159+ }
160+ } else {
161+ None
162+ }
163+ } else {
164+ None
165+ } ?;
166+ let lua_params = closure. get_params_list ( ) ?;
167+ let document = document?;
168+ let url = document. get_uri ( ) ;
169+ let mut lua_params_map: HashMap < String , Location > = HashMap :: new ( ) ;
170+ for param in lua_params. get_params ( ) {
171+ if let Some ( name_token) = param. get_name_token ( ) {
172+ let name = name_token. get_name_text ( ) . to_string ( ) ;
173+ let range = param. get_range ( ) ;
174+ let lsp_range = document. to_lsp_range ( range) ?;
175+ lua_params_map. insert ( name, Location :: new ( url. clone ( ) , lsp_range) ) ;
176+ } else if param. is_dots ( ) {
177+ let range = param. get_range ( ) ;
178+ let lsp_range = document. to_lsp_range ( range) ?;
179+ lua_params_map. insert ( "..." . to_string ( ) , Location :: new ( url. clone ( ) , lsp_range) ) ;
180+ }
181+ }
182+ Some ( lua_params_map)
183+ }
184+
124185fn build_call_expr_await_hint (
125186 semantic_model : & SemanticModel ,
126187 result : & mut Vec < InlayHint > ,
@@ -182,6 +243,7 @@ fn build_call_args_for_func_type(
182243 call_args : Vec < LuaExpr > ,
183244 colon_call : bool ,
184245 func_type : & LuaFunctionType ,
246+ params_location : Option < HashMap < String , Location > > ,
185247) -> Option < ( ) > {
186248 let call_args_len = call_args. len ( ) ;
187249 let mut params = func_type
@@ -210,13 +272,28 @@ fn build_call_args_for_func_type(
210272
211273 if name == "..." {
212274 for i in idx..call_args_len {
275+ let label_name = format ! ( "var{}:" , i - idx) ;
276+ let label = if let Some ( params_location) = & params_location {
277+ if let Some ( location) = params_location. get ( name) {
278+ InlayHintLabel :: LabelParts ( vec ! [ InlayHintLabelPart {
279+ value: label_name,
280+ location: Some ( location. clone( ) ) ,
281+ ..Default :: default ( )
282+ } ] )
283+ } else {
284+ InlayHintLabel :: String ( label_name)
285+ }
286+ } else {
287+ InlayHintLabel :: String ( label_name)
288+ } ;
289+
213290 let arg = & call_args[ i] ;
214291 let range = arg. get_range ( ) ;
215292 let document = semantic_model. get_document ( ) ;
216293 let lsp_range = document. to_lsp_range ( range) ?;
217294 let hint = InlayHint {
218295 kind : Some ( InlayHintKind :: PARAMETER ) ,
219- label : InlayHintLabel :: String ( format ! ( "var{}:" , i - idx ) ) ,
296+ label,
220297 position : lsp_range. start ,
221298 text_edits : None ,
222299 tooltip : None ,
@@ -239,12 +316,27 @@ fn build_call_args_for_func_type(
239316 }
240317 }
241318
242- let range = arg. get_range ( ) ;
243319 let document = semantic_model. get_document ( ) ;
244- let lsp_range = document. to_lsp_range ( range) ?;
320+ let lsp_range = document. to_lsp_range ( arg. get_range ( ) ) ?;
321+
322+ let label_name = format ! ( "{}:" , name) ;
323+ let label = if let Some ( params_location) = & params_location {
324+ if let Some ( location) = params_location. get ( name) {
325+ InlayHintLabel :: LabelParts ( vec ! [ InlayHintLabelPart {
326+ value: label_name,
327+ location: Some ( location. clone( ) ) ,
328+ ..Default :: default ( )
329+ } ] )
330+ } else {
331+ InlayHintLabel :: String ( label_name)
332+ }
333+ } else {
334+ InlayHintLabel :: String ( label_name)
335+ } ;
336+
245337 let hint = InlayHint {
246338 kind : Some ( InlayHintKind :: PARAMETER ) ,
247- label : InlayHintLabel :: String ( format ! ( "{}:" , name ) ) ,
339+ label,
248340 position : lsp_range. start ,
249341 text_edits : None ,
250342 tooltip : None ,
0 commit comments