mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-06 19:46:00 +08:00
Reduce the amount of erpc calls when loading functions for a module (#2345)
This commit is contained in:
parent
048d197053
commit
3b15e75227
1 changed files with 32 additions and 27 deletions
|
@ -320,6 +320,11 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
|
|||
end
|
||||
end
|
||||
|
||||
# This is ignoring information from remote nodes
|
||||
# and only listing structs that are also structs
|
||||
# in the current node. Doing this check remotely
|
||||
# would unfortunately be too expensive. Alternatively
|
||||
# we list all modules.
|
||||
defp match_struct(hint, ctx) do
|
||||
for %{kind: :module, module: module} = item <- match_alias(hint, ctx, true),
|
||||
has_struct?(module),
|
||||
|
@ -616,30 +621,27 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
|
|||
defp get_modules(node) do
|
||||
modules = Enum.map(:erpc.call(node, :code, :all_loaded, []), &elem(&1, 0))
|
||||
|
||||
case :erpc.call(node, :code, :get_mode, []) do
|
||||
:interactive -> modules ++ get_modules_from_applications(node)
|
||||
_otherwise -> modules
|
||||
if node == node() and :code.get_mode() == :interactive do
|
||||
modules ++ get_modules_from_applications()
|
||||
else
|
||||
modules
|
||||
end
|
||||
end
|
||||
|
||||
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(node) do
|
||||
defp get_modules_from_applications() 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.
|
||||
:erpc.call(node, :ets, :match, [:ac_tab, {{:loaded, :"$1"}, :_}])
|
||||
for [app] <- :ets.match(:ac_tab, {{:loaded, :"$1"}, :_}),
|
||||
{:ok, modules} = :application.get_key(app, :modules),
|
||||
module <- modules,
|
||||
do: module
|
||||
end
|
||||
|
||||
defp match_module_function(mod, hint, ctx, funs \\ nil) do
|
||||
if :erpc.call(ctx.node, Code, :ensure_loaded?, [mod]) do
|
||||
if ensure_loaded?(mod, ctx.node) do
|
||||
funs = funs || exports(mod, ctx.node)
|
||||
|
||||
matching_funs =
|
||||
|
@ -686,21 +688,21 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
|
|||
end
|
||||
|
||||
defp exports(mod, node) do
|
||||
loaded = :erpc.call(node, Code, :ensure_loaded?, [mod])
|
||||
exported = :erpc.call(node, :erlang, :function_exported, [mod, :__info__, 1])
|
||||
|
||||
if loaded and exported do
|
||||
macros = :erpc.call(node, mod, :__info__, [:macros])
|
||||
functions = :erpc.call(node, mod, :__info__, [:functions]) -- [__info__: 1]
|
||||
append_funs_type(macros, :macro) ++ append_funs_type(functions, :function)
|
||||
else
|
||||
functions =
|
||||
:erpc.call(node, mod, :module_info, [:exports]) -- [module_info: 0, module_info: 1]
|
||||
|
||||
append_funs_type(functions, :function)
|
||||
end
|
||||
for {fun, arity} <- :erpc.call(node, mod, :module_info, [:exports]),
|
||||
not reflection?(fun, arity),
|
||||
do: function_or_macro(Atom.to_string(fun), fun, arity)
|
||||
end
|
||||
|
||||
defp reflection?(:module_info, 0), do: true
|
||||
defp reflection?(:module_info, 1), do: true
|
||||
defp reflection?(:__info__, 1), do: true
|
||||
defp reflection?(_, _), do: false
|
||||
|
||||
defp function_or_macro("MACRO-" <> name, _, arity),
|
||||
do: {String.to_atom(name), arity - 1, :macro}
|
||||
|
||||
defp function_or_macro(_, fun, arity), do: {fun, arity, :function}
|
||||
|
||||
defp append_funs_type(funs, type) do
|
||||
Enum.map(funs, &Tuple.append(&1, type))
|
||||
end
|
||||
|
@ -745,8 +747,11 @@ defmodule Livebook.Intellisense.IdentifierMatcher do
|
|||
end
|
||||
end
|
||||
|
||||
# Skip Elixir to avoid warnings
|
||||
defp ensure_loaded?(Elixir, _node), do: false
|
||||
defp ensure_loaded?(mod, node), do: :erpc.call(node, Code, :ensure_loaded?, [mod])
|
||||
# Remote nodes only have loaded modules
|
||||
defp ensure_loaded?(_mod, node) when node != node(), do: true
|
||||
defp ensure_loaded?(mod, _node), do: Code.ensure_loaded?(mod)
|
||||
|
||||
defp imports_from_env(env) do
|
||||
Enum.map(env.functions, fn {mod, funs} ->
|
||||
|
|
Loading…
Add table
Reference in a new issue