Skip to content

Commit

Permalink
fix: use registry for runtime messaging
Browse files Browse the repository at this point in the history
This allows a runtime to register itself, which is necessary for when a
runtime crashes and restarts.
  • Loading branch information
mhanberg committed Jul 20, 2023
1 parent 7188497 commit f58aa39
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 40 deletions.
78 changes: 47 additions & 31 deletions lib/next_ls.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ defmodule NextLS do
:dynamic_supervisor,
:extensions,
:extension_registry,
:runtime_registry,
:symbol_table
])

Expand All @@ -56,6 +57,7 @@ defmodule NextLS do
runtime_task_supervisor = Keyword.fetch!(args, :runtime_task_supervisor)
dynamic_supervisor = Keyword.fetch!(args, :dynamic_supervisor)
extension_registry = Keyword.fetch!(args, :extension_registry)
runtime_registry = Keyword.fetch!(args, :runtime_registry)
extensions = Keyword.get(args, :extensions, [NextLS.ElixirExtension])
cache = Keyword.fetch!(args, :cache)
symbol_table = Keyword.fetch!(args, :symbol_table)
Expand All @@ -73,6 +75,7 @@ defmodule NextLS do
runtime_task_supervisor: runtime_task_supervisor,
dynamic_supervisor: dynamic_supervisor,
extension_registry: extension_registry,
runtime_registry: runtime_registry,
extensions: extensions,
runtime_tasks: nil,
ready: false,
Expand Down Expand Up @@ -208,38 +211,49 @@ defmodule NextLS do
def handle_request(%TextDocumentFormatting{params: %{text_document: %{uri: uri}}}, lsp) do
document = lsp.assigns.documents[uri]

{_, %{runtime: runtime}} =
Enum.find(lsp.assigns.runtimes, fn {_name, %{uri: wuri}} -> String.starts_with?(uri, wuri) end)

with {:ok, {formatter, _}} <- Runtime.call(runtime, {Mix.Tasks.Format, :formatter_for_file, [".formatter.exs"]}),
{:ok, response} when is_binary(response) or is_list(response) <-
Runtime.call(runtime, {Kernel, :apply, [formatter, [Enum.join(document, "\n")]]}) do
{:reply,
[
%TextEdit{
new_text: IO.iodata_to_binary(response),
range: %Range{
start: %Position{line: 0, character: 0},
end: %Position{
line: length(document),
character: document |> List.last() |> String.length() |> Kernel.-(1) |> max(0)
}
}
}
], lsp}
else
{:error, :not_ready} ->
GenLSP.notify(lsp, %GenLSP.Notifications.WindowShowMessage{
params: %GenLSP.Structures.ShowMessageParams{
type: GenLSP.Enumerations.MessageType.info(),
message: "The NextLS runtime is still initializing!"
}
})
me = self()

Registry.dispatch(lsp.assigns.runtime_registry, :runtimes, fn entries ->
for {runtime, %{uri: wuri}} <- entries, String.starts_with?(uri, wuri) do
with {:ok, {formatter, _}} <-
Runtime.call(runtime, {Mix.Tasks.Format, :formatter_for_file, [".formatter.exs"]}),
{:ok, response} when is_binary(response) or is_list(response) <-
Runtime.call(runtime, {Kernel, :apply, [formatter, [Enum.join(document, "\n")]]}) do
send(
me,
{:reply,
[
%TextEdit{
new_text: IO.iodata_to_binary(response),
range: %Range{
start: %Position{line: 0, character: 0},
end: %Position{
line: length(document),
character: document |> List.last() |> String.length() |> Kernel.-(1) |> max(0)
}
}
}
], lsp}
)
else
{:error, :not_ready} ->
GenLSP.notify(lsp, %GenLSP.Notifications.WindowShowMessage{
params: %GenLSP.Structures.ShowMessageParams{
type: GenLSP.Enumerations.MessageType.info(),
message: "The NextLS runtime is still initializing!"
}
})

{:reply, nil, lsp}
send(me, {:reply, nil, lsp})

_ ->
send(me, {:reply, nil, lsp})
end
end
end)

_ ->
{:reply, nil, lsp}
receive do
{:reply, _, _} = resp -> resp
end
end

Expand Down Expand Up @@ -271,7 +285,7 @@ defmodule NextLS do
)
end

GenLSP.log(lsp, "[NextLS] Booting runtime...")
GenLSP.log(lsp, "[NextLS] Booting runtimes...")

runtimes =
for %{uri: uri, name: name} <- lsp.assigns.workspace_folders do
Expand All @@ -284,7 +298,9 @@ defmodule NextLS do
{NextLS.Runtime,
task_supervisor: lsp.assigns.runtime_task_supervisor,
extension_registry: lsp.assigns.extension_registry,
runtime_registry: lsp.assigns.runtime_registry,
working_dir: URI.parse(uri).path,
uri: uri,
parent: self(),
logger: lsp.assigns.logger}
)
Expand Down
5 changes: 4 additions & 1 deletion lib/next_ls/lsp_supervisor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,16 @@ defmodule NextLS.LSPSupervisor do
{NextLS.DiagnosticCache, name: :diagnostic_cache},
{NextLS.SymbolTable, name: :symbol_table, path: hidden_folder},
{Registry, name: NextLS.ExtensionRegistry, keys: :duplicate},
{Registry, name: NextLS.RuntimeRegistry, keys: :duplicate},
{NextLS,
cache: :diagnostic_cache,
symbol_table: :symbol_table,
task_supervisor: NextLS.TaskSupervisor,
runtime_task_supervisor: :runtime_task_supervisor,
dynamic_supervisor: NextLS.DynamicSupervisor,
extension_registry: NextLS.ExtensionRegistry}
extension_registry: NextLS.ExtensionRegistry,
runtime_registry: NextLS.RuntimeRegistry,
}
]

Supervisor.init(children, strategy: :one_for_one)
Expand Down
4 changes: 4 additions & 0 deletions lib/next_ls/runtime.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,14 @@ defmodule NextLS.Runtime do
def init(opts) do
sname = "nextls-runtime-#{System.system_time()}"
working_dir = Keyword.fetch!(opts, :working_dir)
uri = Keyword.fetch!(opts, :uri)
parent = Keyword.fetch!(opts, :parent)
logger = Keyword.fetch!(opts, :logger)
task_supervisor = Keyword.fetch!(opts, :task_supervisor)
extension_registry = Keyword.fetch!(opts, :extension_registry)
runtime_registry = Keyword.fetch!(opts, :runtime_registry)

Registry.register(runtime_registry, :runtimes, %{uri: uri})

port =
Port.open(
Expand Down
21 changes: 15 additions & 6 deletions test/next_ls/runtime_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,20 @@ defmodule NextLs.RuntimeTest do
end

test "returns the response in an ok tuple", %{logger: logger, cwd: cwd} do
start_supervised!({Registry, keys: :unique, name: RuntimeTestRegistry})
start_supervised!({Registry, keys: :duplicate, name: RuntimeTest.RuntimeRegistry})
start_supervised!({Registry, keys: :duplicate, name: RuntimeTest.ExtensionRegistry})
tvisor = start_supervised!(Task.Supervisor)

pid =
start_supervised!(
{Runtime,
task_supervisor: tvisor,
working_dir: cwd,
uri: "file://#{cwd}",
parent: self(),
logger: logger,
extension_registry: RuntimeTestRegistry}
runtime_registry: RuntimeTest.RuntimeRegistry,
extension_registry: RuntimeTest.ExtensionRegistry}
)

Process.link(pid)
Expand All @@ -62,7 +65,8 @@ defmodule NextLs.RuntimeTest do
end

test "call returns an error when the runtime is node ready", %{logger: logger, cwd: cwd} do
start_supervised!({Registry, keys: :unique, name: RuntimeTestRegistry})
start_supervised!({Registry, keys: :duplicate, name: RuntimeTest.RuntimeRegistry})
start_supervised!({Registry, keys: :duplicate, name: RuntimeTest.ExtensionRegistry})

tvisor = start_supervised!(Task.Supervisor)

Expand All @@ -71,9 +75,11 @@ defmodule NextLs.RuntimeTest do
{Runtime,
task_supervisor: tvisor,
working_dir: cwd,
uri: "file://#{cwd}",
parent: self(),
logger: logger,
extension_registry: RuntimeTestRegistry}
runtime_registry: RuntimeTest.RuntimeRegistry,
extension_registry: RuntimeTest.ExtensionRegistry}
)

Process.link(pid)
Expand All @@ -82,7 +88,8 @@ defmodule NextLs.RuntimeTest do
end

test "compiles the code and returns diagnostics", %{logger: logger, cwd: cwd} do
start_supervised!({Registry, keys: :unique, name: RuntimeTestRegistry})
start_supervised!({Registry, keys: :duplicate, name: RuntimeTest.RuntimeRegistry})
start_supervised!({Registry, keys: :duplicate, name: RuntimeTest.ExtensionRegistry})

tvisor = start_supervised!(Task.Supervisor)

Expand All @@ -92,9 +99,11 @@ defmodule NextLs.RuntimeTest do
{Runtime,
task_supervisor: tvisor,
working_dir: cwd,
uri: "file://#{cwd}",
parent: self(),
logger: logger,
extension_registry: RuntimeTestRegistry}
runtime_registry: RuntimeTest.RuntimeRegistry,
extension_registry: RuntimeTest.ExtensionRegistry}
)

Process.link(pid)
Expand Down
6 changes: 4 additions & 2 deletions test/next_ls_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,8 @@ defmodule NextLSTest do
tvisor = start_supervised!(Supervisor.child_spec(Task.Supervisor, id: :one))
r_tvisor = start_supervised!(Supervisor.child_spec(Task.Supervisor, id: :two))
rvisor = start_supervised!({DynamicSupervisor, [strategy: :one_for_one]})
start_supervised!({Registry, [keys: :unique, name: Registry.NextLSTest]})
start_supervised!({Registry, [keys: :duplicate, name: Registry.NextLSTest.Extensions]})
start_supervised!({Registry, [keys: :duplicate, name: Registry.NextLSTest.Runtimes]})
extensions = [NextLS.ElixirExtension]
cache = start_supervised!(NextLS.DiagnosticCache)
symbol_table = start_supervised!({NextLS.SymbolTable, path: tmp_dir})
Expand All @@ -877,7 +878,8 @@ defmodule NextLSTest do
task_supervisor: tvisor,
runtime_task_supervisor: r_tvisor,
dynamic_supervisor: rvisor,
extension_registry: Registry.NextLSTest,
extension_registry: Registry.NextLSTest.Extensions,
runtime_registry: Registry.NextLSTest.Runtimes,
extensions: extensions,
cache: cache,
symbol_table: symbol_table
Expand Down

0 comments on commit f58aa39

Please sign in to comment.