diff --git a/lib/next_ls.ex b/lib/next_ls.ex index 82a2d985..2f6ee77a 100644 --- a/lib/next_ls.ex +++ b/lib/next_ls.ex @@ -21,7 +21,6 @@ defmodule NextLS do Keyword.split(args, [ :cache, :auto_update, - :task_supervisor, :runtime_task_supervisor, :dynamic_supervisor, :extensions, @@ -36,7 +35,6 @@ defmodule NextLS do @impl true def init(lsp, args) do - task_supervisor = Keyword.fetch!(args, :task_supervisor) runtime_task_supervisor = Keyword.fetch!(args, :runtime_task_supervisor) dynamic_supervisor = Keyword.fetch!(args, :dynamic_supervisor) bundle_base = Keyword.get(args, :bundle_base, Path.expand("~/.cache/elixir-tools/nextls")) @@ -72,7 +70,6 @@ defmodule NextLS do refresh_refs: %{}, cache: cache, logger: logger, - task_supervisor: task_supervisor, runtime_task_supervisor: runtime_task_supervisor, dynamic_supervisor: dynamic_supervisor, registry: registry, @@ -105,12 +102,12 @@ defmodule NextLS do # if we are on 1.17, we will not bundle {mix_home, mix_archives} = - if lsp.assigns.is_1_17 do + if assigns(lsp).is_1_17 do {nil, nil} else # if we are not on 1.17, we bundle if completions are enabled if init_opts.experimental.completions.enable do - {BundledElixir.mix_home(lsp.assigns.bundle_base), BundledElixir.mix_archives(lsp.assigns.bundle_base)} + {BundledElixir.mix_home(assigns(lsp).bundle_base), BundledElixir.mix_archives(assigns(lsp).bundle_base)} else {nil, nil} end @@ -180,7 +177,7 @@ defmodule NextLS do data = %NextLS.CodeActionable.Data{ diagnostic: diagnostic, uri: uri, - document: lsp.assigns.documents[uri] + document: assigns(lsp).documents[uri] }, namespace = diagnostic.data["namespace"], action <- NextLS.CodeActionable.from(namespace, data) do @@ -192,7 +189,7 @@ defmodule NextLS do def handle_request(%TextDocumentDefinition{params: %{text_document: %{uri: uri}, position: position}}, lsp) do result = - dispatch(lsp.assigns.registry, :databases, fn entries -> + dispatch(assigns(lsp).registry, :databases, fn entries -> for {pid, _} <- entries do case Definition.fetch( URI.parse(uri).path, @@ -246,9 +243,9 @@ defmodule NextLS do def handle_request(%TextDocumentDocumentSymbol{params: %{text_document: %{uri: uri}}}, lsp) do symbols = - if Path.extname(uri) in [".ex", ".exs"] && lsp.assigns.documents[uri] do + if Path.extname(uri) in [".ex", ".exs"] && assigns(lsp).documents[uri] do try do - lsp.assigns.documents[uri] + assigns(lsp).documents[uri] |> Enum.join("\n") |> NextLS.DocumentSymbol.fetch() rescue @@ -269,7 +266,7 @@ defmodule NextLS do col = position.character + 1 locations = - dispatch(lsp.assigns.registry, :databases, fn databases -> + dispatch(assigns(lsp).registry, :databases, fn databases -> Enum.flat_map(databases, fn {database, _} -> references = case symbol_info(file, line, col, database) do @@ -356,7 +353,7 @@ defmodule NextLS do """ locations = - dispatch(lsp.assigns.registry, :databases, fn databases -> + dispatch(assigns(lsp).registry, :databases, fn databases -> Enum.flat_map(databases, fn {database, _} -> DB.query(database, reference_query, args: [file, line, col], select: select) end) @@ -373,7 +370,7 @@ defmodule NextLS do end result = - dispatch(lsp.assigns.registry, :runtimes, fn entries -> + dispatch(assigns(lsp).registry, :runtimes, fn entries -> [result] = for {runtime, %{uri: wuri}} <- entries, String.starts_with?(uri, wuri) do Runtime.call(runtime, {Code, :fetch_docs, [mod]}) @@ -453,7 +450,7 @@ defmodule NextLS do end symbols = - dispatch(lsp.assigns.registry, :databases, fn entries -> + dispatch(assigns(lsp).registry, :databases, fn entries -> filtered_symbols = for {pid, _} <- entries, symbol <- symbols.(pid), @@ -491,74 +488,85 @@ defmodule NextLS do end def handle_request(%TextDocumentFormatting{params: %{text_document: %{uri: uri}}}, lsp) do - document = lsp.assigns.documents[uri] + # NextLS.Logger.log(assigns(lsp).logger, "formatting start: #{System.system_time()}") + document = assigns(lsp).documents[uri] if is_list(document) do - dispatch_to_workspace(lsp.assigns.registry, uri, fn runtime, %{uri: wuri} -> - with {:ok, {formatter, _}} <- - Runtime.call( - runtime, - {:_next_ls_private_formatter, :formatter_for_file, [URI.parse(uri).path]} - ), - {: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) + result = + dispatch_to_workspace(assigns(lsp).registry, uri, fn runtime, %{uri: wuri} -> + # NextLS.Logger.log(assigns(lsp).logger, "dispatched to workspace: #{System.system_time()}") + + with {:ok, {formatter, _}} <- + Runtime.call( + runtime, + {:_next_ls_private_formatter, :formatter_for_file, [URI.parse(uri).path]} + ), + # NextLS.Logger.log(assigns(lsp).logger, "got formatter: #{System.system_time()}"), + {:ok, response} when is_binary(response) or is_list(response) <- + Runtime.call( + runtime, + {Kernel, :apply, [formatter, [Enum.join(document, "\n")]]} + ) do + # NextLS.Logger.log(assigns(lsp).logger, "finished formatting: #{System.system_time()}") + + {: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, %WindowShowMessage{ - params: %ShowMessageParams{ - type: MessageType.info(), - message: "The NextLS runtime is still initializing!" - } - }) + ], lsp} + else + {:error, :not_ready} -> + GenLSP.notify(lsp, %WindowShowMessage{ + params: %ShowMessageParams{ + type: MessageType.info(), + message: "The NextLS runtime is still initializing!" + } + }) - {:reply, nil, lsp} + {:reply, nil, lsp} - e -> - case e do - {:ok, {:badrpc, {:EXIT, {%{description: description, file: file}, _stacktrace}}}} -> - file = Path.relative_to(file, URI.parse(wuri).path) - - NextLS.Logger.show_message( - lsp.assigns.logger, - :error, - "Failed to format #{file}: #{description}" - ) + e -> + case e do + {:ok, {:badrpc, {:EXIT, {%{description: description, file: file}, _stacktrace}}}} -> + file = Path.relative_to(file, URI.parse(wuri).path) - NextLS.Logger.warning( - lsp.assigns.logger, - "Failed to format #{file}: #{description}" - ) + NextLS.Logger.show_message( + assigns(lsp).logger, + :error, + "Failed to format #{file}: #{description}" + ) - _ -> - abs_file = URI.parse(uri).path - root_dir = URI.parse(wuri).path - file = Path.relative_to(abs_file, root_dir) - NextLS.Logger.show_message(lsp.assigns.logger, :error, "Failed to format #{file}") - NextLS.Logger.warning(lsp.assigns.logger, "Failed to format #{file}") - end + NextLS.Logger.warning( + assigns(lsp).logger, + "Failed to format #{file}: #{description}" + ) - {:reply, nil, lsp} - end - end) + _ -> + abs_file = URI.parse(uri).path + root_dir = URI.parse(wuri).path + file = Path.relative_to(abs_file, root_dir) + NextLS.Logger.show_message(assigns(lsp).logger, :error, "Failed to format #{file}") + NextLS.Logger.warning(assigns(lsp).logger, "Failed to format #{file}") + end + + {:reply, nil, lsp} + end + end) + + with %GenLSP.ErrorResponse{} <- result do + {:reply, result, lsp} + end else NextLS.Logger.warning( - lsp.assigns.logger, + assigns(lsp).logger, "The file #{uri} was not found in the server's process state. Something must have gone wrong when opening, changing, or saving the file." ) @@ -582,7 +590,7 @@ defmodule NextLS do end result = - dispatch_to_workspace(lsp.assigns.registry, uri, fn runtime, _entry -> + dispatch_to_workspace(assigns(lsp).registry, uri, fn runtime, _entry -> Runtime.call(runtime, {Code, :fetch_docs, [module]}) end) @@ -609,7 +617,7 @@ defmodule NextLS do end def handle_request(%TextDocumentCompletion{params: %{text_document: %{uri: uri}, position: position}}, lsp) do - document = lsp.assigns.documents[uri] + document = assigns(lsp).documents[uri] document_slice = document @@ -628,89 +636,89 @@ defmodule NextLS do {:error, with_cursor, _} -> with_cursor end - {root_path, entries} = - dispatch_to_workspace(lsp.assigns.registry, uri, fn runtime, %{uri: wuri} -> - {:ok, {_, _, _, macro_env}} = - Runtime.expand(runtime, with_cursor, Path.basename(uri)) + results = + with {root_path, entries} <- + dispatch_to_workspace(assigns(lsp).registry, uri, fn runtime, %{uri: wuri} -> + {:ok, {_, _, _, macro_env}} = + Runtime.expand(runtime, with_cursor, Path.basename(uri)) - doc = - document_slice - |> String.to_charlist() - |> Enum.reverse() + doc = + document_slice + |> String.to_charlist() + |> Enum.reverse() - result = NextLS.Autocomplete.expand(doc, runtime, macro_env) + result = NextLS.Autocomplete.expand(doc, runtime, macro_env) - case result do - {:yes, entries} -> {wuri, entries} - _ -> {wuri, []} - end - end) - - results = - entries - |> Enum.reduce([], fn %{name: name, kind: kind} = symbol, results -> - {label, kind, docs} = - case kind do - :struct -> - {name, CompletionItemKind.struct(), ""} + case result do + {:yes, entries} -> {wuri, entries} + _ -> {wuri, []} + end + end) do + entries + |> Enum.reduce([], fn %{name: name, kind: kind} = symbol, results -> + {label, kind, docs} = + case kind do + :struct -> + {name, CompletionItemKind.struct(), ""} - :function -> - {"#{name}/#{symbol.arity}", CompletionItemKind.function(), symbol[:docs] || ""} + :function -> + {"#{name}/#{symbol.arity}", CompletionItemKind.function(), symbol[:docs] || ""} - :module -> - {name, CompletionItemKind.module(), symbol[:docs] || ""} + :module -> + {name, CompletionItemKind.module(), symbol[:docs] || ""} - :variable -> - {to_string(name), CompletionItemKind.variable(), ""} + :variable -> + {to_string(name), CompletionItemKind.variable(), ""} - :dir -> - {name, CompletionItemKind.folder(), ""} + :dir -> + {name, CompletionItemKind.folder(), ""} - :file -> - {name, CompletionItemKind.file(), ""} + :file -> + {name, CompletionItemKind.file(), ""} - :reserved -> - {name, CompletionItemKind.keyword(), ""} + :reserved -> + {name, CompletionItemKind.keyword(), ""} - :keyword -> - {name, CompletionItemKind.field(), ""} + :keyword -> + {name, CompletionItemKind.field(), ""} - :attribute -> - {name, CompletionItemKind.property(), ""} + :attribute -> + {name, CompletionItemKind.property(), ""} - :sigil -> - {name, CompletionItemKind.function(), ""} + :sigil -> + {name, CompletionItemKind.function(), ""} - _ -> - {name, CompletionItemKind.text(), ""} - end + _ -> + {name, CompletionItemKind.text(), ""} + end - completion_item = - %GenLSP.Structures.CompletionItem{ - label: label, - kind: kind, - insert_text: to_string(name), - documentation: docs, - data: - if symbol[:data] do - %{uri: uri, data: symbol[:data] |> :erlang.term_to_binary() |> Base.encode64()} - end - } + completion_item = + %GenLSP.Structures.CompletionItem{ + label: label, + kind: kind, + insert_text: to_string(name), + documentation: docs, + data: + if symbol[:data] do + %{uri: uri, data: symbol[:data] |> :erlang.term_to_binary() |> Base.encode64()} + end + } - root_path = root_path |> URI.parse() |> Map.get(:path) + root_path = root_path |> URI.parse() |> Map.get(:path) - case NextLS.Snippet.get(label, nil, uri: Path.relative_to(URI.parse(uri).path, root_path)) do - nil -> [completion_item | results] - %{} = snippet -> [Map.merge(completion_item, snippet) | results] - end - end) - |> Enum.reverse() + case NextLS.Snippet.get(label, nil, uri: Path.relative_to(URI.parse(uri).path, root_path)) do + nil -> [completion_item | results] + %{} = snippet -> [Map.merge(completion_item, snippet) | results] + end + end) + |> Enum.reverse() + end {:reply, results, lsp} rescue e -> NextLS.Logger.warning( - lsp.assigns.logger, + assigns(lsp).logger, "Failed to run completion request: #{Exception.format(:error, e, __STACKTRACE__)}" ) @@ -730,7 +738,7 @@ defmodule NextLS do uri = arguments["uri"] position = arguments["position"] - text = lsp.assigns.documents[uri] + text = assigns(lsp).documents[uri] Pipe.from(%{ uri: uri, @@ -743,7 +751,7 @@ defmodule NextLS do uri = arguments["uri"] position = arguments["position"] - text = lsp.assigns.documents[uri] + text = assigns(lsp).documents[uri] Pipe.to(%{ uri: uri, @@ -756,7 +764,7 @@ defmodule NextLS do uri = arguments["uri"] position = arguments["position"] - text = lsp.assigns.documents[uri] + text = assigns(lsp).documents[uri] NextLS.Commands.Alias.run(%{ uri: uri, @@ -766,7 +774,7 @@ defmodule NextLS do _ -> NextLS.Logger.show_message( - lsp.assigns.logger, + assigns(lsp).logger, :warning, "[Next LS] Unknown workspace command: #{command}" ) @@ -789,12 +797,12 @@ defmodule NextLS do rescue e -> NextLS.Logger.show_message( - lsp.assigns.logger, + assigns(lsp).logger, :error, "[Next LS] #{command} has failed, see the logs for more details" ) - NextLS.Logger.error(lsp.assigns.logger, Exception.format(:error, e, __STACKTRACE__)) + NextLS.Logger.error(assigns(lsp).logger, Exception.format(:error, e, __STACKTRACE__)) {:reply, nil, lsp} end @@ -804,7 +812,7 @@ defmodule NextLS do end def handle_request(%{method: method}, lsp) do - NextLS.Logger.warning(lsp.assigns.logger, "Method Not Found: #{method}") + NextLS.Logger.warning(assigns(lsp).logger, "Method Not Found: #{method}") {:reply, %ErrorResponse{ @@ -815,32 +823,32 @@ defmodule NextLS do @impl true def handle_notification(%Initialized{}, lsp) do - NextLS.Logger.log(lsp.assigns.logger, "NextLS v#{version()} has initialized!") + NextLS.Logger.log(assigns(lsp).logger, "NextLS v#{version()} has initialized!") NextLS.Logger.log( - lsp.assigns.logger, + assigns(lsp).logger, "Log file located at #{Path.join(File.cwd!(), ".elixir-tools/next-ls.log")}" ) - with opts when is_list(opts) <- lsp.assigns.auto_update do + with opts when is_list(opts) <- assigns(lsp).auto_update do {:ok, _} = DynamicSupervisor.start_child( - lsp.assigns.dynamic_supervisor, - {NextLS.Updater, Keyword.put(opts, :logger, lsp.assigns.logger)} + assigns(lsp).dynamic_supervisor, + {NextLS.Updater, Keyword.put(opts, :logger, assigns(lsp).logger)} ) end - for {id, extension} <- lsp.assigns.extensions do + for {id, extension} <- assigns(lsp).extensions do child = DynamicSupervisor.start_child( - lsp.assigns.dynamic_supervisor, + assigns(lsp).dynamic_supervisor, {extension, - settings: Map.fetch!(lsp.assigns.init_opts.extensions, id), - logger: lsp.assigns.logger, - cache: lsp.assigns.cache, - registry: lsp.assigns.registry, - publisher: self(), - task_supervisor: lsp.assigns.runtime_task_supervisor} + settings: Map.fetch!(assigns(lsp).init_opts.extensions, id), + logger: assigns(lsp).logger, + cache: assigns(lsp).cache, + registry: assigns(lsp).registry, + publisher: lsp.pid, + task_supervisor: assigns(lsp).runtime_task_supervisor} ) case child do @@ -850,7 +858,7 @@ defmodule NextLS do end with %{dynamic_registration: true} <- - lsp.assigns.client_capabilities.workspace.did_change_watched_files do + assigns(lsp).client_capabilities.workspace.did_change_watched_files do nil = GenLSP.request(lsp, %GenLSP.Requests.ClientRegisterCapability{ id: System.unique_integer([:positive]), @@ -871,58 +879,58 @@ defmodule NextLS do }) end - BundledElixir.install(lsp.assigns.bundle_base, lsp.assigns.logger) - NextLS.Logger.log(lsp.assigns.logger, "Booting runtimes...") + BundledElixir.install(assigns(lsp).bundle_base, assigns(lsp).logger) + NextLS.Logger.log(assigns(lsp).logger, "Booting runtimes...") - parent = self() + parent = lsp.pid elixir_bin_path = cond do - lsp.assigns.is_1_17 -> + assigns(lsp).is_1_17 -> "elixir" |> System.find_executable() |> Path.dirname() - lsp.assigns.init_opts.elixir_bin_path != nil -> - lsp.assigns.init_opts.elixir_bin_path + assigns(lsp).init_opts.elixir_bin_path != nil -> + assigns(lsp).init_opts.elixir_bin_path - lsp.assigns.init_opts.experimental.completions.enable -> - BundledElixir.binpath(lsp.assigns.bundle_base) + assigns(lsp).init_opts.experimental.completions.enable -> + BundledElixir.binpath(assigns(lsp).bundle_base) true -> "elixir" |> System.find_executable() |> Path.dirname() end - for %{uri: uri, name: name} <- lsp.assigns.workspace_folders do + for %{uri: uri, name: name} <- assigns(lsp).workspace_folders do token = Progress.token() Progress.start(lsp, token, "Initializing NextLS runtime for folder #{name}...") working_dir = URI.parse(uri).path {:ok, _} = DynamicSupervisor.start_child( - lsp.assigns.dynamic_supervisor, + assigns(lsp).dynamic_supervisor, {NextLS.Runtime.Supervisor, path: Path.join(working_dir, ".elixir-tools"), name: name, lsp: lsp, lsp_pid: parent, - registry: lsp.assigns.registry, - logger: lsp.assigns.logger, + registry: assigns(lsp).registry, + logger: assigns(lsp).logger, runtime: [ - task_supervisor: lsp.assigns.runtime_task_supervisor, + task_supervisor: assigns(lsp).runtime_task_supervisor, working_dir: working_dir, uri: uri, - mix_env: lsp.assigns.init_opts.mix_env, - mix_target: lsp.assigns.init_opts.mix_target, - mix_home: lsp.assigns.mix_home, - mix_archives: lsp.assigns.mix_archives, + mix_env: assigns(lsp).init_opts.mix_env, + mix_target: assigns(lsp).init_opts.mix_target, + mix_home: assigns(lsp).mix_home, + mix_archives: assigns(lsp).mix_archives, elixir_bin_path: elixir_bin_path, on_initialized: fn status -> if status == :ready do Progress.stop(lsp, token, "NextLS runtime for folder #{name} has initialized!") - NextLS.Logger.log(lsp.assigns.logger, "Runtime for folder #{name} is ready...") + NextLS.Logger.log(assigns(lsp).logger, "Runtime for folder #{name} is ready...") msg = {:runtime_ready, name, self()} - dispatch(lsp.assigns.registry, :extensions, fn entries -> + dispatch(assigns(lsp).registry, :extensions, fn entries -> for {pid, _} <- entries, do: send(pid, msg) end) @@ -933,12 +941,12 @@ defmodule NextLS do send(parent, {:runtime_failed, name, status}) NextLS.Logger.error( - lsp.assigns.logger, + assigns(lsp).logger, "Runtime for folder #{name} failed to initialize" ) end end, - logger: lsp.assigns.logger + logger: assigns(lsp).logger ]} ) end @@ -953,17 +961,13 @@ defmodule NextLS do }, lsp ) do - refresh_refs = - if lsp.assigns.ready do - for task <- Task.Supervisor.children(lsp.assigns.task_supervisor) do - Process.exit(task, :kill) - end + # NextLS.Logger.log(assigns(lsp).logger, "did save pid: " <> inspect(self())) + refresh_refs = + if assigns(lsp).ready do # dispatching to all workspaces - dispatch(lsp.assigns.registry, :runtimes, fn entries -> - for {pid, %{name: name, uri: wuri}} <- entries, - String.starts_with?(uri, wuri), - into: %{} do + dispatch(assigns(lsp).registry, :runtimes, fn entries -> + for {pid, %{name: name, uri: wuri}} <- entries, String.starts_with?(uri, wuri), into: %{} do token = Progress.token() Progress.start(lsp, token, "Compiling #{name}...") @@ -977,10 +981,8 @@ defmodule NextLS do Map.new() end - lsp = - lsp - |> then(&put_in(&1.assigns.documents[uri], String.split(text, "\n"))) - |> then(&update_in(&1.assigns.refresh_refs, fn r -> Map.merge(r, refresh_refs) end)) + insert_document(lsp, uri, text) + assign(lsp, fn assigns -> update_in(assigns.refresh_refs, fn r -> Map.merge(r, refresh_refs) end) end) {:noreply, lsp} end @@ -989,13 +991,7 @@ defmodule NextLS do %TextDocumentDidChange{params: %{text_document: %{uri: uri}, content_changes: [%{text: text}]}}, lsp ) do - if lsp.assigns.ready do - for task <- Task.Supervisor.children(lsp.assigns.task_supervisor) do - Process.exit(task, :kill) - end - end - - lsp = put_in(lsp.assigns.documents[uri], String.split(text, "\n")) + insert_document(lsp, uri, text) {:noreply, lsp} end @@ -1005,7 +1001,8 @@ defmodule NextLS do }, lsp ) do - {:noreply, put_in(lsp.assigns.documents[uri], String.split(text, "\n"))} + insert_document(lsp, uri, text) + {:noreply, lsp} end def handle_notification( @@ -1014,40 +1011,40 @@ defmodule NextLS do }, lsp ) do - NextLS.Registry.dispatch(lsp.assigns.registry, :runtime_supervisors, fn entries -> + NextLS.Registry.dispatch(assigns(lsp).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 - NextLS.Logger.log(lsp.assigns.logger, "Adding workspace folder #{name}") + NextLS.Logger.log(assigns(lsp).logger, "Adding workspace folder #{name}") token = Progress.token() Progress.start(lsp, token, "Initializing NextLS runtime for folder #{name}...") - parent = self() + parent = lsp.pid working_dir = URI.parse(uri).path {:ok, _} = - NextLS.Runtime.boot(lsp.assigns.dynamic_supervisor, + NextLS.Runtime.boot(assigns(lsp).dynamic_supervisor, path: Path.join(working_dir, ".elixir-tools"), name: name, lsp: lsp, lsp_pid: parent, - registry: lsp.assigns.registry, + registry: assigns(lsp).registry, runtime: [ - task_supervisor: lsp.assigns.runtime_task_supervisor, + task_supervisor: assigns(lsp).runtime_task_supervisor, working_dir: working_dir, - elixir_bin_path: lsp.assigns.elixir_bin_path, + elixir_bin_path: assigns(lsp).elixir_bin_path, uri: uri, - mix_env: lsp.assigns.init_opts.mix_env, - mix_target: lsp.assigns.init_opts.mix_target, - mix_home: lsp.assigns.mix_home, - mix_archives: lsp.assigns.mix_archives, + mix_env: assigns(lsp).init_opts.mix_env, + mix_target: assigns(lsp).init_opts.mix_target, + mix_home: assigns(lsp).mix_home, + mix_archives: assigns(lsp).mix_archives, on_initialized: fn status -> if status == :ready do Progress.stop(lsp, token, "NextLS runtime for folder #{name} has initialized!") - NextLS.Logger.log(lsp.assigns.logger, "Runtime for folder #{name} is ready...") + NextLS.Logger.log(assigns(lsp).logger, "Runtime for folder #{name} is ready...") msg = {:runtime_ready, name, self()} - dispatch(lsp.assigns.registry, :extensions, fn entries -> + dispatch(assigns(lsp).registry, :extensions, fn entries -> for {pid, _} <- entries, do: send(pid, msg) end) @@ -1058,12 +1055,12 @@ defmodule NextLS do send(parent, {:runtime_failed, name, status}) NextLS.Logger.error( - lsp.assigns.logger, + assigns(lsp).logger, "Runtime for folder #{name} failed to initialize" ) end end, - logger: lsp.assigns.logger + logger: assigns(lsp).logger ] ) end @@ -1071,8 +1068,8 @@ defmodule NextLS do names = Enum.map(removed, & &1.name) for {pid, %{name: name}} <- entries, name in names do - NextLS.Logger.log(lsp.assigns.logger, "Removing workspace folder #{name}") - NextLS.Runtime.stop(lsp.assigns.dynamic_supervisor, pid) + NextLS.Logger.log(assigns(lsp).logger, "Removing workspace folder #{name}") + NextLS.Runtime.stop(assigns(lsp).dynamic_supervisor, pid) end end) @@ -1088,13 +1085,13 @@ defmodule NextLS do cond do type == FileChangeType.created() -> case File.read(file) do - {:ok, text} -> put_in(lsp.assigns.documents[uri], String.split(text, "\n")) + {:ok, text} -> insert_document(lsp, uri, text) _ -> lsp end type == FileChangeType.changed() -> case File.read(file) do - {:ok, text} -> put_in(lsp.assigns.documents[uri], String.split(text, "\n")) + {:ok, text} -> insert_document(lsp, uri, text) _ -> lsp end @@ -1102,7 +1099,7 @@ defmodule NextLS do if File.exists?(file) do lsp else - dispatch(lsp.assigns.registry, :databases, fn entries -> + dispatch(assigns(lsp).registry, :databases, fn entries -> for {pid, _} <- entries do NextLS.DB.query( pid, @@ -1124,7 +1121,7 @@ defmodule NextLS do end end) - update_in(lsp.assigns.documents, &Map.delete(&1, uri)) + assign(lsp, fn assigns -> update_in(assigns.documents, &Map.delete(&1, uri)) end) end end end @@ -1133,7 +1130,7 @@ defmodule NextLS do end def handle_notification(%Exit{}, lsp) do - System.halt(lsp.assigns.exit_code) + System.halt(assigns(lsp).exit_code) {:noreply, lsp} end @@ -1146,22 +1143,22 @@ defmodule NextLS do end def handle_info({:compiler_result, caller_ref, name, result} = _msg, lsp) do - {{token, msg}, refs} = Map.pop(lsp.assigns.refresh_refs, caller_ref) + {{token, msg}, refs} = Map.pop(assigns(lsp).refresh_refs, caller_ref) case result do {_, diagnostics} when is_list(diagnostics) -> - Registry.dispatch(lsp.assigns.registry, :extensions, fn entries -> + Registry.dispatch(assigns(lsp).registry, :extensions, fn entries -> for {pid, _} <- entries, do: send(pid, {:compiler, diagnostics}) end) - NextLS.Logger.info(lsp.assigns.logger, "Compiled #{name}!") + NextLS.Logger.info(assigns(lsp).logger, "Compiled #{name}!") {:error, %Mix.Error{message: "Can't continue due to errors on dependencies"}} -> - send(self(), {:runtime_failed, name, {:error, :deps}}) + send(lsp.pid, {:runtime_failed, name, {:error, :deps}}) unknown -> NextLS.Logger.warning( - lsp.assigns.logger, + assigns(lsp).logger, "Unexpected compiler response: #{inspect(unknown)}" ) end @@ -1172,7 +1169,7 @@ defmodule NextLS do end def handle_info({:compiler_canceled, caller_ref}, lsp) do - {{token, msg}, refs} = Map.pop(lsp.assigns.refresh_refs, caller_ref) + {{token, msg}, refs} = Map.pop(assigns(lsp).refresh_refs, caller_ref) Progress.stop(lsp, token, msg) @@ -1182,7 +1179,7 @@ defmodule NextLS do def handle_info(:publish, lsp) do Task.start(fn -> all = - for {_namespace, cache} <- DiagnosticCache.get(lsp.assigns.cache), + for {_namespace, cache} <- DiagnosticCache.get(assigns(lsp).cache), {file, diagnostics} <- cache, reduce: %{} do d -> Map.update(d, file, diagnostics, fn value -> value ++ diagnostics end) @@ -1202,7 +1199,7 @@ defmodule NextLS do end def handle_info({:runtime_ready, name, runtime_pid}, lsp) do - case NextLS.Registry.dispatch(lsp.assigns.registry, :databases, fn entries -> + case NextLS.Registry.dispatch(assigns(lsp).registry, :databases, fn entries -> Enum.find(entries, fn {_, %{runtime: runtime}} -> runtime == name end) end) do {_, %{mode: mode}} -> @@ -1212,7 +1209,7 @@ defmodule NextLS do ref = make_ref() Runtime.compile(runtime_pid, caller_ref: ref, force: mode == :reindex) - refresh_refs = Map.put(lsp.assigns.refresh_refs, ref, {token, "Compiled #{name}!"}) + refresh_refs = Map.put(assigns(lsp).refresh_refs, ref, {token, "Compiled #{name}!"}) {:noreply, assign(lsp, ready: true, refresh_refs: refresh_refs)} @@ -1223,13 +1220,13 @@ defmodule NextLS do def handle_info({:runtime_failed, name, status}, lsp) do {pid, %{init_arg: init_arg}} = - NextLS.Registry.dispatch(lsp.assigns.registry, :runtime_supervisors, fn entries -> + NextLS.Registry.dispatch(assigns(lsp).registry, :runtime_supervisors, fn entries -> Enum.find(entries, fn {_pid, %{name: n}} -> n == name end) end) - :ok = DynamicSupervisor.terminate_child(lsp.assigns.dynamic_supervisor, pid) + :ok = DynamicSupervisor.terminate_child(assigns(lsp).dynamic_supervisor, pid) - if status == {:error, :deps} && lsp.assigns.client_capabilities.window.show_message do + if status == {:error, :deps} && assigns(lsp).client_capabilities.window.show_message do resp = GenLSP.request( lsp, @@ -1250,7 +1247,7 @@ defmodule NextLS do case resp do %MessageActionItem{title: "yes"} -> NextLS.Logger.info( - lsp.assigns.logger, + assigns(lsp).logger, "Running `mix deps.get` in directory #{init_arg[:runtime][:working_dir]}" ) @@ -1264,32 +1261,32 @@ defmodule NextLS do ) do {msg, 0} -> NextLS.Logger.info( - lsp.assigns.logger, + assigns(lsp).logger, "Restarting runtime #{name} for directory #{init_arg[:runtime][:working_dir]}" ) - NextLS.Logger.info(lsp.assigns.logger, msg) + NextLS.Logger.info(assigns(lsp).logger, msg) {:ok, _} = DynamicSupervisor.start_child( - lsp.assigns.dynamic_supervisor, + assigns(lsp).dynamic_supervisor, {NextLS.Runtime.Supervisor, init_arg} ) {msg, _} -> NextLS.Logger.warning( - lsp.assigns.logger, + assigns(lsp).logger, "Failed to run `mix deps.get` in directory #{init_arg[:runtime][:working_dir]} with message: #{msg}" ) end _ -> - NextLS.Logger.info(lsp.assigns.logger, "Not running `mix deps.get`") + NextLS.Logger.info(assigns(lsp).logger, "Not running `mix deps.get`") end else - unless lsp.assigns.client_capabilities.window.show_message do + unless assigns(lsp).client_capabilities.window.show_message do NextLS.Logger.info( - lsp.assigns.logger, + assigns(lsp).logger, "Client does not support window/showMessageRequest" ) end @@ -1298,20 +1295,25 @@ defmodule NextLS do {:noreply, lsp} end - def handle_info({ref, {:runtime_failed, _, _} = error}, %{assigns: %{refresh_refs: refs}} = lsp) - when is_map_key(refs, ref) do - Process.demonitor(ref, [:flush]) - {{token, msg}, refs} = Map.pop(refs, ref) + def handle_info({ref, {:runtime_failed, _, _} = error}, lsp) do + %{refresh_refs: refs} = assigns(lsp) - Progress.stop(lsp, token, msg) - send(self(), error) + if is_map_key(refs, ref) do + Process.demonitor(ref, [:flush]) + {{token, msg}, refs} = Map.pop(refs, ref) - {:noreply, assign(lsp, refresh_refs: refs)} + Progress.stop(lsp, token, msg) + send(lsp.pid, error) + + {:noreply, assign(lsp, refresh_refs: refs)} + else + {:noreply, lsp} + end end def handle_info(message, lsp) do - NextLS.Logger.log(lsp.assigns.logger, "Unhandled message: #{inspect(message)}") - NextLS.Logger.log(lsp.assigns.logger, "process assigns=#{inspect(lsp.assigns)}") + NextLS.Logger.log(assigns(lsp).logger, "Unhandled message: #{inspect(message)}") + NextLS.Logger.log(assigns(lsp).logger, "process assigns=#{inspect(assigns(lsp))}") {:noreply, lsp} end @@ -1345,12 +1347,13 @@ defmodule NextLS do {^ref, result} -> result after 1000 -> - :timeout + %GenLSP.ErrorResponse{code: GenLSP.Enumerations.ErrorCodes.internal_error(), message: "Timeout"} end end defp dispatch_to_workspace(registry, uri, callback) do ref = make_ref() + me = self() Registry.dispatch(registry, :runtimes, fn entries -> @@ -1366,7 +1369,7 @@ defmodule NextLS do {^ref, result} -> result after 1000 -> - :timeout + %GenLSP.ErrorResponse{code: GenLSP.Enumerations.ErrorCodes.internal_error(), message: "Timeout"} end end @@ -1519,6 +1522,10 @@ defmodule NextLS do # penalty for unmatched letter defp calc_unmatched_penalty(score, _traits), do: score - 1 + defp insert_document(lsp, uri, text) do + assign(lsp, fn assigns -> put_in(assigns.documents[uri], String.split(text, "\n")) end) + end + defmodule InitOpts.Experimental do @moduledoc false defstruct completions: %{enable: false} diff --git a/lib/next_ls/commands/alias.ex b/lib/next_ls/commands/alias.ex index 4a66a454..20a71062 100644 --- a/lib/next_ls/commands/alias.ex +++ b/lib/next_ls/commands/alias.ex @@ -18,7 +18,7 @@ defmodule NextLS.Commands.Alias do defp opts do map(%{ - position: Position.schematic(), + position: Position.schema(), uri: str(), text: list(str()) }) diff --git a/lib/next_ls/commands/pipe.ex b/lib/next_ls/commands/pipe.ex index 47b6dbf6..3aa77c39 100644 --- a/lib/next_ls/commands/pipe.ex +++ b/lib/next_ls/commands/pipe.ex @@ -12,7 +12,7 @@ defmodule NextLS.Commands.Pipe do defp opts do map(%{ - position: Position.schematic(), + position: Position.schema(), uri: str(), text: list(str()) }) diff --git a/lib/next_ls/extensions/credo_extension.ex b/lib/next_ls/extensions/credo_extension.ex index e139768b..4cc96858 100644 --- a/lib/next_ls/extensions/credo_extension.ex +++ b/lib/next_ls/extensions/credo_extension.ex @@ -88,10 +88,26 @@ defmodule NextLS.CredoExtension do task = Task.Supervisor.async_nolink(state.task_supervisor, fn -> - case Runtime.call(runtime, {:_next_ls_private_credo, :issues, [state.settings.cli_options, path]}) do - {:ok, issues} -> issues - _error -> [] - end + {time, result} = + :timer.tc( + fn -> + case Runtime.call( + runtime, + {:_next_ls_private_credo, :issues, [state.settings.cli_options, path]} + ) do + {:ok, issues} -> issues + _error -> [] + end + end, + :millisecond + ) + + NextLS.Logger.info( + state.logger, + "[extension] Credo finished running in #{time}ms" + ) + + result end) {state, Map.put(refs, task.ref, namespace)} @@ -142,6 +158,17 @@ defmodule NextLS.CredoExtension do {:noreply, put_in(state.refresh_refs, refs)} end + def handle_info({ref, issues}, %{refresh_refs: _refs} = state) do + Process.demonitor(ref, [:flush]) + + NextLS.Logger.info( + state.logger, + "[extension] Credo received response from untracked ref: #{inspect(ref)} with payload: #{inspect(issues)}" + ) + + {:noreply, state} + end + def handle_info({:DOWN, ref, :process, _pid, _reason}, %{refresh_refs: refs} = state) when is_map_key(refs, ref) do {_, refs} = Map.pop(refs, ref) diff --git a/lib/next_ls/lsp_supervisor.ex b/lib/next_ls/lsp_supervisor.ex index 69393b1d..7c2e1629 100644 --- a/lib/next_ls/lsp_supervisor.ex +++ b/lib/next_ls/lsp_supervisor.ex @@ -89,12 +89,14 @@ defmodule NextLS.LSPSupervisor do {DynamicSupervisor, name: NextLS.DynamicSupervisor}, {Task.Supervisor, name: NextLS.TaskSupervisor}, {Task.Supervisor, name: :runtime_task_supervisor}, + {GenLSP.Assigns, [name: NextLS.Assigns]}, {GenLSP.Buffer, [name: NextLS.Buffer] ++ buffer_opts}, {NextLS.DiagnosticCache, name: :diagnostic_cache}, {Registry, name: NextLS.Registry, keys: :duplicate}, {NextLS, auto_update: auto_update, buffer: NextLS.Buffer, + assigns: NextLS.Assigns, cache: :diagnostic_cache, task_supervisor: NextLS.TaskSupervisor, runtime_task_supervisor: :runtime_task_supervisor, diff --git a/lib/next_ls/progress.ex b/lib/next_ls/progress.ex index 8df4a5ad..7d42fa45 100644 --- a/lib/next_ls/progress.ex +++ b/lib/next_ls/progress.ex @@ -1,12 +1,14 @@ defmodule NextLS.Progress do @moduledoc false + import GenLSP.LSP + alias GenLSP.Notifications.DollarProgress alias GenLSP.Structures.ProgressParams def start(lsp, token, msg) do Task.start(fn -> - if lsp.assigns.client_capabilities.window.work_done_progress do + if assigns(lsp).client_capabilities.window.work_done_progress do GenLSP.request(lsp, %GenLSP.Requests.WindowWorkDoneProgressCreate{ id: System.unique_integer([:positive]), params: %GenLSP.Structures.WorkDoneProgressCreateParams{ diff --git a/lib/next_ls/runtime.ex b/lib/next_ls/runtime.ex index 42289c29..c608cba7 100644 --- a/lib/next_ls/runtime.ex +++ b/lib/next_ls/runtime.ex @@ -2,10 +2,6 @@ defmodule NextLS.Runtime do @moduledoc false use GenServer - alias OpenTelemetry.Tracer - - require OpenTelemetry.Tracer - @env Mix.env() defguardp is_ready(state) when is_map_key(state, :node) @@ -321,37 +317,41 @@ defmodule NextLS.Runtime do {:reply, {:error, :not_ready}, state} end - def handle_call({:call, {m, f, a}, ctx}, _from, %{node: node} = state) do - token = OpenTelemetry.Ctx.attach(ctx) + def handle_call({:call, {m, f, a}, _ctx}, from, %{node: node} = state) do + Task.start_link(fn -> + reply = :rpc.call(node, m, f, a) + GenServer.reply(from, {:ok, reply}) + end) - try do - Tracer.with_span :"runtime.call", %{attributes: %{mfa: inspect({m, f, a})}} do - reply = :rpc.call(node, m, f, a) - {:reply, {:ok, reply}, state} - end - after - OpenTelemetry.Ctx.detach(token) - end + {:noreply, state} end - def handle_call({:expand, ast, file}, _from, %{node: node} = state) do - NextLS.Logger.info(state.logger, "expanding on the runtime node") - reply = :rpc.call(node, :_next_ls_private_spitfire_env, :expand, [ast, file]) - {:reply, {:ok, reply}, state} + def handle_call({:expand, ast, file}, from, %{node: node} = state) do + Task.start_link(fn -> + NextLS.Logger.info(state.logger, "expanding on the runtime node") + reply = :rpc.call(node, :_next_ls_private_spitfire_env, :expand, [ast, file]) + GenServer.reply(from, {:ok, reply}) + end) + + {:noreply, state} end - def handle_call({:compile, opts}, _from, %{node: node} = state) do + def handle_call({:compile, opts}, from, %{node: node} = state) do opts = opts |> Keyword.put_new(:working_dir, state.working_dir) |> Keyword.put_new(:registry, state.registry) |> Keyword.put(:from, self()) - with {:badrpc, error} <- :rpc.call(node, :_next_ls_private_compiler_worker, :enqueue_compiler, [opts]) do - NextLS.Logger.error(state.logger, "Bad RPC call to node #{node}: #{inspect(error)}") - end + Task.start_link(fn -> + with {:badrpc, error} <- :rpc.call(node, :_next_ls_private_compiler_worker, :enqueue_compiler, [opts]) do + NextLS.Logger.error(state.logger, "Bad RPC call to node #{node}: #{inspect(error)}") + end - {:reply, :ok, state} + GenServer.reply(from, :ok) + end) + + {:noreply, state} end @impl GenServer diff --git a/lib/next_ls/runtime/bundled_elixir.ex b/lib/next_ls/runtime/bundled_elixir.ex index a1bef561..20c42de2 100644 --- a/lib/next_ls/runtime/bundled_elixir.ex +++ b/lib/next_ls/runtime/bundled_elixir.ex @@ -4,7 +4,7 @@ defmodule NextLS.Runtime.BundledElixir do The `@version` attribute corresponds to the last digit in the file name of the zip archive, they need to be incremented in lockstep. """ - @version 1 + @version 3 @base "~/.cache/elixir-tools/nextls" @dir "elixir/1-17-#{@version}" @@ -52,8 +52,8 @@ defmodule NextLS.Runtime.BundledElixir do mixbin = mixpath(base) env = [{"PATH", new_path}, {"MIX_HOME", mixhome}, {"MIX_ARCHIVES", mixarchives}] - {_, 0} = System.cmd(mixbin, ["local.rebar", "--force"], env: env) - {_, 0} = System.cmd(mixbin, ["local.hex", "--force"], env: env) + {_, 0} = System.cmd(mixbin, ["local.rebar", "--force"], env: env, stderr_to_stdout: true) + {_, 0} = System.cmd(mixbin, ["local.hex", "--force"], env: env, stderr_to_stdout: true) :ok rescue diff --git a/mix.exs b/mix.exs index e2c70ace..76d9049a 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,8 @@ defmodule NextLS.MixProject do use Mix.Project - @version "0.23.3" # x-release-please-version + # x-release-please-version + @version "0.23.3" def project do [ @@ -63,8 +64,9 @@ defmodule NextLS.MixProject do defp deps do [ {:exqlite, "~> 0.13.14"}, - {:gen_lsp, "~> 0.10"}, + {:gen_lsp, "~> 0.11"}, # {:gen_lsp, path: "../gen_lsp"}, + # {:gen_lsp, github: "elixir-tools/gen_lsp", branch: "async"}, {:req, "~> 0.3"}, {:schematic, "~> 0.2"}, {:spitfire, github: "elixir-tools/spitfire"}, diff --git a/mix.lock b/mix.lock index f9fd7b7f..ecaa2d89 100644 --- a/mix.lock +++ b/mix.lock @@ -20,12 +20,12 @@ "exqlite": {:hex, :exqlite, "0.13.15", "a32c0763915e2b0d7ced9dd8638802d38e9569053f3b28b815bd0faef1cbe6d9", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "4afcc870a33b57781a1e57cd4294eef68815059d26b774c7cd075536b21434b7"}, "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"}, - "gen_lsp": {:hex, :gen_lsp, "0.10.0", "f6da076b5ccedf937d17aa9743635a2c3d0f31265c853e58b02ab84d71852270", [:mix], [{:jason, "~> 1.3", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:schematic, "~> 0.2.1", [hex: :schematic, repo: "hexpm", optional: false]}, {:typed_struct, "~> 0.3.0", [hex: :typed_struct, repo: "hexpm", optional: false]}], "hexpm", "768f8f7b5c5e218fb36dcebd30dcd6275b61ca77052c98c3c4c0375158392c4a"}, + "gen_lsp": {:hex, :gen_lsp, "0.11.0", "9eda4d2fcaff94d9b3062e322fcf524c176db1502f584a3cff6135088b46084b", [:mix], [{:jason, "~> 1.3", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:schematic, "~> 0.2.1", [hex: :schematic, repo: "hexpm", optional: false]}, {:typed_struct, "~> 0.3.0", [hex: :typed_struct, repo: "hexpm", optional: false]}], "hexpm", "d67c20650a5290a02f7bac53083ac4487d3c6b461f35a8b14c5d2d7638c20d26"}, "gproc": {:hex, :gproc, "0.9.1", "f1df0364423539cf0b80e8201c8b1839e229e5f9b3ccb944c5834626998f5b8c", [:rebar3], [], "hexpm", "905088e32e72127ed9466f0bac0d8e65704ca5e73ee5a62cb073c3117916d507"}, "grpcbox": {:hex, :grpcbox, "0.17.1", "6e040ab3ef16fe699ffb513b0ef8e2e896da7b18931a1ef817143037c454bcce", [:rebar3], [{:acceptor_pool, "~> 1.0.0", [hex: :acceptor_pool, repo: "hexpm", optional: false]}, {:chatterbox, "~> 0.15.1", [hex: :ts_chatterbox, repo: "hexpm", optional: false]}, {:ctx, "~> 0.6.0", [hex: :ctx, repo: "hexpm", optional: false]}, {:gproc, "~> 0.9.1", [hex: :gproc, repo: "hexpm", optional: false]}], "hexpm", "4a3b5d7111daabc569dc9cbd9b202a3237d81c80bf97212fbc676832cb0ceb17"}, "hpack": {:hex, :hpack_erl, "0.3.0", "2461899cc4ab6a0ef8e970c1661c5fc6a52d3c25580bc6dd204f84ce94669926", [:rebar3], [], "hexpm", "d6137d7079169d8c485c6962dfe261af5b9ef60fbc557344511c1e65e3d95fb0"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, - "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, @@ -50,7 +50,7 @@ "spitfire": {:git, "https://github.com/elixir-tools/spitfire.git", "178b00becd55b33e080f23c9ed0d1126d57574be", []}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "styler": {:hex, :styler, "1.0.0-rc.0", "977c702b91b11e86ae1995f0f699a372a43e8df175f4878d7e9cc1678d0d7513", [:mix], [], "hexpm", "031624294295d47af7859ef43595092f33b861f0a88e44fae6366a54f1736a1a"}, - "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "telemetry_registry": {:hex, :telemetry_registry, "0.3.1", "14a3319a7d9027bdbff7ebcacf1a438f5f5c903057b93aee484cca26f05bdcba", [:mix, :rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6d0ca77b691cf854ed074b459a93b87f4c7f5512f8f7743c635ca83da81f939e"}, "tls_certificate_check": {:hex, :tls_certificate_check, "1.20.0", "1ac0c53f95e201feb8d398ef9d764ae74175231289d89f166ba88a7f50cd8e73", [:rebar3], [{:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "ab57b74b1a63dc5775650699a3ec032ec0065005eff1f020818742b7312a8426"}, "typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"}, diff --git a/package.nix b/package.nix index 5718be90..d309b037 100644 --- a/package.nix +++ b/package.nix @@ -3,7 +3,6 @@ beamPackages, elixir, }: - beamPackages.mixRelease rec { pname = "next-ls"; src = ./.; @@ -17,7 +16,7 @@ beamPackages.mixRelease rec { mixFodDeps = beamPackages.fetchMixDeps { inherit src version elixir; pname = "next-ls-deps"; - hash = "sha256-4Rt5Q0fX+fbncvxyXdpIhgEvn9VYX/QDxDdnbanT21Q="; + hash = "sha256-TE/hBsbFN6vlE0/VvdJaTxPah5uOdBfC70uhwNYyD4Y="; mixEnv = "prod"; }; diff --git a/priv/precompiled-1-17-3.zip b/priv/precompiled-1-17-3.zip new file mode 100644 index 00000000..cda6c843 Binary files /dev/null and b/priv/precompiled-1-17-3.zip differ diff --git a/test/next_ls/completions_test.exs b/test/next_ls/completions_test.exs index bcfce92e..d5637d39 100644 --- a/test/next_ls/completions_test.exs +++ b/test/next_ls/completions_test.exs @@ -214,9 +214,9 @@ defmodule NextLS.CompletionsTest do } assert_result 2, [ - %{"data" => nil, "documentation" => "", "insertText" => "one", "kind" => 5, "label" => "one"}, %{"data" => nil, "documentation" => "", "insertText" => "two", "kind" => 5, "label" => "two"}, - %{"data" => nil, "documentation" => "", "insertText" => "three", "kind" => 5, "label" => "three"} + %{"data" => nil, "documentation" => "", "insertText" => "three", "kind" => 5, "label" => "three"}, + %{"data" => nil, "documentation" => "", "insertText" => "one", "kind" => 5, "label" => "one"} ] end diff --git a/test/next_ls/pipe_test.exs b/test/next_ls/pipe_test.exs index 7d9b71b7..c9fbe5ba 100644 --- a/test/next_ls/pipe_test.exs +++ b/test/next_ls/pipe_test.exs @@ -50,6 +50,12 @@ defmodule NextLS.PipeTest do did_open(context.client, context.foo_path, context.foo) did_open(context.client, context.bar_path, context.bar) + + # the test runs so fast that it actually runs the executeCommand request + # before the notifications are processed + # could potentially add test affordances so that the server will send the test + # a message when the notification has finished processing + Process.sleep(50) context end diff --git a/test/next_ls_test.exs b/test/next_ls_test.exs index cc63a6de..1e1b4eca 100644 --- a/test/next_ls_test.exs +++ b/test/next_ls_test.exs @@ -94,21 +94,6 @@ defmodule NextLSTest do } end - test "can initialize the server" do - assert_result 1, %{ - "capabilities" => %{ - "textDocumentSync" => %{ - "openClose" => true, - "save" => %{ - "includeText" => true - }, - "change" => 1 - } - }, - "serverInfo" => %{"name" => "Next LS"} - } - end - test "formats", %{client: client, cwd: cwd} = context do assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) diff --git a/test/support/utils.ex b/test/support/utils.ex index da1a4192..2872b6b8 100644 --- a/test/support/utils.ex +++ b/test/support/utils.ex @@ -49,7 +49,6 @@ defmodule NextLS.Support.Utils do mixarchives = Path.join(mixhome, "archives") File.mkdir_p!(bundle_base) - 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]}, id: :three) start_supervised!({Registry, [keys: :duplicate, name: context.module]}, id: :four) @@ -58,7 +57,6 @@ defmodule NextLS.Support.Utils do init_options = context[:init_options] || %{} pids = [ - :one, :two, :three, :four, @@ -67,7 +65,6 @@ defmodule NextLS.Support.Utils do server = server(NextLS, - task_supervisor: tvisor, runtime_task_supervisor: r_tvisor, dynamic_supervisor: rvisor, registry: context.module, @@ -106,6 +103,8 @@ defmodule NextLS.Support.Utils do } }) + assert_result 1, _, 500 + [server: server, client: client, pids: pids] end