I’m trying to run a script with Mix.install inside, and set some breakpoints. I’m running VSCode with the ElixirLS extension. I can run the script just fine if I mix run --no-mix-exs file.exs
but not with the debugger, even If I add the flag to taskArgs
. Haven’t found this functionality doccumented in the extension docs so either I’m doing something wrong or it’s not implemented?
I don’t have a direct solution but figured I’d respond since you haven’t gotten any bites yet.
By debugger do you mean dbg
? If so then I’m not sure this is possible since in order for it to be available, you need to add :runtime_tools
to :extra_applications
in a mix file. I’m sorry I don’t know the answer but maybe that’s a good enough clue?
…and welcome to Elixir Forum!
By debugger do you mean
dbg
No @sodapopcan, OP means ElixirLS debug adapter (GitHub - elixir-lsp/vscode-elixir-ls: Elixir language support and debugger for VS Code, powered by ElixirLS.)
Haven’t found this functionality doccumented in the extension docs so either I’m doing something wrong or it’s not implemented?
@kidp330 ElixirLS debug adapter currently requires a mix project (I opened Debug adapter does not support no mixfile projects · Issue #1037 · elixir-lsp/elixir-ls · GitHub for tracking). Trying to run in a folder that does not contain mix.exs
will raise Mix.NoMixProjectError
. You can create a dummy project and run your scripts from there.
However this is tricky in case of .exs files.
- OTP debugger which ElixirLS uses underneath requires modules to be interpreted before you can set breakpoints in them. So you need to put your code in module functions
- .exs files are compiled in memory. To interpret them you need to include them in
requireFiles
so they are purged, recompiled and their beam files saved to disk so the OTP debugger can interpret them - .exs script starts executing when you compile it not giving the debugger required time to interpret and set breakpoints. It’s not possible to purge a module when a process executes it’s code. The reasult is that interpretation happens when the script has already returned. You can overcome this with invoking your code in a separate process started from the script
mix run
exits when the script return. By default debugger will end the session when mix task finishes. You need to setexitAfterTaskReturns
tofalse
so the debug session will continue
I was able to create a proof of concept. The debugger breaks when the breakpoint in Abc.debug_me
is hit from the task I start. I needed to add some delay though. Otherwise the code finished before the breakpoint was set.
poc.exs
defmodule Abc do
def debug_me() do
a = [1, 2, 3]
b = Enum.map(a, & &1 + 1)
b
end
end
a = [1, 2, 3]
b = Enum.map(a, & &1 + 1)
IO.puts("done #{inspect(b)}, #{Abc.debug_me()}")
Task.start(fn ->
Process.sleep(4000)
IO.puts("done from task #{inspect(b)}, #{Abc.debug_me()}")
end)
launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "mix_task",
"name": "mix run",
"request": "launch",
"task": "run",
"taskArgs": [
"--no-mix-exs",
"poc.exs"
],
"startApps": false,
"projectDir": "${workspaceRoot}",
"exitAfterTaskReturns": false,
"requireFiles": [
"poc.exs"
]
}
]
}
The other possibility is breaking on Kernel.dbg
macro. This is easier to achieve. In this case do not put the script into requireFiles
as recompilation and interpreting will deadlock the debugger
ElixirLS Debug adapter will support --no-mix-exs
in 0.19 release