Skip to content

Commit 294160a

Browse files
committed
Add completion for binary type specifiers
1 parent 89a2a4c commit 294160a

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,
@@ -308,6 +327,18 @@ find_completions(
308327
%% Check for "-anything"
309328
[{atom, _, _}, {'-', _}] ->
310329
attributes(Document, Line);
330+
%% Check for "[...] -"
331+
[{'-', _} | _] ->
332+
binary_type_specifiers(Prefix);
333+
%% Check for "[...] -"
334+
[{'/', _} | _] ->
335+
Tokens = lists:reverse(els_text:tokens(Prefix)),
336+
case in_binary_heuristic(Tokens) of
337+
true ->
338+
binary_type_specifier();
339+
false ->
340+
[]
341+
end;
311342
%% Check for "-export(["
312343
[{'[', _}, {'(', _}, {atom, _, export}, {'-', _}] ->
313344
unexported_definitions(Document, function);
@@ -476,6 +507,115 @@ complete_atom(Name, Tokens, Opts) ->
476507
end
477508
end.
478509

510+
-spec binary_type_specifiers(binary()) -> [completion_item()].
511+
binary_type_specifiers(Prefix) ->
512+
%% in_binary_heuristic will only consider current line
513+
%% TODO: make it work for multi-line binaries too.
514+
Tokens = lists:reverse(els_text:tokens(Prefix)),
515+
case
516+
in_binary_heuristic(Tokens) andalso
517+
in_binary_type_specifier(Tokens, [])
518+
of
519+
{true, TypeListTokens} ->
520+
HasType = lists:any(
521+
fun(T) ->
522+
lists:member(T, binary_types())
523+
end,
524+
TypeListTokens
525+
),
526+
HasEndianess = lists:any(
527+
fun(T) ->
528+
lists:member(T, binary_endianness())
529+
end,
530+
TypeListTokens
531+
),
532+
HasSignedness = lists:any(
533+
fun(T) ->
534+
lists:member(T, binary_signedness())
535+
end,
536+
TypeListTokens
537+
),
538+
HasUnit = lists:member(unit, TypeListTokens),
539+
[binary_type_specifier(unit) || not HasUnit] ++
540+
[binary_type_specifier(Label) || Label <- binary_types(), not HasType] ++
541+
[binary_type_specifier(Label) || Label <- binary_endianness(), not HasEndianess] ++
542+
[binary_type_specifier(Label) || Label <- binary_signedness(), not HasSignedness];
543+
false ->
544+
[]
545+
end.
546+
547+
-spec in_binary_heuristic([any()]) -> boolean().
548+
in_binary_heuristic([{'>>', _} | _]) ->
549+
false;
550+
in_binary_heuristic([{'<<', _} | _]) ->
551+
true;
552+
in_binary_heuristic([_ | T]) ->
553+
in_binary_heuristic(T);
554+
in_binary_heuristic([]) ->
555+
false.
556+
557+
-spec in_binary_type_specifier([any()], [atom()]) -> {true, [atom()]} | false.
558+
in_binary_type_specifier([{integer, _, _}, {':', _}, {atom, _, unit} | T], Spec) ->
559+
in_binary_type_specifier(T, [unit | Spec]);
560+
in_binary_type_specifier([{atom, _, Atom} | T], Spec) ->
561+
case lists:member(Atom, binary_type_specifiers()) of
562+
true ->
563+
in_binary_type_specifier(T, [Atom | Spec]);
564+
false ->
565+
false
566+
end;
567+
in_binary_type_specifier([{'-', _} | T], Spec) ->
568+
in_binary_type_specifier(T, Spec);
569+
in_binary_type_specifier([{'/', _} | _], Spec) ->
570+
{true, Spec};
571+
in_binary_type_specifier([], _Spec) ->
572+
false.
573+
574+
-spec binary_type_specifiers() -> [atom()].
575+
binary_type_specifiers() ->
576+
binary_types() ++ binary_signedness() ++ binary_endianness() ++ [unit].
577+
578+
-spec binary_signedness() -> [atom()].
579+
binary_signedness() ->
580+
[signed, unsigned].
581+
582+
-spec binary_types() -> [atom()].
583+
binary_types() ->
584+
[integer, float, binary, bytes, bitstring, bits, utf8, utf16, utf32].
585+
586+
-spec binary_endianness() -> [atom()].
587+
binary_endianness() ->
588+
[big, little, native].
589+
590+
-spec binary_type_specifier() -> [completion_item()].
591+
binary_type_specifier() ->
592+
Labels = binary_type_specifiers(),
593+
[binary_type_specifier(Label) || Label <- Labels].
594+
595+
-spec binary_type_specifier(atom()) -> completion_item().
596+
binary_type_specifier(unit) ->
597+
case snippet_support() of
598+
true ->
599+
#{
600+
label => <<"unit:N">>,
601+
kind => ?COMPLETION_ITEM_KIND_TYPE_PARAM,
602+
insertTextFormat => ?INSERT_TEXT_FORMAT_SNIPPET,
603+
insertText => <<"unit:${1:N}">>
604+
};
605+
false ->
606+
#{
607+
label => <<"unit:">>,
608+
kind => ?COMPLETION_ITEM_KIND_TYPE_PARAM,
609+
insertTextFormat => ?INSERT_TEXT_FORMAT_PLAIN_TEXT
610+
}
611+
end;
612+
binary_type_specifier(Label) ->
613+
#{
614+
label => atom_to_binary(Label),
615+
kind => ?COMPLETION_ITEM_KIND_TYPE_PARAM,
616+
insertTextFormat => ?INSERT_TEXT_FORMAT_PLAIN_TEXT
617+
}.
618+
479619
-spec complete_record_field(map(), list()) -> items().
480620
complete_record_field(_Opts, [{atom, _, _}, {'=', _} | _]) ->
481621
[];

0 commit comments

Comments
 (0)