Skip to content
This repository was archived by the owner on Oct 8, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
507 changes: 257 additions & 250 deletions lib/next_ls.ex

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/next_ls/commands/alias.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ defmodule NextLS.Commands.Alias do

defp opts do
map(%{
position: Position.schematic(),
position: Position.schema(),
uri: str(),
text: list(str())
})
Expand Down
2 changes: 1 addition & 1 deletion lib/next_ls/commands/pipe.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ defmodule NextLS.Commands.Pipe do

defp opts do
map(%{
position: Position.schematic(),
position: Position.schema(),
uri: str(),
text: list(str())
})
Expand Down
35 changes: 31 additions & 4 deletions lib/next_ls/extensions/credo_extension.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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)}
Expand Down Expand Up @@ -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)

Expand Down
2 changes: 2 additions & 0 deletions lib/next_ls/lsp_supervisor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion lib/next_ls/progress.ex
Original file line number Diff line number Diff line change
@@ -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{
Expand Down
46 changes: 23 additions & 23 deletions lib/next_ls/runtime.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions lib/next_ls/runtime/bundled_elixir.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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}"

Expand Down Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -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
[
Expand Down Expand Up @@ -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"},
Expand Down
6 changes: 3 additions & 3 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"},
Expand All @@ -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"},
Expand Down
3 changes: 1 addition & 2 deletions package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
beamPackages,
elixir,
}:

beamPackages.mixRelease rec {
pname = "next-ls";
src = ./.;
Expand All @@ -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";
};

Expand Down
Binary file added priv/precompiled-1-17-3.zip
Binary file not shown.
4 changes: 2 additions & 2 deletions test/next_ls/completions_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 6 additions & 0 deletions test/next_ls/pipe_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
15 changes: 0 additions & 15 deletions test/next_ls_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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: %{}})

Expand Down
5 changes: 2 additions & 3 deletions test/support/utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -58,7 +57,6 @@ defmodule NextLS.Support.Utils do
init_options = context[:init_options] || %{}

pids = [
:one,
:two,
:three,
:four,
Expand All @@ -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,
Expand Down Expand Up @@ -106,6 +103,8 @@ defmodule NextLS.Support.Utils do
}
})

assert_result 1, _, 500

[server: server, client: client, pids: pids]
end

Expand Down
Loading