mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-12-12 14:52:39 +08:00
Add completion for bitstring modifiers (#1291)
Co-authored-by: José Valim <jose.valim@gmail.com> Co-authored-by: Jonatan Kłosko <jonatanklosko@gmail.com>
This commit is contained in:
parent
895373e08b
commit
648edf23e7
3 changed files with 118 additions and 2 deletions
|
|
@ -266,6 +266,23 @@ defmodule Livebook.Intellisense do
|
||||||
insert_text: Atom.to_string(name)
|
insert_text: Atom.to_string(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defp format_completion_item(%{kind: :bitstring_modifier, name: name, arity: arity}) do
|
||||||
|
insert_text =
|
||||||
|
if arity == 0 do
|
||||||
|
Atom.to_string(name)
|
||||||
|
else
|
||||||
|
"#{name}($0)"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
label: Atom.to_string(name),
|
||||||
|
kind: :bitstring_option,
|
||||||
|
detail: "bitstring option",
|
||||||
|
documentation: nil,
|
||||||
|
insert_text: insert_text
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
defp keyword_macro?(name) do
|
defp keyword_macro?(name) do
|
||||||
def? = name |> Atom.to_string() |> String.starts_with?("def")
|
def? = name |> Atom.to_string() |> String.starts_with?("def")
|
||||||
|
|
||||||
|
|
@ -346,7 +363,17 @@ defmodule Livebook.Intellisense do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ordered_kinds [:keyword, :field, :variable, :module, :struct, :interface, :function, :type]
|
@ordered_kinds [
|
||||||
|
:keyword,
|
||||||
|
:field,
|
||||||
|
:variable,
|
||||||
|
:module,
|
||||||
|
:struct,
|
||||||
|
:interface,
|
||||||
|
:function,
|
||||||
|
:type,
|
||||||
|
:bitstring_option
|
||||||
|
]
|
||||||
|
|
||||||
defp completion_item_priority(%{kind: :struct, detail: "exception"} = completion_item) do
|
defp completion_item_priority(%{kind: :struct, detail: "exception"} = completion_item) do
|
||||||
{length(@ordered_kinds), completion_item.label}
|
{length(@ordered_kinds), completion_item.label}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,11 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
|
||||||
name: name(),
|
name: name(),
|
||||||
documentation: Docs.documentation()
|
documentation: Docs.documentation()
|
||||||
}
|
}
|
||||||
|
| %{
|
||||||
|
kind: :bitstring_modifier,
|
||||||
|
name: name(),
|
||||||
|
arity: integer()
|
||||||
|
}
|
||||||
|
|
||||||
@type name :: atom()
|
@type name :: atom()
|
||||||
@type display_name :: String.t()
|
@type display_name :: String.t()
|
||||||
|
|
@ -72,6 +77,23 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
|
||||||
@exact_matcher &Kernel.==/2
|
@exact_matcher &Kernel.==/2
|
||||||
@prefix_matcher &String.starts_with?/2
|
@prefix_matcher &String.starts_with?/2
|
||||||
|
|
||||||
|
@bitstring_modifiers [
|
||||||
|
{:big, 0},
|
||||||
|
{:binary, 0},
|
||||||
|
{:bitstring, 0},
|
||||||
|
{:integer, 0},
|
||||||
|
{:float, 0},
|
||||||
|
{:little, 0},
|
||||||
|
{:native, 0},
|
||||||
|
{:signed, 0},
|
||||||
|
{:size, 1},
|
||||||
|
{:unit, 1},
|
||||||
|
{:unsigned, 0},
|
||||||
|
{:utf8, 0},
|
||||||
|
{:utf16, 0},
|
||||||
|
{:utf32, 0}
|
||||||
|
]
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Returns a list of identifiers matching the given `hint`
|
Returns a list of identifiers matching the given `hint`
|
||||||
together with relevant information.
|
together with relevant information.
|
||||||
|
|
@ -151,7 +173,10 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
|
||||||
match_default(ctx)
|
match_default(ctx)
|
||||||
|
|
||||||
{:local_or_var, local_or_var} ->
|
{:local_or_var, local_or_var} ->
|
||||||
match_in_struct_fields_or_local_or_var(List.to_string(local_or_var), ctx)
|
hint = List.to_string(local_or_var)
|
||||||
|
|
||||||
|
match_container_context(ctx.fragment, hint) ||
|
||||||
|
match_in_struct_fields_or_local_or_var(hint, ctx)
|
||||||
|
|
||||||
{:local_arity, local} ->
|
{:local_arity, local} ->
|
||||||
match_local(List.to_string(local), %{ctx | matcher: @exact_matcher})
|
match_local(List.to_string(local), %{ctx | matcher: @exact_matcher})
|
||||||
|
|
@ -162,6 +187,10 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
|
||||||
:locate -> match_local(List.to_string(local), %{ctx | matcher: @exact_matcher})
|
:locate -> match_local(List.to_string(local), %{ctx | matcher: @exact_matcher})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
{:operator, operator} when operator in ~w(:: -)c ->
|
||||||
|
match_container_context(ctx.fragment, "") ||
|
||||||
|
match_local_or_var(List.to_string(operator), ctx)
|
||||||
|
|
||||||
{:operator, operator} ->
|
{:operator, operator} ->
|
||||||
match_local_or_var(List.to_string(operator), ctx)
|
match_local_or_var(List.to_string(operator), ctx)
|
||||||
|
|
||||||
|
|
@ -297,6 +326,34 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp match_container_context(code, hint) do
|
||||||
|
case container_context(code) do
|
||||||
|
:bitstring_modifier ->
|
||||||
|
existing = code |> String.split("::") |> List.last() |> String.split("-")
|
||||||
|
|
||||||
|
for {modifier, arity} <- @bitstring_modifiers,
|
||||||
|
name = Atom.to_string(modifier),
|
||||||
|
String.starts_with?(name, hint) and name not in existing,
|
||||||
|
do: %{kind: :bitstring_modifier, name: modifier, arity: arity}
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp container_context(code) do
|
||||||
|
case Code.Fragment.container_cursor_to_quoted(code) do
|
||||||
|
{:ok, quoted} ->
|
||||||
|
case Macro.path(quoted, &match?({:__cursor__, _, []}, &1)) do
|
||||||
|
[cursor, {:"::", _, [_, cursor]}, {:<<>>, _, [_ | _]} | _] -> :bitstring_modifier
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
|
||||||
|
{:error, _} ->
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp expand_struct_fields(ctx) do
|
defp expand_struct_fields(ctx) do
|
||||||
with {:ok, quoted} <- Code.Fragment.container_cursor_to_quoted(ctx.fragment),
|
with {:ok, quoted} <- Code.Fragment.container_cursor_to_quoted(ctx.fragment),
|
||||||
{aliases, pairs} <- find_struct_fields(quoted) do
|
{aliases, pairs} <- find_struct_fields(quoted) do
|
||||||
|
|
|
||||||
|
|
@ -1158,6 +1158,38 @@ defmodule Livebook.IntellisenseTest do
|
||||||
}
|
}
|
||||||
] = Intellisense.get_completion_items("__EN", context)
|
] = Intellisense.get_completion_items("__EN", context)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "Elixir bitstring modifiers" do
|
||||||
|
context = eval(do: nil)
|
||||||
|
|
||||||
|
assert [
|
||||||
|
%{
|
||||||
|
detail: "bitstring option",
|
||||||
|
documentation: nil,
|
||||||
|
insert_text: "integer",
|
||||||
|
kind: :bitstring_option,
|
||||||
|
label: "integer"
|
||||||
|
}
|
||||||
|
] = Intellisense.get_completion_items("<<a::intege", context)
|
||||||
|
|
||||||
|
assert [
|
||||||
|
%{
|
||||||
|
detail: "bitstring option",
|
||||||
|
documentation: nil,
|
||||||
|
insert_text: "size($0)",
|
||||||
|
kind: :bitstring_option,
|
||||||
|
label: "size"
|
||||||
|
}
|
||||||
|
] = Intellisense.get_completion_items("<<a::siz", context)
|
||||||
|
|
||||||
|
assert %{
|
||||||
|
detail: "bitstring option",
|
||||||
|
documentation: nil,
|
||||||
|
insert_text: "integer",
|
||||||
|
kind: :bitstring_option,
|
||||||
|
label: "integer"
|
||||||
|
} in Intellisense.get_completion_items("<<a::", context)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "get_details/3" do
|
describe "get_details/3" do
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue