rekkice
IEx - Expose API to evaluate code inside IEx session for REPL Integrations
I’m building an editor integration to evaluate Elixir code in an IEx session. While Code.eval_string/3 allows tracking variable bindings, i think there’s currently no way to persist the environment (aliases, imports, etc.) between evaluations using this approach.
Use Case:
- User is using an editor to send code to IEx (through a named pipe, e.g.), which is then read by a custom module defined in
.iex.exs. - User defines
alias MyApp.Modulein one evaluation. - In subsequent evaluations, they expect
Module.function()to work (as if it would in a regular IEx shell).
Proposal:
Expose a public API to evaluate code directly in the IEx instance, e.g.:
# it could be a helper function
result = IEx.Helpers.eval_string("IO.puts(123)")
# or maybe work by directly sending a message to IEx’s evaluator process (e.g., using eval_pid() if such a function were available)
send(eval_pid(), {:eval, "IO.puts(123)"})
I think this would make integrating IEx with external tools such as code editors a much easier task. Helix allows piping selected code directly to a Bash command, so i was using that to send code to a named pipe and read that in IEx. IEx is very useful, but i always experience some friction between it and my editor because i have to manually copy and paste code to it.
I found this post from a while ago that suggests something that i think would work for my case, but i tried it on Elixir 1.18.1 with OTP 26 and it didn’t work, maybe because it’s not a public API.
I’d love to hear if others have faced similar challenges or if there’s an existing approach i might have missed. I’d also be happy to contribute to this implementation if there’s interest, though I’m still learning Elixir and don’t have experience with Erlang.
Most Liked
v0idpwn
Hi,
I think most of what you want is achievable with Code:
def iterative_eval(code, bindings \\ [], env \\ env_for_eval([])) do
quoted = Code.string_to_quoted(code)
Code.eval_quoted_with_env(quoted, bindings, env)
end
Which can be used as:
iex(5)> {result, bindings, env} = Repl.iterative_eval("a = 1"); :ok # Using this `:ok` to avoid printing env
:ok
iex(6)> {result, bindings, env} = Repl.iterative_eval("a + 2", bindings, env); :ok
:ok
iex(7)> result
{:ok, 3}
iex(8)> bindings
[a: 1]
It carries the env, hence it carries aliases, requires, etc. To use the env from iex, you can just use __ENV__:
iex(9)> alias Map, as: M
Map
iex(10)> {result, bindings, env} = Repl.iterative_eval("map = M.new()", [], __ENV__); :ok
:ok
iex(11)> result
{:ok, %{}}
iex(12)> bindings
[map: %{}]
iex(13)>
I don’t know if there’s a way to load these bindings/env back in iex, though.
Popular in Proposals: Ideas
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









