Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proxy for expensive API requests #736

Merged
merged 10 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 56 additions & 6 deletions apps/remote_control/lib/lexical/remote_control.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,62 @@ defmodule Lexical.RemoteControl do
"""

alias Lexical.Project
alias Lexical.RemoteControl
alias Lexical.RemoteControl.Api.Proxy
alias Lexical.RemoteControl.CodeAction
alias Lexical.RemoteControl.CodeIntelligence
alias Lexical.RemoteControl.ProjectNode

require Logger

@excluded_apps [:patch, :nimble_parsec]
@allowed_apps [:remote_control | Mix.Project.deps_apps()] -- @excluded_apps

defdelegate schedule_compile(force?), to: Proxy

defdelegate compile_document(document), to: Proxy

defdelegate format(document), to: Proxy

defdelegate reindex, to: Proxy

defdelegate index_running?, to: Proxy

defdelegate broadcast(message), to: Proxy

defdelegate expand_alias(segments_or_module, analysis, position), to: RemoteControl.Analyzer

defdelegate list_modules, to: :code, as: :all_available

defdelegate code_actions(document, range, diagnostics, kinds), to: CodeAction, as: :for_range

defdelegate complete(env), to: RemoteControl.Completion, as: :elixir_sense_expand

defdelegate complete_struct_fields(analysis, position),
to: RemoteControl.Completion,
as: :struct_fields

defdelegate definition(document, position), to: CodeIntelligence.Definition

defdelegate references(analysis, position, include_definitions?),
to: CodeIntelligence.References

defdelegate modules_with_prefix(prefix), to: RemoteControl.Modules, as: :with_prefix

defdelegate modules_with_prefix(prefix, predicate), to: RemoteControl.Modules, as: :with_prefix

defdelegate docs(module, opts \\ []), to: CodeIntelligence.Docs, as: :for_module

defdelegate register_listener(listener_pid, message_types), to: RemoteControl.Dispatch

defdelegate resolve_entity(analysis, position), to: CodeIntelligence.Entity, as: :resolve

defdelegate struct_definitions, to: CodeIntelligence.Structs, as: :for_project

defdelegate document_symbols(document), to: CodeIntelligence.Symbols, as: :for_document

defdelegate workspace_symbols(query), to: CodeIntelligence.Symbols, as: :for_workspace

def start_link(%Project{} = project) do
:ok = ensure_epmd_started()
start_net_kernel(project)
Expand Down Expand Up @@ -49,15 +99,15 @@ defmodule Lexical.RemoteControl do
|> :erpc.call(m, f, a)
end

defp start_net_kernel(%Project{} = project) do
:net_kernel.start([manager_node_name(project)])
end

def manager_node_name(%Project{} = project) do
:"manager-#{Project.name(project)}-#{Project.entropy(project)}@127.0.0.1"
end

def ensure_apps_started(node, app_names) do
defp start_net_kernel(%Project{} = project) do
:net_kernel.start([manager_node_name(project)])
end

defp ensure_apps_started(node, app_names) do
Enum.reduce_while(app_names, :ok, fn app_name, _ ->
case :rpc.call(node, :application, :ensure_all_started, [app_name]) do
{:ok, _} -> {:cont, :ok}
Expand All @@ -66,7 +116,7 @@ defmodule Lexical.RemoteControl do
end)
end

def glob_paths do
defp glob_paths do
for entry <- :code.get_path(),
entry_string = List.to_string(entry),
entry_string != ".",
Expand Down
59 changes: 31 additions & 28 deletions apps/remote_control/lib/lexical/remote_control/api.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,37 @@ defmodule Lexical.RemoteControl.Api do
alias Lexical.Document.Range
alias Lexical.Project
alias Lexical.RemoteControl
alias Lexical.RemoteControl.Build
alias Lexical.RemoteControl.CodeAction
alias Lexical.RemoteControl.CodeIntelligence
alias Lexical.RemoteControl.CodeMod
alias Lexical.RemoteControl.Commands

require Logger

defdelegate schedule_compile(project, force?), to: Build
defdelegate compile_document(project, document), to: Build
def schedule_compile(%Project{} = project, force?) do
RemoteControl.call(project, RemoteControl, :schedule_compile, [force?])
end

def compile_document(%Project{} = project, %Document{} = document) do
RemoteControl.call(project, RemoteControl, :compile_document, [document])
end

def expand_alias(
%Project{} = project,
segments_or_module,
%Analysis{} = analysis,
%Position{} = position
) do
RemoteControl.call(project, RemoteControl.Analyzer, :expand_alias, [
RemoteControl.call(project, RemoteControl, :expand_alias, [
segments_or_module,
analysis,
position
])
end

def list_modules(%Project{} = project) do
RemoteControl.call(project, :code, :all_available)
RemoteControl.call(project, RemoteControl, :list_modules)
end

def format(%Project{} = project, %Document{} = document) do
RemoteControl.call(project, CodeMod.Format, :edits, [document])
RemoteControl.call(project, RemoteControl, :format, [document])
end

def code_actions(
Expand All @@ -45,26 +46,28 @@ defmodule Lexical.RemoteControl.Api do
diagnostics,
kinds
) do
RemoteControl.call(project, CodeAction, :for_range, [document, range, diagnostics, kinds])
RemoteControl.call(project, RemoteControl, :code_actions, [
document,
range,
diagnostics,
kinds
])
end

def complete(%Project{} = project, %Env{} = env) do
Logger.info("Completion for #{inspect(env.position)}")
RemoteControl.call(project, RemoteControl.Completion, :elixir_sense_expand, [env])
RemoteControl.call(project, RemoteControl, :complete, [env])
end

def complete_struct_fields(%Project{} = project, %Analysis{} = analysis, %Position{} = position) do
RemoteControl.call(project, RemoteControl.Completion, :struct_fields, [
RemoteControl.call(project, RemoteControl, :complete_struct_fields, [
analysis,
position
])
end

def definition(%Project{} = project, %Document{} = document, %Position{} = position) do
RemoteControl.call(project, CodeIntelligence.Definition, :definition, [
document,
position
])
RemoteControl.call(project, RemoteControl, :definition, [document, position])
end

def references(
Expand All @@ -73,7 +76,7 @@ defmodule Lexical.RemoteControl.Api do
%Position{} = position,
include_definitions?
) do
RemoteControl.call(project, CodeIntelligence.References, :references, [
RemoteControl.call(project, RemoteControl, :references, [
analysis,
position,
include_definitions?
Expand All @@ -82,52 +85,52 @@ defmodule Lexical.RemoteControl.Api do

def modules_with_prefix(%Project{} = project, prefix)
when is_binary(prefix) or is_atom(prefix) do
RemoteControl.call(project, RemoteControl.Modules, :with_prefix, [prefix])
RemoteControl.call(project, RemoteControl, :modules_with_prefix, [prefix])
end

def modules_with_prefix(%Project{} = project, prefix, predicate)
when is_binary(prefix) or is_atom(prefix) do
RemoteControl.call(project, RemoteControl.Modules, :with_prefix, [prefix, predicate])
RemoteControl.call(project, RemoteControl, :modules_with_prefix, [prefix, predicate])
end

@spec docs(Project.t(), module()) :: {:ok, CodeIntelligence.Docs.t()} | {:error, any()}
def docs(%Project{} = project, module, opts \\ []) when is_atom(module) do
RemoteControl.call(project, CodeIntelligence.Docs, :for_module, [module, opts])
RemoteControl.call(project, RemoteControl, :docs, [module, opts])
end

def register_listener(%Project{} = project, listener_pid, message_types)
when is_pid(listener_pid) and is_list(message_types) do
RemoteControl.call(project, RemoteControl.Dispatch, :register_listener, [
RemoteControl.call(project, RemoteControl, :register_listener, [
listener_pid,
message_types
])
end

def broadcast(%Project{} = project, message) do
RemoteControl.call(project, RemoteControl.Dispatch, :broadcast, [message])
RemoteControl.call(project, RemoteControl, :broadcast, [message])
end

def reindex(%Project{} = project) do
RemoteControl.call(project, Commands.Reindex, :perform, [])
RemoteControl.call(project, RemoteControl, :reindex, [])
end

def index_running?(%Project{} = project) do
RemoteControl.call(project, Commands.Reindex, :running?, [])
RemoteControl.call(project, RemoteControl, :index_running?, [])
end

def resolve_entity(%Project{} = project, %Analysis{} = analysis, %Position{} = position) do
RemoteControl.call(project, CodeIntelligence.Entity, :resolve, [analysis, position])
RemoteControl.call(project, RemoteControl, :resolve_entity, [analysis, position])
end

def struct_definitions(%Project{} = project) do
RemoteControl.call(project, CodeIntelligence.Structs, :for_project, [])
RemoteControl.call(project, RemoteControl, :struct_definitions, [])
end

def document_symbols(%Project{} = project, %Document{} = document) do
RemoteControl.call(project, CodeIntelligence.Symbols, :for_document, [document])
RemoteControl.call(project, RemoteControl, :document_symbols, [document])
end

def workspace_symbols(%Project{} = project, query) do
RemoteControl.call(project, CodeIntelligence.Symbols, :for_workspace, [query])
RemoteControl.call(project, RemoteControl, :workspace_symbols, [query])
end
end
Loading
Loading