Skip to content

Commit 1103d01

Browse files
authored
fix: create the symbol table in the workspace path (#125)
1 parent df331dc commit 1103d01

9 files changed

+160
-123
lines changed

lib/next_ls.ex

+66-83
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ defmodule NextLS do
4242
:runtime_task_supervisor,
4343
:dynamic_supervisor,
4444
:extensions,
45-
:registry,
46-
:symbol_table
45+
:registry
4746
])
4847

4948
GenLSP.start_link(__MODULE__, args, opts)
@@ -58,7 +57,6 @@ defmodule NextLS do
5857
registry = Keyword.fetch!(args, :registry)
5958
extensions = Keyword.get(args, :extensions, [NextLS.ElixirExtension])
6059
cache = Keyword.fetch!(args, :cache)
61-
symbol_table = Keyword.fetch!(args, :symbol_table)
6260
{:ok, logger} = DynamicSupervisor.start_child(dynamic_supervisor, {NextLS.Logger, lsp: lsp})
6361

6462
{:ok,
@@ -68,7 +66,6 @@ defmodule NextLS do
6866
refresh_refs: %{},
6967
cache: cache,
7068
logger: logger,
71-
symbol_table: symbol_table,
7269
task_supervisor: task_supervisor,
7370
runtime_task_supervisor: runtime_task_supervisor,
7471
dynamic_supervisor: dynamic_supervisor,
@@ -118,35 +115,39 @@ defmodule NextLS do
118115

119116
def handle_request(%TextDocumentDefinition{params: %{text_document: %{uri: uri}, position: position}}, lsp) do
120117
result =
121-
case Definition.fetch(
122-
URI.parse(uri).path,
123-
{position.line + 1, position.character + 1},
124-
:symbol_table,
125-
:reference_table
126-
) do
127-
nil ->
128-
nil
129-
130-
[] ->
131-
nil
132-
133-
[{file, line, column} | _] ->
134-
%Location{
135-
uri: "file://#{file}",
136-
range: %Range{
137-
start: %Position{
138-
line: line - 1,
139-
character: column - 1
140-
},
141-
end: %Position{
142-
line: line - 1,
143-
character: column - 1
118+
dispatch(lsp.assigns.registry, :symbol_tables, fn entries ->
119+
for {_, %{symbol_table: symbol_table, reference_table: ref_table}} <- entries do
120+
case Definition.fetch(
121+
URI.parse(uri).path,
122+
{position.line + 1, position.character + 1},
123+
symbol_table,
124+
ref_table
125+
) do
126+
nil ->
127+
nil
128+
129+
[] ->
130+
nil
131+
132+
[{file, line, column} | _] ->
133+
%Location{
134+
uri: "file://#{file}",
135+
range: %Range{
136+
start: %Position{
137+
line: line - 1,
138+
character: column - 1
139+
},
140+
end: %Position{
141+
line: line - 1,
142+
character: column - 1
143+
}
144+
}
144145
}
145-
}
146-
}
147-
end
146+
end
147+
end
148+
end)
148149

149-
{:reply, result, lsp}
150+
{:reply, List.first(result), lsp}
150151
end
151152

152153
def handle_request(%TextDocumentDocumentSymbol{params: %{text_document: %{uri: uri}}}, lsp) do
@@ -174,32 +175,34 @@ defmodule NextLS do
174175
end
175176

176177
symbols =
177-
for %SymbolTable.Symbol{} = symbol <- SymbolTable.symbols(lsp.assigns.symbol_table), filter.(symbol.name) do
178-
name =
179-
if symbol.type != :defstruct do
180-
"#{symbol.type} #{symbol.name}"
181-
else
182-
"#{symbol.name}"
183-
end
184-
185-
%SymbolInformation{
186-
name: name,
187-
kind: elixir_kind_to_lsp_kind(symbol.type),
188-
location: %Location{
189-
uri: "file://#{symbol.file}",
190-
range: %Range{
191-
start: %Position{
192-
line: symbol.line - 1,
193-
character: symbol.col - 1
194-
},
195-
end: %Position{
196-
line: symbol.line - 1,
197-
character: symbol.col - 1
178+
dispatch(lsp.assigns.registry, :symbol_tables, fn entries ->
179+
for {pid, _} <- entries, %SymbolTable.Symbol{} = symbol <- SymbolTable.symbols(pid), filter.(symbol.name) do
180+
name =
181+
if symbol.type != :defstruct do
182+
"#{symbol.type} #{symbol.name}"
183+
else
184+
"#{symbol.name}"
185+
end
186+
187+
%SymbolInformation{
188+
name: name,
189+
kind: elixir_kind_to_lsp_kind(symbol.type),
190+
location: %Location{
191+
uri: "file://#{symbol.file}",
192+
range: %Range{
193+
start: %Position{
194+
line: symbol.line - 1,
195+
character: symbol.col - 1
196+
},
197+
end: %Position{
198+
line: symbol.line - 1,
199+
character: symbol.col - 1
200+
}
198201
}
199202
}
200203
}
201-
}
202-
end
204+
end
205+
end)
203206

204207
{:reply, symbols, lsp}
205208
end
@@ -248,7 +251,9 @@ defmodule NextLS do
248251
end
249252

250253
def handle_request(%Shutdown{}, lsp) do
251-
SymbolTable.close(lsp.assigns.symbol_table)
254+
dispatch(lsp.assigns.registry, :symbol_tables, fn entries ->
255+
for {pid, _} <- entries, do: SymbolTable.close(pid)
256+
end)
252257

253258
{:reply, nil, assign(lsp, exit_code: 0)}
254259
end
@@ -281,18 +286,19 @@ defmodule NextLS do
281286
token = token()
282287
Progress.start(lsp, token, "Initializing NextLS runtime for folder #{name}...")
283288
parent = self()
289+
working_dir = URI.parse(uri).path
284290

285291
{:ok, runtime} =
286292
DynamicSupervisor.start_child(
287293
lsp.assigns.dynamic_supervisor,
288-
{NextLS.RuntimeSupervisor,
294+
{NextLS.Runtime.Supervisor,
295+
path: Path.join(working_dir, ".elixir-tools"),
296+
name: name,
297+
registry: lsp.assigns.registry,
289298
runtime: [
290-
name: name,
291299
task_supervisor: lsp.assigns.runtime_task_supervisor,
292-
registry: lsp.assigns.registry,
293-
working_dir: URI.parse(uri).path,
300+
working_dir: working_dir,
294301
uri: uri,
295-
parent: parent,
296302
on_initialized: fn status ->
297303
if status == :ready do
298304
Progress.stop(lsp, token, "NextLS runtime for folder #{name} has initialized!")
@@ -307,10 +313,6 @@ defmodule NextLS do
307313
]}
308314
)
309315

310-
ref = Process.monitor(runtime)
311-
312-
Process.put(ref, name)
313-
314316
{name, %{uri: uri, runtime: runtime}}
315317
end
316318

@@ -387,16 +389,6 @@ defmodule NextLS do
387389
{:noreply, lsp}
388390
end
389391

390-
def handle_info({:tracer, payload}, lsp) do
391-
SymbolTable.put_symbols(lsp.assigns.symbol_table, payload)
392-
{:noreply, lsp}
393-
end
394-
395-
def handle_info({{:tracer, :reference}, payload}, lsp) do
396-
SymbolTable.put_reference(lsp.assigns.symbol_table, payload)
397-
{:noreply, lsp}
398-
end
399-
400392
def handle_info(:publish, lsp) do
401393
GenLSP.log(lsp, "[NextLS] Compiled!")
402394

@@ -449,15 +441,6 @@ defmodule NextLS do
449441
{:noreply, assign(lsp, refresh_refs: refs)}
450442
end
451443

452-
def handle_info({:DOWN, ref, :process, _runtime, _reason}, lsp) do
453-
name = Process.get(ref)
454-
Process.delete(ref)
455-
456-
GenLSP.error(lsp, "[NextLS] The runtime for #{name} has crashed")
457-
458-
{:noreply, lsp}
459-
end
460-
461444
def handle_info(message, lsp) do
462445
GenLSP.log(lsp, "[NextLS] Unhandled message: #{inspect(message)}")
463446
{:noreply, lsp}

lib/next_ls/lsp_supervisor.ex

-9
Original file line numberDiff line numberDiff line change
@@ -51,24 +51,15 @@ defmodule NextLS.LSPSupervisor do
5151
raise OptionsError, invalid
5252
end
5353

54-
# FIXME: this directory should be inside the workspace, which will is not determined until
55-
# the LSP has begun initialization
56-
# The symbol table may need to started dynamically, like the extensions and the runtimes
57-
hidden_folder = Path.expand(".elixir-tools")
58-
File.mkdir_p!(hidden_folder)
59-
File.write!(Path.join(hidden_folder, ".gitignore"), "*\n")
60-
6154
children = [
6255
{DynamicSupervisor, name: NextLS.DynamicSupervisor},
6356
{Task.Supervisor, name: NextLS.TaskSupervisor},
6457
{Task.Supervisor, name: :runtime_task_supervisor},
6558
{GenLSP.Buffer, buffer_opts},
6659
{NextLS.DiagnosticCache, name: :diagnostic_cache},
67-
{NextLS.SymbolTable, name: :symbol_table, path: hidden_folder},
6860
{Registry, name: NextLS.Registry, keys: :duplicate},
6961
{NextLS,
7062
cache: :diagnostic_cache,
71-
symbol_table: :symbol_table,
7263
task_supervisor: NextLS.TaskSupervisor,
7364
runtime_task_supervisor: :runtime_task_supervisor,
7465
dynamic_supervisor: NextLS.DynamicSupervisor,

lib/next_ls/runtime.ex

+22-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ defmodule NextLS.Runtime do
5353

5454
Registry.register(registry, :runtimes, %{name: name, uri: uri})
5555

56+
pid =
57+
cond do
58+
is_pid(parent) -> parent
59+
is_atom(parent) -> Process.whereis(parent)
60+
end
61+
62+
parent =
63+
pid
64+
|> :erlang.term_to_binary()
65+
|> Base.encode64()
66+
|> String.to_charlist()
67+
5668
port =
5769
Port.open(
5870
{:spawn_executable, @exe},
@@ -64,7 +76,7 @@ defmodule NextLS.Runtime do
6476
cd: working_dir,
6577
env: [
6678
{~c"LSP", ~c"nextls"},
67-
{~c"NEXTLS_PARENT_PID", parent |> :erlang.term_to_binary() |> Base.encode64() |> String.to_charlist()},
79+
{~c"NEXTLS_PARENT_PID", parent},
6880
{~c"MIX_ENV", ~c"dev"},
6981
{~c"MIX_BUILD_ROOT", ~c".elixir-tools/_build"}
7082
],
@@ -85,6 +97,15 @@ defmodule NextLS.Runtime do
8597

8698
me = self()
8799

100+
Task.Supervisor.async_nolink(task_supervisor, fn ->
101+
ref = Process.monitor(me)
102+
103+
receive do
104+
{:DOWN, ^ref, :process, ^me, _reason} ->
105+
NextLS.Logger.error(logger, "[NextLS] The runtime for #{name} has crashed")
106+
end
107+
end)
108+
88109
Task.start_link(fn ->
89110
with {:ok, host} <- :inet.gethostname(),
90111
node <- :"#{sname}@#{host}",

lib/next_ls/runtime/sidecar.ex

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
defmodule NextLS.Runtime.Sidecar do
2+
@moduledoc false
3+
use GenServer
4+
5+
alias NextLS.SymbolTable
6+
7+
def start_link(args) do
8+
GenServer.start_link(__MODULE__, Keyword.take(args, [:symbol_table]), Keyword.take(args, [:name]))
9+
end
10+
11+
def init(args) do
12+
symbol_table = Keyword.fetch!(args, :symbol_table)
13+
{:ok, %{symbol_table: symbol_table}}
14+
end
15+
16+
def handle_info({:tracer, payload}, state) do
17+
SymbolTable.put_symbols(state.symbol_table, payload)
18+
{:noreply, state}
19+
end
20+
21+
def handle_info({{:tracer, :reference}, payload}, state) do
22+
SymbolTable.put_reference(state.symbol_table, payload)
23+
{:noreply, state}
24+
end
25+
end

lib/next_ls/runtime/supervisor.ex

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
defmodule NextLS.Runtime.Supervisor do
2+
@moduledoc false
3+
4+
use Supervisor
5+
6+
def start_link(init_arg) do
7+
Supervisor.start_link(__MODULE__, init_arg)
8+
end
9+
10+
@impl true
11+
def init(init_arg) do
12+
name = init_arg[:name]
13+
registry = init_arg[:registry]
14+
hidden_folder = init_arg[:path]
15+
File.mkdir_p!(hidden_folder)
16+
File.write!(Path.join(hidden_folder, ".gitignore"), "*\n")
17+
18+
symbol_table_name = :"symbol-table-#{name}"
19+
sidecar_name = :"sidecar-#{name}"
20+
21+
children = [
22+
{NextLS.SymbolTable, workspace: name, path: hidden_folder, registry: registry, name: symbol_table_name},
23+
{NextLS.Runtime.Sidecar, name: sidecar_name, symbol_table: symbol_table_name},
24+
{NextLS.Runtime, init_arg[:runtime] ++ [name: name, registry: registry, parent: sidecar_name]}
25+
]
26+
27+
Supervisor.init(children, strategy: :one_for_one)
28+
end
29+
end

lib/next_ls/runtime_supervisor.ex

-18
This file was deleted.

0 commit comments

Comments
 (0)