@@ -293,6 +293,9 @@ find_completions(
293
293
% % Check for "[...] #"
294
294
[{'#' , _ } | _ ] ->
295
295
definitions (Document , record );
296
+ % % Check for "#{"
297
+ [{'{' , _ }, {'#' , _ } | _ ] ->
298
+ [map_comprehension_completion_item (Document , Line , Column )];
296
299
% % Check for "[...] #anything"
297
300
[_ , {'#' , _ } | _ ] ->
298
301
definitions (Document , record );
@@ -336,6 +339,9 @@ find_completions(
336
339
Attribute =:= behaviour ; Attribute =:= behavior
337
340
->
338
341
[item_kind_module (Module ) || Module <- behaviour_modules (" " )];
342
+ % % Check for "["
343
+ [{'[' , _ } | _ ] ->
344
+ [list_comprehension_completion_item (Document , Line , Column )];
339
345
% % Check for "[...] fun atom"
340
346
[{atom , _ , _ }, {'fun' , _ } | _ ] ->
341
347
bifs (function , ItemFormat = arity_only ) ++
@@ -345,42 +351,26 @@ find_completions(
345
351
{ItemFormat , _POIKind } =
346
352
completion_context (Document , Line , Column , Tokens ),
347
353
complete_type_definition (Document , Name , ItemFormat );
354
+ % % Check for "::"
355
+ [{'::' , _ } | _ ] = Tokens ->
356
+ {ItemFormat , _POIKind } =
357
+ completion_context (Document , Line , Column , Tokens ),
358
+ complete_type_definition (Document , '' , ItemFormat );
348
359
% % Check for ":: atom"
349
360
[{atom , _ , Name }, {'::' , _ } | _ ] = Tokens ->
350
361
{ItemFormat , _POIKind } =
351
362
completion_context (Document , Line , Column , Tokens ),
352
363
complete_type_definition (Document , Name , ItemFormat );
353
364
% % Check for "[...] atom"
354
365
[{atom , _ , Name } | _ ] = Tokens ->
355
- NameBinary = atom_to_binary (Name , utf8 ),
356
- {ItemFormat , POIKind } = completion_context (Document , Line , Column , Tokens ),
357
- case ItemFormat of
358
- arity_only ->
359
- #{text := Text } = Document ,
360
- case
361
- is_in (Document , Line , Column , [nifs ]) orelse
362
- is_in_heuristic (Text , <<" nifs" >>, Line - 1 )
363
- of
364
- true ->
365
- definitions (Document , POIKind , ItemFormat , false );
366
- _ ->
367
- % % Only complete unexported definitions when in
368
- % % export
369
- unexported_definitions (Document , POIKind )
370
- end ;
371
- _ ->
372
- case complete_record_field (Opts , Tokens ) of
373
- [] ->
374
- keywords (POIKind , ItemFormat ) ++
375
- bifs (POIKind , ItemFormat ) ++
376
- atoms (Document , NameBinary ) ++
377
- all_record_fields (Document , NameBinary ) ++
378
- modules (NameBinary ) ++
379
- definitions (Document , POIKind , ItemFormat ) ++
380
- snippets (POIKind , ItemFormat );
381
- RecordFields ->
382
- RecordFields
383
- end
366
+ complete_atom (Name , Tokens , Opts );
367
+ % % Treat keywords as atom completion
368
+ [{Name , _ } | _ ] = Tokens ->
369
+ case lists :member (Name , keywords ()) of
370
+ true ->
371
+ complete_atom (Name , Tokens , Opts );
372
+ false ->
373
+ []
384
374
end ;
385
375
Tokens ->
386
376
? LOG_DEBUG (
@@ -392,6 +382,100 @@ find_completions(
392
382
find_completions (_Prefix , _TriggerKind , _Opts ) ->
393
383
[].
394
384
385
+ -spec list_comprehension_completion_item (els_dt_document :item (), line (), column ()) ->
386
+ completion_item ().
387
+ list_comprehension_completion_item (#{text := Text }, Line , Column ) ->
388
+ Suffix =
389
+ try els_text :get_char (Text , Line , Column + 1 ) of
390
+ {ok , $] } ->
391
+ % % Don't include ']' if next character is a ']'
392
+ % % I.e if cursor is at []
393
+ % % ^
394
+ <<" " >>;
395
+ _ ->
396
+ <<" ]" >>
397
+ catch
398
+ _ :_ :_ ->
399
+ <<" ]" >>
400
+ end ,
401
+ InsertText =
402
+ case snippet_support () of
403
+ true ->
404
+ <<" ${3:Expr} || ${2:Elem} <- ${1:List}" , Suffix /binary >>;
405
+ false ->
406
+ <<" Expr || Elem <- List" , Suffix /binary >>
407
+ end ,
408
+ #{
409
+ label => <<" [Expr || Elem <- List]" >>,
410
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD ,
411
+ insertTextFormat => ? INSERT_TEXT_FORMAT_SNIPPET ,
412
+ insertText => InsertText
413
+ }.
414
+
415
+ -spec map_comprehension_completion_item (els_dt_document :item (), line (), column ()) ->
416
+ completion_item ().
417
+ map_comprehension_completion_item (#{text := Text }, Line , Column ) ->
418
+ Suffix =
419
+ try els_text :get_char (Text , Line , Column + 1 ) of
420
+ {ok , $} } ->
421
+ % % Don't include '}' if next character is a '}'
422
+ % % I.e if cursor is at #{}
423
+ % % ^
424
+ <<" " >>;
425
+ _ ->
426
+ <<" }" >>
427
+ catch
428
+ _ :_ :_ ->
429
+ <<" }" >>
430
+ end ,
431
+ InsertText =
432
+ case snippet_support () of
433
+ true ->
434
+ <<" ${4:K} => ${5:V} || ${2:K} => ${3:V} <- ${1:Map}" , Suffix /binary >>;
435
+ false ->
436
+ <<" K => V || K := V <- Map" , Suffix /binary >>
437
+ end ,
438
+ #{
439
+ label => <<" #{K => V || K := V <- Map}" >>,
440
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD ,
441
+ insertTextFormat => ? INSERT_TEXT_FORMAT_SNIPPET ,
442
+ insertText => InsertText
443
+ }.
444
+
445
+ -spec complete_atom (atom (), [any ()], map ()) -> [completion_item ()].
446
+ complete_atom (Name , Tokens , Opts ) ->
447
+ #{document := Document , line := Line , column := Column } = Opts ,
448
+ NameBinary = atom_to_binary (Name , utf8 ),
449
+ {ItemFormat , POIKind } = completion_context (Document , Line , Column , Tokens ),
450
+ case ItemFormat of
451
+ arity_only ->
452
+ #{text := Text } = Document ,
453
+ case
454
+ is_in (Document , Line , Column , [nifs ]) orelse
455
+ is_in_heuristic (Text , <<" nifs" >>, Line - 1 )
456
+ of
457
+ true ->
458
+ definitions (Document , POIKind , ItemFormat , false );
459
+ _ ->
460
+ % % Only complete unexported definitions when in
461
+ % % export
462
+ unexported_definitions (Document , POIKind )
463
+ end ;
464
+ _ ->
465
+ case complete_record_field (Opts , Tokens ) of
466
+ [] ->
467
+ keywords (POIKind , ItemFormat ) ++
468
+ bifs (POIKind , ItemFormat ) ++
469
+ atoms (Document , NameBinary ) ++
470
+ all_record_fields (Document , NameBinary ) ++
471
+ modules (NameBinary ) ++
472
+ definitions (Document , POIKind , ItemFormat ) ++
473
+ snippets (POIKind , ItemFormat );
474
+ RecordFields ->
475
+ RecordFields
476
+ end
477
+ end .
478
+
395
479
-spec complete_record_field (map (), list ()) -> items ().
396
480
complete_record_field (_Opts , [{atom , _ , _ }, {'=' , _ } | _ ]) ->
397
481
[];
@@ -999,7 +1083,15 @@ keywords(type_definition, _ItemFormat) ->
999
1083
keywords (_POIKind , arity_only ) ->
1000
1084
[];
1001
1085
keywords (_POIKind , _ItemFormat ) ->
1002
- Keywords = [
1086
+ Keywords = keywords (),
1087
+ [
1088
+ keyword_completion_item (K , snippet_support ())
1089
+ || K <- Keywords
1090
+ ].
1091
+
1092
+ -spec keywords () -> [atom ()].
1093
+ keywords () ->
1094
+ [
1003
1095
'after' ,
1004
1096
'and' ,
1005
1097
'andalso' ,
@@ -1015,9 +1107,11 @@ keywords(_POIKind, _ItemFormat) ->
1015
1107
'cond' ,
1016
1108
'div' ,
1017
1109
'end' ,
1110
+ 'else' ,
1018
1111
'fun' ,
1019
1112
'if' ,
1020
1113
'let' ,
1114
+ 'maybe' ,
1021
1115
'not' ,
1022
1116
'of' ,
1023
1117
'or' ,
@@ -1027,15 +1121,128 @@ keywords(_POIKind, _ItemFormat) ->
1027
1121
'try' ,
1028
1122
'when' ,
1029
1123
'xor'
1030
- ],
1031
- [
1032
- #{
1033
- label => atom_to_binary (K , utf8 ),
1034
- kind => ? COMPLETION_ITEM_KIND_KEYWORD
1035
- }
1036
- || K <- Keywords
1037
1124
].
1038
1125
1126
+ -spec keyword_completion_item (_ , _ ) -> _ .
1127
+ keyword_completion_item ('case' , true ) ->
1128
+ #{
1129
+ label => <<" case" >>,
1130
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD ,
1131
+ insertTextFormat => ? INSERT_TEXT_FORMAT_SNIPPET ,
1132
+ insertText =>
1133
+ <<
1134
+ " case ${1:Exprs} of\n "
1135
+ " ${2:Pattern} ->\n "
1136
+ " ${3:Body}\n "
1137
+ " end"
1138
+ >>
1139
+ };
1140
+ keyword_completion_item ('try' , true ) ->
1141
+ #{
1142
+ label => <<" try" >>,
1143
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD ,
1144
+ insertTextFormat => ? INSERT_TEXT_FORMAT_SNIPPET ,
1145
+ insertText =>
1146
+ <<
1147
+ " try ${1:Exprs}\n "
1148
+ " catch\n "
1149
+ " ${2:Class}:${3:ExceptionPattern}:${4:Stacktrace} ->\n "
1150
+ " ${5:ExceptionBody}\n "
1151
+ " end"
1152
+ >>
1153
+ };
1154
+ keyword_completion_item ('catch' , true ) ->
1155
+ #{
1156
+ label => <<" catch" >>,
1157
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD ,
1158
+ insertTextFormat => ? INSERT_TEXT_FORMAT_SNIPPET ,
1159
+ insertText =>
1160
+ <<
1161
+ " catch\n "
1162
+ " ${1:Class}:${2:ExceptionPattern}:${3:Stacktrace} ->\n "
1163
+ " ${4:ExceptionBody}\n "
1164
+ " end"
1165
+ >>
1166
+ };
1167
+ keyword_completion_item ('begin' , true ) ->
1168
+ #{
1169
+ label => <<" begin" >>,
1170
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD ,
1171
+ insertTextFormat => ? INSERT_TEXT_FORMAT_SNIPPET ,
1172
+ insertText =>
1173
+ <<
1174
+ " begin\n "
1175
+ " ${1:Body}\n "
1176
+ " end"
1177
+ >>
1178
+ };
1179
+ keyword_completion_item ('maybe' , true ) ->
1180
+ #{
1181
+ label => <<" maybe" >>,
1182
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD ,
1183
+ insertTextFormat => ? INSERT_TEXT_FORMAT_SNIPPET ,
1184
+ insertText =>
1185
+ <<
1186
+ " maybe\n "
1187
+ " ${1:Body}\n "
1188
+ " end"
1189
+ >>
1190
+ };
1191
+ keyword_completion_item ('after' , true ) ->
1192
+ #{
1193
+ label => <<" after" >>,
1194
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD ,
1195
+ insertTextFormat => ? INSERT_TEXT_FORMAT_SNIPPET ,
1196
+ insertText =>
1197
+ <<
1198
+ " after\n "
1199
+ " ${1:Duration} ->\n "
1200
+ " ${2:Body}"
1201
+ >>
1202
+ };
1203
+ keyword_completion_item ('else' , true ) ->
1204
+ #{
1205
+ label => <<" else" >>,
1206
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD ,
1207
+ insertTextFormat => ? INSERT_TEXT_FORMAT_SNIPPET ,
1208
+ insertText =>
1209
+ <<
1210
+ " else\n "
1211
+ " ${1:Pattern} ->\n "
1212
+ " ${2:Body}"
1213
+ >>
1214
+ };
1215
+ keyword_completion_item ('of' , true ) ->
1216
+ #{
1217
+ label => <<" of" >>,
1218
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD ,
1219
+ insertTextFormat => ? INSERT_TEXT_FORMAT_SNIPPET ,
1220
+ insertText =>
1221
+ <<
1222
+ " of\n "
1223
+ " ${1:Pattern} ->\n "
1224
+ " ${2:Body}"
1225
+ >>
1226
+ };
1227
+ keyword_completion_item ('receive' , true ) ->
1228
+ #{
1229
+ label => <<" receive" >>,
1230
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD ,
1231
+ insertTextFormat => ? INSERT_TEXT_FORMAT_SNIPPET ,
1232
+ insertText =>
1233
+ <<
1234
+ " receive\n "
1235
+ " ${1:Pattern} ->\n "
1236
+ " ${2:Body}\n "
1237
+ " end"
1238
+ >>
1239
+ };
1240
+ keyword_completion_item (K , _SnippetSupport ) ->
1241
+ #{
1242
+ label => atom_to_binary (K , utf8 ),
1243
+ kind => ? COMPLETION_ITEM_KIND_KEYWORD
1244
+ }.
1245
+
1039
1246
% %==============================================================================
1040
1247
% % Built-in functions
1041
1248
% %==============================================================================
0 commit comments