Skip to content

Commit 96bfc76

Browse files
authoredJul 6, 2023
fix: run compiler in task (#95)
This lets the compiler stdout messgaes to be logged to the client while the RPC is still happening. Previously, the port would message back to the process that was synchronously waiting on the RPC to finish, so it didn't send any log messages to the LSP process until the compiler was done. This made it look like the initial compiler was hanging. Fixes #60
1 parent 32f8313 commit 96bfc76

File tree

5 files changed

+69
-13
lines changed

5 files changed

+69
-13
lines changed
 

‎lib/next_ls.ex

+4
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ defmodule NextLS do
5353
Keyword.split(args, [
5454
:cache,
5555
:task_supervisor,
56+
:runtime_task_supervisor,
5657
:dynamic_supervisor,
5758
:extensions,
5859
:extension_registry,
@@ -65,6 +66,7 @@ defmodule NextLS do
6566
@impl true
6667
def init(lsp, args) do
6768
task_supervisor = Keyword.fetch!(args, :task_supervisor)
69+
runtime_task_supervisor = Keyword.fetch!(args, :runtime_task_supervisor)
6870
dynamic_supervisor = Keyword.fetch!(args, :dynamic_supervisor)
6971
extension_registry = Keyword.fetch!(args, :extension_registry)
7072
extensions = Keyword.get(args, :extensions, [NextLS.ElixirExtension])
@@ -81,6 +83,7 @@ defmodule NextLS do
8183
logger: logger,
8284
symbol_table: symbol_table,
8385
task_supervisor: task_supervisor,
86+
runtime_task_supervisor: runtime_task_supervisor,
8487
dynamic_supervisor: dynamic_supervisor,
8588
extension_registry: extension_registry,
8689
extensions: extensions,
@@ -272,6 +275,7 @@ defmodule NextLS do
272275
DynamicSupervisor.start_child(
273276
lsp.assigns.dynamic_supervisor,
274277
{NextLS.Runtime,
278+
task_supervisor: lsp.assigns.runtime_task_supervisor,
275279
extension_registry: lsp.assigns.extension_registry,
276280
working_dir: working_dir,
277281
parent: self(),

‎lib/next_ls/lsp_supervisor.ex

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ defmodule NextLS.LSPSupervisor do
3535
children = [
3636
{DynamicSupervisor, name: NextLS.DynamicSupervisor},
3737
{Task.Supervisor, name: NextLS.TaskSupervisor},
38+
{Task.Supervisor, name: :runtime_task_supervisor},
3839
{GenLSP.Buffer, buffer_opts},
3940
{NextLS.DiagnosticCache, name: :diagnostic_cache},
4041
{NextLS.SymbolTable, name: :symbol_table, path: Path.expand(".elixir-tools")},
@@ -43,6 +44,7 @@ defmodule NextLS.LSPSupervisor do
4344
cache: :diagnostic_cache,
4445
symbol_table: :symbol_table,
4546
task_supervisor: NextLS.TaskSupervisor,
47+
runtime_task_supervisor: :runtime_task_supervisor,
4648
dynamic_supervisor: NextLS.DynamicSupervisor,
4749
extension_registry: NextLS.ExtensionRegistry}
4850
]

‎lib/next_ls/runtime.ex

+37-9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ defmodule NextLS.Runtime do
4444
working_dir = Keyword.fetch!(opts, :working_dir)
4545
parent = Keyword.fetch!(opts, :parent)
4646
logger = Keyword.fetch!(opts, :logger)
47+
task_supervisor = Keyword.fetch!(opts, :task_supervisor)
4748
extension_registry = Keyword.fetch!(opts, :extension_registry)
4849

4950
port =
@@ -104,7 +105,16 @@ defmodule NextLS.Runtime do
104105
end
105106
end)
106107

107-
{:ok, %{port: port, logger: logger, parent: parent, errors: nil, extension_registry: extension_registry}}
108+
{:ok,
109+
%{
110+
compiler_ref: nil,
111+
port: port,
112+
task_supervisor: task_supervisor,
113+
logger: logger,
114+
parent: parent,
115+
errors: nil,
116+
extension_registry: extension_registry
117+
}}
108118
end
109119

110120
@impl GenServer
@@ -125,19 +135,37 @@ defmodule NextLS.Runtime do
125135
{:reply, {:error, :not_ready}, state}
126136
end
127137

128-
def handle_call(:compile, _, %{node: node} = state) do
129-
{_, errors} = :rpc.call(node, :_next_ls_private_compiler, :compile, [])
138+
def handle_call(:compile, from, %{node: node} = state) do
139+
task =
140+
Task.Supervisor.async_nolink(state.task_supervisor, fn ->
141+
{_, errors} = :rpc.call(node, :_next_ls_private_compiler, :compile, [])
130142

131-
Registry.dispatch(state.extension_registry, :extension, fn entries ->
132-
for {pid, _} <- entries do
133-
send(pid, {:compiler, errors})
134-
end
135-
end)
143+
Registry.dispatch(state.extension_registry, :extension, fn entries ->
144+
for {pid, _} <- entries do
145+
send(pid, {:compiler, errors})
146+
end
147+
end)
136148

137-
{:reply, errors, %{state | errors: errors}}
149+
errors
150+
end)
151+
152+
{:noreply, %{state | compiler_ref: %{task.ref => from}}}
138153
end
139154

140155
@impl GenServer
156+
def handle_info({ref, errors}, %{compiler_ref: compiler_ref} = state) when is_map_key(compiler_ref, ref) do
157+
Process.demonitor(ref, [:flush])
158+
159+
GenServer.reply(compiler_ref[ref], errors)
160+
161+
{:noreply, %{state | compiler_ref: nil}}
162+
end
163+
164+
def handle_info({:DOWN, ref, :process, _pid, _reason}, %{compiler_ref: compiler_ref} = state)
165+
when is_map_key(compiler_ref, ref) do
166+
{:noreply, %{state | compiler_ref: nil}}
167+
end
168+
141169
def handle_info({:node, node}, state) do
142170
Node.monitor(node, true)
143171
{:noreply, Map.put(state, :node, node)}

‎test/next_ls/runtime_test.exs

+23-3
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,16 @@ defmodule NextLs.RuntimeTest do
4141

4242
test "returns the response in an ok tuple", %{logger: logger, cwd: cwd} do
4343
start_supervised!({Registry, keys: :unique, name: RuntimeTestRegistry})
44+
tvisor = start_supervised!(Task.Supervisor)
4445

4546
pid =
4647
start_supervised!(
47-
{Runtime, working_dir: cwd, parent: self(), logger: logger, extension_registry: RuntimeTestRegistry}
48+
{Runtime,
49+
task_supervisor: tvisor,
50+
working_dir: cwd,
51+
parent: self(),
52+
logger: logger,
53+
extension_registry: RuntimeTestRegistry}
4854
)
4955

5056
Process.link(pid)
@@ -57,9 +63,16 @@ defmodule NextLs.RuntimeTest do
5763
test "call returns an error when the runtime is node ready", %{logger: logger, cwd: cwd} do
5864
start_supervised!({Registry, keys: :unique, name: RuntimeTestRegistry})
5965

66+
tvisor = start_supervised!(Task.Supervisor)
67+
6068
pid =
6169
start_supervised!(
62-
{Runtime, working_dir: cwd, parent: self(), logger: logger, extension_registry: RuntimeTestRegistry}
70+
{Runtime,
71+
task_supervisor: tvisor,
72+
working_dir: cwd,
73+
parent: self(),
74+
logger: logger,
75+
extension_registry: RuntimeTestRegistry}
6376
)
6477

6578
Process.link(pid)
@@ -70,10 +83,17 @@ defmodule NextLs.RuntimeTest do
7083
test "compiles the code and returns diagnostics", %{logger: logger, cwd: cwd} do
7184
start_supervised!({Registry, keys: :unique, name: RuntimeTestRegistry})
7285

86+
tvisor = start_supervised!(Task.Supervisor)
87+
7388
capture_log(fn ->
7489
pid =
7590
start_supervised!(
76-
{Runtime, working_dir: cwd, parent: self(), logger: logger, extension_registry: RuntimeTestRegistry}
91+
{Runtime,
92+
task_supervisor: tvisor,
93+
working_dir: cwd,
94+
parent: self(),
95+
logger: logger,
96+
extension_registry: RuntimeTestRegistry}
7797
)
7898

7999
Process.link(pid)

‎test/next_ls_test.exs

+3-1
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,8 @@ defmodule NextLSTest do
869869
defp with_lsp(%{tmp_dir: tmp_dir}) do
870870
root_path = Path.absname(tmp_dir)
871871

872-
tvisor = start_supervised!(Task.Supervisor)
872+
tvisor = start_supervised!(Supervisor.child_spec(Task.Supervisor, id: :one))
873+
r_tvisor = start_supervised!(Supervisor.child_spec(Task.Supervisor, id: :two))
873874
rvisor = start_supervised!({DynamicSupervisor, [strategy: :one_for_one]})
874875
start_supervised!({Registry, [keys: :unique, name: Registry.NextLSTest]})
875876
extensions = [NextLS.ElixirExtension]
@@ -879,6 +880,7 @@ defmodule NextLSTest do
879880
server =
880881
server(NextLS,
881882
task_supervisor: tvisor,
883+
runtime_task_supervisor: r_tvisor,
882884
dynamic_supervisor: rvisor,
883885
extension_registry: Registry.NextLSTest,
884886
extensions: extensions,

0 commit comments

Comments
 (0)
Please sign in to comment.