Skip to content

Commit a691ca4

Browse files
committed
Add completion for binary type specifiers
1 parent 79eab37 commit a691ca4

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed

apps/els_lsp/src/els_completion_provider.erl

+140
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ trigger_characters() ->
4444
<<"-">>,
4545
<<"\"">>,
4646
<<"{">>,
47+
<<"/">>,
4748
<<" ">>
4849
].
4950

@@ -198,6 +199,24 @@ find_completions(
198199
#{trigger := <<"-">>, document := Document, column := 1, line := Line}
199200
) ->
200201
attributes(Document, Line);
202+
find_completions(
203+
Prefix,
204+
?COMPLETION_TRIGGER_KIND_CHARACTER,
205+
#{trigger := <<"/">>}
206+
) ->
207+
Tokens = lists:reverse(els_text:tokens(Prefix)),
208+
case in_binary_heuristic(Tokens) of
209+
true ->
210+
binary_type_specifier();
211+
false ->
212+
[]
213+
end;
214+
find_completions(
215+
Prefix,
216+
?COMPLETION_TRIGGER_KIND_CHARACTER,
217+
#{trigger := <<"-">>}
218+
) ->
219+
binary_type_specifiers(Prefix);
201220
find_completions(
202221
_Prefix,
203222
?COMPLETION_TRIGGER_KIND_CHARACTER,
@@ -305,6 +324,18 @@ find_completions(
305324
%% Check for "-anything"
306325
[{atom, _, _}, {'-', _}] ->
307326
attributes(Document, Line);
327+
%% Check for "[...] -"
328+
[{'-', _} | _] ->
329+
binary_type_specifiers(Prefix);
330+
%% Check for "[...] -"
331+
[{'/', _} | _] ->
332+
Tokens = lists:reverse(els_text:tokens(Prefix)),
333+
case in_binary_heuristic(Tokens) of
334+
true ->
335+
binary_type_specifier();
336+
false ->
337+
[]
338+
end;
308339
%% Check for "-export(["
309340
[{'[', _}, {'(', _}, {atom, _, export}, {'-', _}] ->
310341
unexported_definitions(Document, function);
@@ -392,6 +423,115 @@ find_completions(
392423
find_completions(_Prefix, _TriggerKind, _Opts) ->
393424
[].
394425

426+
-spec binary_type_specifiers(binary()) -> [completion_item()].
427+
binary_type_specifiers(Prefix) ->
428+
%% in_binary_heuristic will only consider current line
429+
%% TODO: make it work for multi-line binaries too.
430+
Tokens = lists:reverse(els_text:tokens(Prefix)),
431+
case
432+
in_binary_heuristic(Tokens) andalso
433+
in_binary_type_specifier(Tokens, [])
434+
of
435+
{true, TypeListTokens} ->
436+
HasType = lists:any(
437+
fun(T) ->
438+
lists:member(T, binary_types())
439+
end,
440+
TypeListTokens
441+
),
442+
HasEndianess = lists:any(
443+
fun(T) ->
444+
lists:member(T, binary_endianness())
445+
end,
446+
TypeListTokens
447+
),
448+
HasSignedness = lists:any(
449+
fun(T) ->
450+
lists:member(T, binary_signedness())
451+
end,
452+
TypeListTokens
453+
),
454+
HasUnit = lists:member(unit, TypeListTokens),
455+
[binary_type_specifier(unit) || not HasUnit] ++
456+
[binary_type_specifier(Label) || Label <- binary_types(), not HasType] ++
457+
[binary_type_specifier(Label) || Label <- binary_endianness(), not HasEndianess] ++
458+
[binary_type_specifier(Label) || Label <- binary_signedness(), not HasSignedness];
459+
false ->
460+
[]
461+
end.
462+
463+
-spec in_binary_heuristic([any()]) -> boolean().
464+
in_binary_heuristic([{'>>', _} | _]) ->
465+
false;
466+
in_binary_heuristic([{'<<', _} | _]) ->
467+
true;
468+
in_binary_heuristic([_ | T]) ->
469+
in_binary_heuristic(T);
470+
in_binary_heuristic([]) ->
471+
false.
472+
473+
-spec in_binary_type_specifier([any()], [atom()]) -> {true, [atom()]} | false.
474+
in_binary_type_specifier([{integer, _, _}, {':', _}, {atom, _, unit} | T], Spec) ->
475+
in_binary_type_specifier(T, [unit | Spec]);
476+
in_binary_type_specifier([{atom, _, Atom} | T], Spec) ->
477+
case lists:member(Atom, binary_type_specifiers()) of
478+
true ->
479+
in_binary_type_specifier(T, [Atom | Spec]);
480+
false ->
481+
false
482+
end;
483+
in_binary_type_specifier([{'-', _} | T], Spec) ->
484+
in_binary_type_specifier(T, Spec);
485+
in_binary_type_specifier([{'/', _} | _], Spec) ->
486+
{true, Spec};
487+
in_binary_type_specifier([], _Spec) ->
488+
false.
489+
490+
-spec binary_type_specifiers() -> [atom()].
491+
binary_type_specifiers() ->
492+
binary_types() ++ binary_signedness() ++ binary_endianness() ++ [unit].
493+
494+
-spec binary_signedness() -> [atom()].
495+
binary_signedness() ->
496+
[signed, unsigned].
497+
498+
-spec binary_types() -> [atom()].
499+
binary_types() ->
500+
[integer, float, binary, bytes, bitstring, bits, utf8, utf16, utf32].
501+
502+
-spec binary_endianness() -> [atom()].
503+
binary_endianness() ->
504+
[big, little, native].
505+
506+
-spec binary_type_specifier() -> [completion_item()].
507+
binary_type_specifier() ->
508+
Labels = binary_type_specifiers(),
509+
[binary_type_specifier(Label) || Label <- Labels].
510+
511+
-spec binary_type_specifier(atom()) -> completion_item().
512+
binary_type_specifier(unit) ->
513+
case snippet_support() of
514+
true ->
515+
#{
516+
label => <<"unit:N">>,
517+
kind => ?COMPLETION_ITEM_KIND_TYPE_PARAM,
518+
insertTextFormat => ?INSERT_TEXT_FORMAT_SNIPPET,
519+
insertText => <<"unit:${1:N}">>
520+
};
521+
false ->
522+
#{
523+
label => <<"unit:">>,
524+
kind => ?COMPLETION_ITEM_KIND_TYPE_PARAM,
525+
insertTextFormat => ?INSERT_TEXT_FORMAT_PLAIN_TEXT
526+
}
527+
end;
528+
binary_type_specifier(Label) ->
529+
#{
530+
label => atom_to_binary(Label),
531+
kind => ?COMPLETION_ITEM_KIND_TYPE_PARAM,
532+
insertTextFormat => ?INSERT_TEXT_FORMAT_PLAIN_TEXT
533+
}.
534+
395535
-spec complete_record_field(map(), list()) -> items().
396536
complete_record_field(_Opts, [{atom, _, _}, {'=', _} | _]) ->
397537
[];

0 commit comments

Comments
 (0)