Skip to content

Commit

Permalink
feat: adding/removing workspace folders
Browse files Browse the repository at this point in the history
  • Loading branch information
mhanberg committed Jul 24, 2023
1 parent d9bacac commit bf755ea
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 43 deletions.
62 changes: 59 additions & 3 deletions lib/next_ls.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ defmodule NextLS do
alias GenLSP.Notifications.TextDocumentDidChange
alias GenLSP.Notifications.TextDocumentDidOpen
alias GenLSP.Notifications.TextDocumentDidSave
alias GenLSP.Notifications.WorkspaceDidChangeWorkspaceFolders
alias GenLSP.Requests.Initialize
alias GenLSP.Requests.Shutdown
alias GenLSP.Requests.TextDocumentDefinition
alias GenLSP.Requests.TextDocumentDocumentSymbol
alias GenLSP.Requests.TextDocumentFormatting
alias GenLSP.Requests.WorkspaceSymbol
alias GenLSP.Structures.DidChangeWorkspaceFoldersParams
alias GenLSP.Structures.DidOpenTextDocumentParams
alias GenLSP.Structures.InitializeParams
alias GenLSP.Structures.InitializeResult
Expand All @@ -28,6 +30,7 @@ defmodule NextLS do
alias GenLSP.Structures.TextDocumentItem
alias GenLSP.Structures.TextDocumentSyncOptions
alias GenLSP.Structures.TextEdit
alias GenLSP.Structures.WorkspaceFoldersChangeEvent
alias NextLS.Definition
alias NextLS.DiagnosticCache
alias NextLS.Progress
Expand Down Expand Up @@ -288,7 +291,7 @@ defmodule NextLS do
parent = self()
working_dir = URI.parse(uri).path

{:ok, runtime} =
{:ok, _} =
DynamicSupervisor.start_child(
lsp.assigns.dynamic_supervisor,
{NextLS.Runtime.Supervisor,
Expand All @@ -312,8 +315,6 @@ defmodule NextLS do
logger: lsp.assigns.logger
]}
)

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

{:noreply, lsp}
Expand Down Expand Up @@ -379,6 +380,61 @@ defmodule NextLS do
{:noreply, put_in(lsp.assigns.documents[uri], String.split(text, "\n"))}
end

def handle_notification(
%WorkspaceDidChangeWorkspaceFolders{
params: %DidChangeWorkspaceFoldersParams{event: %WorkspaceFoldersChangeEvent{added: added, removed: removed}}
},
lsp
) do
dispatch(lsp.assigns.registry, :runtime_supervisors, fn entries ->
names = Enum.map(entries, fn {_, %{name: name}} -> name end)

for %{name: name, uri: uri} <- added, name not in names do
GenLSP.log(lsp, "[NextLS] Adding workspace folder #{name}")
token = token()
Progress.start(lsp, token, "Initializing NextLS runtime for folder #{name}...")
parent = self()
working_dir = URI.parse(uri).path

# TODO: probably extract this to the Runtime module
{:ok, _} =
DynamicSupervisor.start_child(
lsp.assigns.dynamic_supervisor,
{NextLS.Runtime.Supervisor,
path: Path.join(working_dir, ".elixir-tools"),
name: name,
registry: lsp.assigns.registry,
runtime: [
task_supervisor: lsp.assigns.runtime_task_supervisor,
working_dir: working_dir,
uri: uri,
on_initialized: fn status ->
if status == :ready do
Progress.stop(lsp, token, "NextLS runtime for folder #{name} has initialized!")
GenLSP.log(lsp, "[NextLS] Runtime for folder #{name} is ready...")
send(parent, {:runtime_ready, name, self()})
else
Progress.stop(lsp, token)
GenLSP.error(lsp, "[NextLS] Runtime for folder #{name} failed to initialize")
end
end,
logger: lsp.assigns.logger
]}
)
end

names = Enum.map(removed, & &1.name)

for {pid, %{name: name}} <- entries, name in names do
GenLSP.log(lsp, "[NextLS] Removing workspace folder #{name}")
# TODO: probably extract this to the Runtime module
DynamicSupervisor.terminate_child(lsp.assigns.dynamic_supervisor, pid)
end
end)

{:noreply, lsp}
end

def handle_notification(%Exit{}, lsp) do
System.halt(lsp.assigns.exit_code)

Expand Down
10 changes: 8 additions & 2 deletions lib/next_ls/runtime.ex
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,14 @@ defmodule NextLS.Runtime do
ref = Process.monitor(me)

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

reason ->
NextLS.Logger.error(logger, "The runtime for #{name} has crashed with reason: #{reason}.")
end
end
end)

Expand Down
2 changes: 2 additions & 0 deletions lib/next_ls/runtime/supervisor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ defmodule NextLS.Runtime.Supervisor do
symbol_table_name = :"symbol-table-#{name}"
sidecar_name = :"sidecar-#{name}"

Registry.register(registry, :runtime_supervisors, %{name: 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},
Expand Down
5 changes: 4 additions & 1 deletion test/next_ls/symbol_table_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ defmodule NextLS.SymbolTableTest do
start_supervised!({Registry, [keys: :duplicate, name: Registry.SymbolTableTest.Registry]})
# this fails with `{:error, incompatible_arguments}` on CI a lot, and I have no idea why
pid =
try_start_supervised({SymbolTable, [path: dir, workspace: cxt.test, registry: Registry.SymbolTableTest.Registry]}, 10)
try_start_supervised(
{SymbolTable, [path: dir, workspace: cxt.test, registry: Registry.SymbolTableTest.Registry]},
10
)

Process.link(pid)
[pid: pid, dir: dir]
Expand Down
Loading

0 comments on commit bf755ea

Please sign in to comment.