Skip to content

Commit

Permalink
find elixir modules that require adding an alias
Browse files Browse the repository at this point in the history
  • Loading branch information
ajayvigneshk committed May 9, 2022
1 parent e76ac8d commit 2cc2520
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 7 deletions.
68 changes: 65 additions & 3 deletions lib/elixir_sense/providers/suggestion/complete.ex
Original file line number Diff line number Diff line change
Expand Up @@ -444,13 +444,19 @@ defmodule ElixirSense.Providers.Suggestion.Complete do
valid_alias_piece?("." <> name),
concatted = parts |> Enum.take(depth) |> Module.concat(),
filter.(concatted) do
{name, concatted}
{name, concatted, false}
end
|> Kernel.++(match_elixir_modules_that_require_alias(module, hint, env, filter))
|> Enum.uniq_by(&elem(&1, 1))
|> Enum.map(fn {name, module} ->
|> Enum.map(fn {name, module, required_alias?} ->
{desc, meta} = Introspection.get_module_docs_summary(module)
subtype = Introspection.get_module_subtype(module)
%{kind: :module, type: :elixir, name: name, desc: {desc, meta}, subtype: subtype}
result = %{kind: :module, type: :elixir, name: name, desc: {desc, meta}, subtype: subtype}

cond do
required_alias? -> Map.put(result, :required_alias, module)
true -> result
end
end)
end

Expand Down Expand Up @@ -485,6 +491,43 @@ defmodule ElixirSense.Providers.Suggestion.Complete do
not String.starts_with?(name, "Elixir.")
end

defp match_elixir_modules_that_require_alias(Elixir, hint, env, filter) do
for {suggestion, required_alias} <- find_elixir_modules_that_require_alias(Elixir, hint, env),
mod_as_atom = required_alias |> String.to_atom(),
filter.(mod_as_atom),
required_alias_mod = required_alias |> String.split(".") |> Module.concat() do
{suggestion, required_alias_mod, true}
end
end

defp match_elixir_modules_that_require_alias(_module, _hint, _env, _filter) do
[]
end

def find_elixir_modules_that_require_alias(Elixir, hint, env) do
get_modules(true, env)
|> Enum.sort()
|> Enum.dedup()
|> Enum.reduce([], fn module, acc ->
module_parts = module |> String.split(".")

maybe_index =
Enum.find_index(module_parts, fn module_part -> Matcher.match?(module_part, hint) end)

case maybe_index do
nil ->
acc

index ->
required_alias = Enum.slice(module_parts, 0..index)
[suggestion | _] = Enum.reverse(required_alias)
required_alias = required_alias |> Module.concat() |> Atom.to_string()
[{suggestion, required_alias} | acc]
end
end)
|> Enum.filter(fn {suggestion, _required_alias} -> valid_alias_piece?("." <> suggestion) end)
end

defp match_modules(hint, root, env) do
hint_parts = hint |> String.split(".")
hint_parts_length = length(hint_parts)
Expand Down Expand Up @@ -793,6 +836,25 @@ defmodule ElixirSense.Providers.Suggestion.Complete do
[%{type: :field, name: name, subtype: subtype, origin: origin, call?: true}]
end

defp to_entries(%{
kind: :module,
name: name,
required_alias: module,
desc: {desc, metadata},
subtype: subtype
}) do
[
%{
type: :module,
name: name,
required_alias: module,
subtype: subtype,
summary: desc,
metadata: metadata
}
]
end

defp to_entries(%{kind: :module, name: name, desc: {desc, metadata}, subtype: subtype}) do
[%{type: :module, name: name, subtype: subtype, summary: desc, metadata: metadata}]
end
Expand Down
33 changes: 29 additions & 4 deletions test/elixir_sense/providers/suggestion/complete_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -176,17 +176,25 @@ defmodule ElixirSense.Providers.Suggestion.CompleteTest do
%{name: "Stream", subtype: :struct, type: :module},
%{name: "String", subtype: nil, type: :module},
%{name: "StringIO", subtype: nil, type: :module}
] = expand('Str') |> Enum.filter(&(&1.name |> String.starts_with?("Str")))
] =
expand('Str')
|> Enum.filter(&(&1.name |> String.starts_with?("Str")))
|> Enum.reject(fn expansion -> expansion[:required_alias] end)

assert [
%{name: "Macro"},
%{name: "Map"},
%{name: "MapSet"},
%{name: "MatchError"}
] = expand('Ma') |> Enum.filter(&(&1.name |> String.starts_with?("Ma")))
] =
expand('Ma')
|> Enum.filter(&(&1.name |> String.starts_with?("Ma")))
|> Enum.reject(fn expansion -> expansion[:required_alias] end)

assert [%{name: "Dict"}] =
expand('Dic') |> Enum.filter(&(&1.name |> String.starts_with?("Dic")))
expand('Dic')
|> Enum.filter(&(&1.name |> String.starts_with?("Dic")))
|> Enum.reject(fn expansion -> expansion[:required_alias] end)

assert suggestions = expand('Ex')
assert Enum.any?(suggestions, &(&1.name == "ExUnit"))
Expand Down Expand Up @@ -249,6 +257,7 @@ defmodule ElixirSense.Providers.Suggestion.CompleteTest do
test "elixir root submodule completion" do
assert [%{name: "Access", summary: "Key-based access to data structures."}] =
expand('Elixir.Acce')
|> Enum.reject(fn expansion -> expansion[:required_alias] end)

assert [_ | _] = expand('Elixir.')
end
Expand All @@ -264,6 +273,19 @@ defmodule ElixirSense.Providers.Suggestion.CompleteTest do
] = expand('String.Cha')
end

test "find elixir modules that require alias" do
assert [
%{metadata: %{}, name: "Chars", required_alias: String.Chars},
%{metadata: %{}, name: "Chars", required_alias: List.Chars},
%{
metadata: %{},
name: "CallerWithAliasesAndImports",
required_alias:
ElixirSense.Providers.ReferencesTest.Modules.CallerWithAliasesAndImports
}
] = expand('Char')
end

test "elixir submodule no completion" do
assert expand('IEx.Xyz') == []
end
Expand Down Expand Up @@ -1570,7 +1592,10 @@ defmodule ElixirSense.Providers.Suggestion.CompleteTest do
subtype: nil,
summary: "This module contains functions to manipulate files."
}
] = expand('Fi') |> Enum.filter(&(&1.name == "File"))
] =
expand('Fi')
|> Enum.filter(&(&1.name == "File"))
|> Enum.reject(fn expansion -> expansion[:required_alias] end)
end

test "complete only struct modules after %" do
Expand Down

0 comments on commit 2cc2520

Please sign in to comment.