Skip to content

Commit

Permalink
Support workspace/project shims with elixir_exec option
Browse files Browse the repository at this point in the history
Relates to elixir-tools#334

IDEs like to work with shims rather than tools that alter path
(such as `mise`/`rtx`). As a result, one must launch their IDE
manually from a terminal session with all the `PATH` loaded in
order to properly find the `elixir` executable. This works fine,
but switching between projects/workspaces that have varying
Elixir/OTP versions will most likely be using the version loaded
when launching the program from terminal.

One resolve might be to include shims in the `PATH` globally.
However, that negates some of the reasoning to move to alternate
tools like `mise.

Instead, this allows setting the `elixir_exec` option to point
directly at a shim. When used in workspace directories, that
should also be able to load the correct versions defined in the
tool version files. This also allows keeping the need for a shim
isolated to the LS tool rather than global use
  • Loading branch information
jjcarstens committed Jan 20, 2024
1 parent 8cf06cb commit 87da773
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 1 deletion.
3 changes: 3 additions & 0 deletions lib/next_ls.ex
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,7 @@ defmodule NextLS do
uri: uri,
mix_env: lsp.assigns.init_opts.mix_env,
mix_target: lsp.assigns.init_opts.mix_target,
elixir_exec: lsp.assigns.init_opts.elixir_exec,
on_initialized: fn status ->
if status == :ready do
Progress.stop(lsp, token, "NextLS runtime for folder #{name} has initialized!")
Expand Down Expand Up @@ -1117,6 +1118,7 @@ defmodule NextLS do

defstruct mix_target: "host",
mix_env: "dev",
elixir_exec: nil,
experimental: %NextLS.InitOpts.Experimental{},
extensions: %NextLS.InitOpts.Extensions{}

Expand All @@ -1126,6 +1128,7 @@ defmodule NextLS do
schema(__MODULE__, %{
optional(:mix_target) => str(),
optional(:mix_env) => str(),
optional(:elixir_exec) => str(),
optional(:experimental) =>
schema(NextLS.InitOpts.Experimental, %{
optional(:completions) =>
Expand Down
14 changes: 13 additions & 1 deletion lib/next_ls/runtime.ex
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ defmodule NextLS.Runtime do
new_path = String.replace(path, bindir <> ":", "")

with dir when is_list(dir) <- :code.priv_dir(:next_ls),
elixir_exe when is_binary(elixir_exe) <- System.find_executable("elixir") do
elixir_exe when is_binary(elixir_exe) <- use_or_find_elixir_exec(opts) do
exe =
dir
|> Path.join("cmd")
Expand Down Expand Up @@ -348,4 +348,16 @@ defmodule NextLS.Runtime do
true
end
end

defp use_or_find_elixir_exec(opts) do
with path when is_binary(path) <- opts[:elixir_exec],
exec = Path.expand(path),
true <- File.exists?(exec),
{_, 0} <- System.cmd(exec, ["--version"]) do
exec
else
_ ->
System.find_executable("elixir")
end
end
end
31 changes: 31 additions & 0 deletions test/next_ls/runtime_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,37 @@ defmodule NextLs.RuntimeTest do
end
end

test "supports using custom elixir_exec path", %{logger: logger, cwd: cwd, on_init: on_init} do
start_supervised!({Registry, keys: :duplicate, name: RuntimeTest.Registry})
tvisor = start_supervised!(Task.Supervisor)

# Create local Elixir shim
elixir_exec = Path.join(cwd, "elixir")
File.ln_s!(System.find_executable("elixir"), elixir_exec)
assert {_, 0} = System.cmd(elixir_exec, ["--version"])

pid =
start_supervised!(
{Runtime,
name: "my_proj",
on_initialized: on_init,
task_supervisor: tvisor,
working_dir: cwd,
uri: "file://#{cwd}",
parent: self(),
logger: logger,
db: :some_db,
mix_env: "dev",
mix_target: "host",
elixir_exec: elixir_exec,
registry: RuntimeTest.Registry}
)

Process.link(pid)

assert_receive :ready
end

defp flush_messages do
receive do
_ -> flush_messages()
Expand Down

0 comments on commit 87da773

Please sign in to comment.