@@ -695,7 +695,13 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
695
695
insert_text =
696
696
case name do
697
697
name when name in [ "size" , "unit" ] ->
698
- function_snippet ( name , [ "integer" ] , 1 , options |> Keyword . merge ( with_parens?: true ) )
698
+ function_snippet (
699
+ name ,
700
+ [ "integer" ] ,
701
+ 1 ,
702
+ "Kernel" ,
703
+ options |> Keyword . merge ( with_parens?: true )
704
+ )
699
705
700
706
other ->
701
707
other
@@ -895,7 +901,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
895
901
896
902
defp def_snippet ( def_str , name , args , arity , opts ) do
897
903
if Keyword . get ( opts , :snippets_supported , false ) do
898
- "#{ def_str } #{ function_snippet ( name , args , arity , opts ) } do\n \t $0\n end"
904
+ "#{ def_str } #{ function_snippet ( name , args , arity , "Kernel" , opts ) } do\n \t $0\n end"
899
905
else
900
906
"#{ def_str } #{ name } "
901
907
end
@@ -972,7 +978,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
972
978
nil
973
979
end
974
980
975
- def function_snippet ( name , args , arity , opts ) do
981
+ def function_snippet ( name , args , arity , origin , opts ) do
982
+ name = sanitize_function_name ( name , origin )
976
983
snippets_supported? = Keyword . get ( opts , :snippets_supported , false )
977
984
trigger_signature? = Keyword . get ( opts , :trigger_signature? , false )
978
985
capture_before? = Keyword . get ( opts , :capture_before? , false )
@@ -1173,36 +1180,32 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
1173
1180
1174
1181
trigger_signature? = signature_help_supported? && ( ( arity == 1 && ! pipe_before? ) || arity > 1 )
1175
1182
1176
- { label , insert_text } =
1183
+ insert_text =
1177
1184
cond do
1178
1185
match? ( "~" <> _ , name ) ->
1179
1186
"~" <> sigil_name = name
1180
- { name , sigil_name }
1187
+ sigil_name
1181
1188
1182
1189
use_name_only? ( origin , name ) or String . starts_with? ( text_after_cursor , "(" ) ->
1183
- { name , name }
1190
+ sanitize_function_name ( name , origin )
1184
1191
1185
1192
true ->
1186
- label = name
1187
-
1188
- insert_text =
1189
- function_snippet (
1190
- name ,
1191
- args_list ,
1192
- arity ,
1193
- Keyword . merge (
1194
- options ,
1195
- pipe_before?: pipe_before? ,
1196
- capture_before?: capture_before? ,
1197
- trigger_signature?: trigger_signature? ,
1198
- locals_without_parens: locals_without_parens ,
1199
- text_after_cursor: text_after_cursor ,
1200
- with_parens?: with_parens? ,
1201
- snippet: info [ :snippet ]
1202
- )
1193
+ function_snippet (
1194
+ name ,
1195
+ args_list ,
1196
+ arity ,
1197
+ origin ,
1198
+ Keyword . merge (
1199
+ options ,
1200
+ pipe_before?: pipe_before? ,
1201
+ capture_before?: capture_before? ,
1202
+ trigger_signature?: trigger_signature? ,
1203
+ locals_without_parens: locals_without_parens ,
1204
+ text_after_cursor: text_after_cursor ,
1205
+ with_parens?: with_parens? ,
1206
+ snippet: info [ :snippet ]
1203
1207
)
1204
-
1205
- { label , insert_text }
1208
+ )
1206
1209
end
1207
1210
1208
1211
footer = SourceFile . format_spec ( spec , line_length: 30 )
@@ -1215,20 +1218,24 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
1215
1218
}
1216
1219
end
1217
1220
1218
- % __MODULE__ {
1219
- label: label ,
1220
- kind: :function ,
1221
- detail: to_string ( type ) ,
1222
- label_details: % {
1223
- "detail" => "(#{ Enum . join ( args_list , ", " ) } )" ,
1224
- "description" => "#{ origin } .#{ name } /#{ arity } "
1225
- } ,
1226
- documentation: summary <> footer ,
1227
- insert_text: insert_text ,
1228
- priority: 17 ,
1229
- tags: metadata_to_tags ( metadata ) ,
1230
- command: command
1231
- }
1221
+ label = sanitize_function_name ( name , origin )
1222
+
1223
+ if label == name or remote_calls? do
1224
+ % __MODULE__ {
1225
+ label: label ,
1226
+ kind: :function ,
1227
+ detail: to_string ( type ) ,
1228
+ label_details: % {
1229
+ "detail" => "(#{ Enum . join ( args_list , ", " ) } )" ,
1230
+ "description" => "#{ origin } .#{ label } /#{ arity } "
1231
+ } ,
1232
+ documentation: summary <> footer ,
1233
+ insert_text: insert_text ,
1234
+ priority: 17 ,
1235
+ tags: metadata_to_tags ( metadata ) ,
1236
+ command: command
1237
+ }
1238
+ end
1232
1239
end
1233
1240
1234
1241
defp use_name_only? ( module_name , function_name ) do
@@ -1369,4 +1376,21 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
1369
1376
|> MapSet . member? ( { String . to_atom ( name ) , arity } )
1370
1377
|> Kernel . not ( )
1371
1378
end
1379
+
1380
+ defp sanitize_function_name ( name , origin ) when origin in [ "Kernel" , "Kernel.SpecialForms" ] ,
1381
+ do: name
1382
+
1383
+ defp sanitize_function_name ( name , origin ) do
1384
+ if not Regex . match? ( ~r/ ^([_\p {Ll}\p {Lo}][\p {L}\p {N}_]*[?!]?)$/ u , name ) do
1385
+ # not an allowed identifier - quote
1386
+ escaped =
1387
+ name
1388
+ |> String . replace ( "\\ " , "\\ \\ " )
1389
+ |> String . replace ( "\" " , "\\ \" " )
1390
+
1391
+ "\" " <> escaped <> "\" "
1392
+ else
1393
+ name
1394
+ end
1395
+ end
1372
1396
end
0 commit comments