Skip to content

Commit

Permalink
fix: create the symbol table in the workspace path
Browse files Browse the repository at this point in the history
  • Loading branch information
mhanberg committed Jul 24, 2023
1 parent df331dc commit d9bacac
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 123 deletions.
149 changes: 66 additions & 83 deletions lib/next_ls.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ defmodule NextLS do
:runtime_task_supervisor,
:dynamic_supervisor,
:extensions,
:registry,
:symbol_table
:registry
])

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

{:ok,
Expand All @@ -68,7 +66,6 @@ defmodule NextLS do
refresh_refs: %{},
cache: cache,
logger: logger,
symbol_table: symbol_table,
task_supervisor: task_supervisor,
runtime_task_supervisor: runtime_task_supervisor,
dynamic_supervisor: dynamic_supervisor,
Expand Down Expand Up @@ -118,35 +115,39 @@ defmodule NextLS do

def handle_request(%TextDocumentDefinition{params: %{text_document: %{uri: uri}, position: position}}, lsp) do
result =
case Definition.fetch(
URI.parse(uri).path,
{position.line + 1, position.character + 1},
:symbol_table,
:reference_table
) do
nil ->
nil

[] ->
nil

[{file, line, column} | _] ->
%Location{
uri: "file://#{file}",
range: %Range{
start: %Position{
line: line - 1,
character: column - 1
},
end: %Position{
line: line - 1,
character: column - 1
dispatch(lsp.assigns.registry, :symbol_tables, fn entries ->
for {_, %{symbol_table: symbol_table, reference_table: ref_table}} <- entries do
case Definition.fetch(
URI.parse(uri).path,
{position.line + 1, position.character + 1},
symbol_table,
ref_table
) do
nil ->
nil

[] ->
nil

[{file, line, column} | _] ->
%Location{
uri: "file://#{file}",
range: %Range{
start: %Position{
line: line - 1,
character: column - 1
},
end: %Position{
line: line - 1,
character: column - 1
}
}
}
}
}
end
end
end
end)

{:reply, result, lsp}
{:reply, List.first(result), lsp}
end

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

symbols =
for %SymbolTable.Symbol{} = symbol <- SymbolTable.symbols(lsp.assigns.symbol_table), filter.(symbol.name) do
name =
if symbol.type != :defstruct do
"#{symbol.type} #{symbol.name}"
else
"#{symbol.name}"
end

%SymbolInformation{
name: name,
kind: elixir_kind_to_lsp_kind(symbol.type),
location: %Location{
uri: "file://#{symbol.file}",
range: %Range{
start: %Position{
line: symbol.line - 1,
character: symbol.col - 1
},
end: %Position{
line: symbol.line - 1,
character: symbol.col - 1
dispatch(lsp.assigns.registry, :symbol_tables, fn entries ->
for {pid, _} <- entries, %SymbolTable.Symbol{} = symbol <- SymbolTable.symbols(pid), filter.(symbol.name) do
name =
if symbol.type != :defstruct do
"#{symbol.type} #{symbol.name}"
else
"#{symbol.name}"
end

%SymbolInformation{
name: name,
kind: elixir_kind_to_lsp_kind(symbol.type),
location: %Location{
uri: "file://#{symbol.file}",
range: %Range{
start: %Position{
line: symbol.line - 1,
character: symbol.col - 1
},
end: %Position{
line: symbol.line - 1,
character: symbol.col - 1
}
}
}
}
}
end
end
end)

{:reply, symbols, lsp}
end
Expand Down Expand Up @@ -248,7 +251,9 @@ defmodule NextLS do
end

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

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

{:ok, runtime} =
DynamicSupervisor.start_child(
lsp.assigns.dynamic_supervisor,
{NextLS.RuntimeSupervisor,
{NextLS.Runtime.Supervisor,
path: Path.join(working_dir, ".elixir-tools"),
name: name,
registry: lsp.assigns.registry,
runtime: [
name: name,
task_supervisor: lsp.assigns.runtime_task_supervisor,
registry: lsp.assigns.registry,
working_dir: URI.parse(uri).path,
working_dir: working_dir,
uri: uri,
parent: parent,
on_initialized: fn status ->
if status == :ready do
Progress.stop(lsp, token, "NextLS runtime for folder #{name} has initialized!")
Expand All @@ -307,10 +313,6 @@ defmodule NextLS do
]}
)

ref = Process.monitor(runtime)

Process.put(ref, name)

{name, %{uri: uri, runtime: runtime}}
end

Expand Down Expand Up @@ -387,16 +389,6 @@ defmodule NextLS do
{:noreply, lsp}
end

def handle_info({:tracer, payload}, lsp) do
SymbolTable.put_symbols(lsp.assigns.symbol_table, payload)
{:noreply, lsp}
end

def handle_info({{:tracer, :reference}, payload}, lsp) do
SymbolTable.put_reference(lsp.assigns.symbol_table, payload)
{:noreply, lsp}
end

def handle_info(:publish, lsp) do
GenLSP.log(lsp, "[NextLS] Compiled!")

Expand Down Expand Up @@ -449,15 +441,6 @@ defmodule NextLS do
{:noreply, assign(lsp, refresh_refs: refs)}
end

def handle_info({:DOWN, ref, :process, _runtime, _reason}, lsp) do
name = Process.get(ref)
Process.delete(ref)

GenLSP.error(lsp, "[NextLS] The runtime for #{name} has crashed")

{:noreply, lsp}
end

def handle_info(message, lsp) do
GenLSP.log(lsp, "[NextLS] Unhandled message: #{inspect(message)}")
{:noreply, lsp}
Expand Down
9 changes: 0 additions & 9 deletions lib/next_ls/lsp_supervisor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,24 +51,15 @@ defmodule NextLS.LSPSupervisor do
raise OptionsError, invalid
end

# FIXME: this directory should be inside the workspace, which will is not determined until
# the LSP has begun initialization
# The symbol table may need to started dynamically, like the extensions and the runtimes
hidden_folder = Path.expand(".elixir-tools")
File.mkdir_p!(hidden_folder)
File.write!(Path.join(hidden_folder, ".gitignore"), "*\n")

children = [
{DynamicSupervisor, name: NextLS.DynamicSupervisor},
{Task.Supervisor, name: NextLS.TaskSupervisor},
{Task.Supervisor, name: :runtime_task_supervisor},
{GenLSP.Buffer, buffer_opts},
{NextLS.DiagnosticCache, name: :diagnostic_cache},
{NextLS.SymbolTable, name: :symbol_table, path: hidden_folder},
{Registry, name: NextLS.Registry, keys: :duplicate},
{NextLS,
cache: :diagnostic_cache,
symbol_table: :symbol_table,
task_supervisor: NextLS.TaskSupervisor,
runtime_task_supervisor: :runtime_task_supervisor,
dynamic_supervisor: NextLS.DynamicSupervisor,
Expand Down
23 changes: 22 additions & 1 deletion lib/next_ls/runtime.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ defmodule NextLS.Runtime do

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

pid =
cond do
is_pid(parent) -> parent
is_atom(parent) -> Process.whereis(parent)
end

parent =
pid
|> :erlang.term_to_binary()
|> Base.encode64()
|> String.to_charlist()

port =
Port.open(
{:spawn_executable, @exe},
Expand All @@ -64,7 +76,7 @@ defmodule NextLS.Runtime do
cd: working_dir,
env: [
{~c"LSP", ~c"nextls"},
{~c"NEXTLS_PARENT_PID", parent |> :erlang.term_to_binary() |> Base.encode64() |> String.to_charlist()},
{~c"NEXTLS_PARENT_PID", parent},
{~c"MIX_ENV", ~c"dev"},
{~c"MIX_BUILD_ROOT", ~c".elixir-tools/_build"}
],
Expand All @@ -85,6 +97,15 @@ defmodule NextLS.Runtime do

me = self()

Task.Supervisor.async_nolink(task_supervisor, fn ->
ref = Process.monitor(me)

receive do
{:DOWN, ^ref, :process, ^me, _reason} ->
NextLS.Logger.error(logger, "[NextLS] The runtime for #{name} has crashed")
end
end)

Task.start_link(fn ->
with {:ok, host} <- :inet.gethostname(),
node <- :"#{sname}@#{host}",
Expand Down
25 changes: 25 additions & 0 deletions lib/next_ls/runtime/sidecar.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
defmodule NextLS.Runtime.Sidecar do
@moduledoc false
use GenServer

alias NextLS.SymbolTable

def start_link(args) do
GenServer.start_link(__MODULE__, Keyword.take(args, [:symbol_table]), Keyword.take(args, [:name]))
end

def init(args) do
symbol_table = Keyword.fetch!(args, :symbol_table)
{:ok, %{symbol_table: symbol_table}}
end

def handle_info({:tracer, payload}, state) do
SymbolTable.put_symbols(state.symbol_table, payload)
{:noreply, state}
end

def handle_info({{:tracer, :reference}, payload}, state) do
SymbolTable.put_reference(state.symbol_table, payload)
{:noreply, state}
end
end
29 changes: 29 additions & 0 deletions lib/next_ls/runtime/supervisor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
defmodule NextLS.Runtime.Supervisor do
@moduledoc false

use Supervisor

def start_link(init_arg) do
Supervisor.start_link(__MODULE__, init_arg)
end

@impl true
def init(init_arg) do
name = init_arg[:name]
registry = init_arg[:registry]
hidden_folder = init_arg[:path]
File.mkdir_p!(hidden_folder)
File.write!(Path.join(hidden_folder, ".gitignore"), "*\n")

symbol_table_name = :"symbol-table-#{name}"
sidecar_name = :"sidecar-#{name}"

children = [
{NextLS.SymbolTable, workspace: name, path: hidden_folder, registry: registry, name: symbol_table_name},
{NextLS.Runtime.Sidecar, name: sidecar_name, symbol_table: symbol_table_name},
{NextLS.Runtime, init_arg[:runtime] ++ [name: name, registry: registry, parent: sidecar_name]}
]

Supervisor.init(children, strategy: :one_for_one)
end
end
18 changes: 0 additions & 18 deletions lib/next_ls/runtime_supervisor.ex

This file was deleted.

Loading

0 comments on commit d9bacac

Please sign in to comment.