ruhshan
Go-to-definition & hover lost when using dynamic module calls via Application.get_env/3
On vscode, I’ve noticed that ElixirLS navigation and hover only work when I call modules directly, but break as soon as I switch to a dynamic lookup via Application.get_env/3.
Direct calls (works)
defmodule TaskProcessor.Events do
alias TaskProcessor.Segments
alias TaskProcessor.Events.Queue.Oban, as: EventsQueue
alias TaskProcessor.Events.Persistance.Ecto, as: Repo
def enqueue_create_event(event_id) when is_integer(event_id) and event_id > 0 do
EventsQueue.enqueue_create_event(event_id)
end
def enqueue_create_event(bad_event_id), do: {:error, {:invalid_event_id, bad_event_id}}
def process_event(%{event_id: id, isCreated: true}) do
case Repo.fetch_with_segments(id) do
:not_found -> {:error, :not_found}
{:ok, %{date: date, segments: segs}} ->
Segments.schedule_segments(segs, id, date)
end
end
end
- Cmd+Click on EventsQueue.enqueue_create_event/1 or Repo.fetch_with_segments/1 jumps to the implementation.
- Hover shows the function signature.
Dynamic calls (Not working, or am i not doing right ?)
defmodule TaskProcessor.Events.Impl do
@behaviour TaskProcessor.Events.Behavior
alias TaskProcessor.Segments
@impl true
@spec enqueue_create_event(any()) :: {:ok, Oban.Job.t()} | {:error, any()}
def enqueue_create_event(event_id) when is_integer(event_id) and event_id > 0 do
queue_impl().enqueue_create_event(event_id)
end
def enqueue_create_event(bad_event_id), do: {:error, {:invalid_event_id, bad_event_id}}
@impl true
def process_event(%{event_id: id, isCreated: true}) do
case repo_impl().fetch_with_segments(id) do
:not_found -> {:error, :not_found}
{:ok, %{date: date, segments: segs}} ->
Segments.schedule_segments(segs, id, date)
end
end
defp queue_impl do
Application.get_env(:task_processor, :events_queue, TaskProcessor.Events.Queue.Oban)
end
defp repo_impl do
Application.get_env(:task_processor, :events_repo, TaskProcessor.Events.Persistance.Ecto)
end
end
- Cmd+Click on queue_impl().enqueue_create_event/1 or repo_impl().fetch_with_segments/1 does nothing.
- Hovering shows nothing.
Environment
- ElixirLS version: 0.28.0
- Elixir version: 1.18.4
- Erlang/OTP version: 28
- Macbook M1
Is there any way to configure ElixirLS (or leverage Dialyzer/Elixir compiler hints) so that go-to-definition and hover info work for modules resolved at runtime via Application.get_env/3? I need this functionality so that I can dynamically inject mocks during tests using the Mox library.
Thank you!
Most Liked
lud
If you can, use Application.compile_env/2 and assign to a module attibute. This works.
If you really need to change the implementationat runtime then it cannot work as far as I know. Better use a callback in thas case.
ruhshan
Update:
Installed elixir tools, that contains next-ls. Now I can use go to definition on @repo.fetch_with_segments.
I’m wondering, if next-ls can do it, elixir-ls which is more mature supposed to do it too.
lud
I don’t have my dev machine right now but I’m using ElixirLS and this generally works. Maybe try rm -rf .elixir_ls sometimes it helps.
apoorv-2204
AFAIK Elixir ls wont.
I would suggest a high level api for Repo and queue.
And separate impl. As it looks coupled
High level api
defmodule TaskProcessor.Events do
alias TaskProcessor.EventsQueue
alias TaskProcessor.EventsRepo
def enqueue_create_event(event_id) when is_integer(event_id) and event_id > 0 do
EventsQueue.enqueue_create_event(event_id)
end
def enqueue_create_event(bad_event_id), do: {:error, {:invalid_event_id, bad_event_id}}
def process_event(%{event_id: id, isCreated: true}) do
case EventsRepo.fetch_with_segments(id) do
:not_found -> {:error, :not_found}
{:ok, %{date: date, segments: segs}} ->
Segments.schedule_segments(segs, id, date)
end
end
end
defmodule TaskProcessor.EventsQueue do
defp impl do
Application.get_env(:task_processor, :events_queue, TaskProcessor.Events.Queue.Oban)
end
def create_event() do
impl()...function_call()
end
end
defmodule TaskProcessor.EventsRepo do
defp repo_impl do
Application.get_env(:task_processor, :events_repo, TaskProcessor.Events.Persistance.Ecto)
end
def with_segs() do
repo_impl()...function_call()
end
end
defmodule TaskProcessor.Events.Persistance.Ecto do
@behaviour Repo....
def fetch_with_segments(...) do
...
end
end
its an example and wont solve the issue of elixir ls…
x







