Remote intellisense - apps and types (#2237)

This commit is contained in:
Cristine Guadelupe 2023-09-29 18:58:18 +07:00 committed by GitHub
parent 6c5b4bb586
commit 114d649524
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 16 deletions

View file

@ -616,26 +616,26 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
defp get_modules(node) do
modules = Enum.map(:erpc.call(node, :code, :all_loaded, []), &elem(&1, 0))
case :code.get_mode() do
:interactive -> modules ++ get_modules_from_applications()
case :erpc.call(node, :code, :get_mode, []) do
:interactive -> modules ++ get_modules_from_applications(node)
_otherwise -> modules
end
end
defp get_modules_from_applications do
for [app] <- loaded_applications(),
{:ok, modules} = :application.get_key(app, :modules),
defp get_modules_from_applications(node) do
for [app] <- loaded_applications(node),
{:ok, modules} = :erpc.call(node, :application, :get_key, [app, :modules]),
module <- modules,
do: module
end
defp loaded_applications do
defp loaded_applications(node) do
# If we invoke :application.loaded_applications/0,
# it can error if we don't call safe_fixtable before.
# Since in both cases we are reaching over the
# application controller internals, we choose to match
# for performance.
:ets.match(:ac_tab, {{:loaded, :"$1"}, :_})
:erpc.call(node, :ets, :match, [:ac_tab, {{:loaded, :"$1"}, :_}])
end
defp match_module_function(mod, hint, ctx, funs \\ nil) do
@ -706,7 +706,7 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
end
defp match_module_type(mod, hint, ctx) do
types = get_module_types(mod)
types = get_module_types(mod, ctx.node)
matching_types =
Enum.filter(types, fn {name, _arity} ->
@ -734,9 +734,9 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
end)
end
defp get_module_types(mod) do
with true <- ensure_loaded?(mod),
{:ok, types} <- Code.Typespec.fetch_types(mod) do
defp get_module_types(mod, node) do
with true <- ensure_loaded?(mod, node),
{:ok, types} <- :erpc.call(node, Code.Typespec, :fetch_types, [mod]) do
for {kind, {name, _, args}} <- types, kind in [:type, :opaque] do
{name, length(args)}
end
@ -745,8 +745,8 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
end
end
defp ensure_loaded?(Elixir), do: false
defp ensure_loaded?(mod), do: Code.ensure_loaded?(mod)
defp ensure_loaded?(Elixir, _node), do: false
defp ensure_loaded?(mod, node), do: :erpc.call(node, Code, :ensure_loaded?, [mod])
defp imports_from_env(env) do
Enum.map(env.functions, fn {mod, funs} ->

View file

@ -49,13 +49,13 @@ defmodule Livebook.RemoteIntellisenseTest do
File.mkdir_p!(@tmp_dir)
File.write!("#{@tmp_dir}/Elixir.RemoteModule.beam", bytecode)
build_path = Mix.Project.build_path() |> String.to_charlist()
paths = Enum.reject(:code.get_path(), &List.starts_with?(&1, build_path))
elixir_path = :code.lib_dir(:elixir, :ebin)
true = :erpc.call(node, :code, :set_path, [[~c"#{@tmp_dir}" | paths]])
:ok = :erpc.call(node, :code, :add_paths, [[~c"#{@tmp_dir}", elixir_path]])
{:ok, _} = :erpc.call(node, :application, :ensure_all_started, [:elixir])
{:module, RemoteModule} = :erpc.call(node, :code, :load_file, [RemoteModule])
:loaded = :erpc.call(node, :code, :module_status, [RemoteModule])
:ok = :erpc.call(node, :application, :load, [:mnesia])
[node: node]
end
@ -89,5 +89,19 @@ defmodule Livebook.RemoteIntellisenseTest do
insert_text: "hello($0)"
} in Intellisense.get_completion_items("RemoteModule.hel", context, node)
end
test "find modules from apps", %{node: node} do
context = eval(do: nil)
assert [
%{
label: "all_keys/1",
kind: :function,
detail: ":mnesia.all_keys/1",
documentation: _all_keys_doc,
insert_text: "all_keys($0)"
}
] = Intellisense.get_completion_items(":mnesia.all", context, node)
end
end
end