From 9b6c286f2e483bd09007b97576ca04ce247649a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20K=C5=82osko?= Date: Mon, 21 Oct 2024 14:26:48 +0800 Subject: [PATCH 1/2] Add iex option to automatically purge recompiled modules --- bin/elixir | 2 +- bin/elixir.bat | 27 ++++++++++++++------------- bin/iex | 2 ++ bin/iex.bat | 2 ++ lib/elixir/lib/kernel/cli.ex | 9 +++++++++ lib/iex/lib/iex/mix_listener.ex | 30 ++++++++++++++++++++---------- 6 files changed, 48 insertions(+), 24 deletions(-) diff --git a/bin/elixir b/bin/elixir index 79b74deb9e2..f13bea48f93 100755 --- a/bin/elixir +++ b/bin/elixir @@ -111,7 +111,7 @@ while [ $I -le $LENGTH ]; do C=1 MODE="iex" ;; - -v|--no-halt) + -v|--auto-reload|--no-halt) C=1 ;; -e|-r|-pr|-pa|-pz|--eval|--remsh|--dot-iex|--dbg) diff --git a/bin/elixir.bat b/bin/elixir.bat index 448e22f4fd3..13aa50a0eb2 100644 --- a/bin/elixir.bat +++ b/bin/elixir.bat @@ -97,19 +97,20 @@ rem ******* EXECUTION OPTIONS ********************** if !par!=="+iex" (set useIEx=1 && goto startloop) if !par!=="+elixirc" (goto startloop) rem ******* ELIXIR PARAMETERS ********************** -if ""==!par:-e=! (shift && goto startloop) -if ""==!par:--eval=! (shift && goto startloop) -if ""==!par:--rpc-eval=! (shift && shift && goto startloop) -if ""==!par:-r=! (shift && goto startloop) -if ""==!par:-pr=! (shift && goto startloop) -if ""==!par:-pa=! (shift && goto startloop) -if ""==!par:-pz=! (shift && goto startloop) -if ""==!par:-v=! (goto startloop) -if ""==!par:--version=! (goto startloop) -if ""==!par:--no-halt=! (goto startloop) -if ""==!par:--remsh=! (shift && goto startloop) -if ""==!par:--dot-iex=! (shift && goto startloop) -if ""==!par:--dbg=! (shift && goto startloop) +if ""==!par:-e=! (shift && goto startloop) +if ""==!par:--eval=! (shift && goto startloop) +if ""==!par:--rpc-eval=! (shift && shift && goto startloop) +if ""==!par:-r=! (shift && goto startloop) +if ""==!par:-pr=! (shift && goto startloop) +if ""==!par:-pa=! (shift && goto startloop) +if ""==!par:-pz=! (shift && goto startloop) +if ""==!par:-v=! (goto startloop) +if ""==!par:--version=! (goto startloop) +if ""==!par:--auto-reload=! (goto startloop) +if ""==!par:--no-halt=! (goto startloop) +if ""==!par:--remsh=! (shift && goto startloop) +if ""==!par:--dot-iex=! (shift && goto startloop) +if ""==!par:--dbg=! (shift && goto startloop) rem ******* ERLANG PARAMETERS ********************** if ""==!par:--boot=! (set "parsErlang=!parsErlang! -boot "%~1"" && shift && goto startloop) if ""==!par:--boot-var=! (set "parsErlang=!parsErlang! -boot_var "%~1" "%~2"" && shift && shift && goto startloop) diff --git a/bin/iex b/bin/iex index 5bf60509369..e3134b2a887 100755 --- a/bin/iex +++ b/bin/iex @@ -7,6 +7,8 @@ Usage: $(basename "$0") [options] [.exs file] [data] The following options are exclusive to IEx: + --auto-reload Automatically purge in-memory modules that get invalidated + by a concurrent compilation. --dbg pry Sets the backend for Kernel.dbg/2 to IEx.pry/0 --dot-iex "FILE" Evaluates FILE, line by line, to set up IEx' environment. Defaults to evaluating .iex.exs or ~/.iex.exs, if any exists. diff --git a/bin/iex.bat b/bin/iex.bat index fc9f5d3f134..aa9245ff251 100644 --- a/bin/iex.bat +++ b/bin/iex.bat @@ -11,6 +11,8 @@ echo Usage: %~nx0 [options] [.exs file] [data] echo. echo The following options are exclusive to IEx: echo. +echo --auto-reload Automatically purge in-memory modules that get invalidated +echo by a concurrent compilation. echo --dbg pry Sets the backend for Kernel.dbg/2 to IEx.pry/0 echo --dot-iex "FILE" Evaluates FILE, line by line, to set up IEx' environment. echo Defaults to evaluating .iex.exs or ~/.iex.exs, if any exists. diff --git a/lib/elixir/lib/kernel/cli.ex b/lib/elixir/lib/kernel/cli.ex index b9b0fd1fcbd..2825be13897 100644 --- a/lib/elixir/lib/kernel/cli.ex +++ b/lib/elixir/lib/kernel/cli.ex @@ -13,6 +13,7 @@ defmodule Kernel.CLI do verbose_compile: false, profile: nil, pry: false, + iex_auto_reload: false, mode: :elixir } @@ -30,6 +31,10 @@ defmodule Kernel.CLI do Application.put_env(:elixir, :dbg_callback, {IEx.Pry, :dbg, []}) end + if config.iex_auto_reload do + Application.put_env(:iex, :auto_reload, true) + end + fun = fn _ -> errors = process_commands(config) @@ -343,6 +348,10 @@ defmodule Kernel.CLI do end end + defp parse_argv([~c"--auto-reload" | t], %{mode: :iex} = config) do + parse_argv(t, %{config | iex_auto_reload: true}) + end + defp parse_argv([~c"--dot-iex", _ | t], %{mode: :iex} = config), do: parse_argv(t, config) defp parse_argv([~c"--remsh", _ | t], %{mode: :iex} = config), do: parse_argv(t, config) diff --git a/lib/iex/lib/iex/mix_listener.ex b/lib/iex/lib/iex/mix_listener.ex index c905a93c764..dad04a46882 100644 --- a/lib/iex/lib/iex/mix_listener.ex +++ b/lib/iex/lib/iex/mix_listener.ex @@ -20,18 +20,14 @@ defmodule IEx.MixListener do @impl true def init({}) do - {:ok, %{to_purge: MapSet.new()}} + auto_reload = Application.get_env(:iex, :auto_reload, false) + {:ok, %{auto_reload: auto_reload, to_purge: MapSet.new()}} end @impl true def handle_call(:purge, _from, state) do - for module <- state.to_purge do - :code.purge(module) - :code.delete(module) - end - + purge_modules(state.to_purge) status = if Enum.empty?(state.to_purge), do: :noop, else: :ok - {:reply, status, %{state | to_purge: MapSet.new()}} end @@ -43,13 +39,27 @@ defmodule IEx.MixListener do {:noreply, state} else %{changed: changed, removed: removed} = info.modules_diff - state = update_in(state.to_purge, &Enum.into(changed, &1)) - state = update_in(state.to_purge, &Enum.into(removed, &1)) - {:noreply, state} + + if state.auto_reload do + purge_modules(changed) + purge_modules(removed) + {:noreply, state} + else + state = update_in(state.to_purge, &Enum.into(changed, &1)) + state = update_in(state.to_purge, &Enum.into(removed, &1)) + {:noreply, state} + end end end def handle_info(_message, state) do {:noreply, state} end + + defp purge_modules(modules) do + for module <- modules do + :code.purge(module) + :code.delete(module) + end + end end From 3ef9b1ab34b9be4095fd42dd92b280fc942c025b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20K=C5=82osko?= Date: Mon, 21 Oct 2024 15:07:08 +0800 Subject: [PATCH 2/2] Use IEx.configure/1 --- bin/elixir | 2 +- bin/elixir.bat | 27 +++++++++++++-------------- bin/iex | 2 -- bin/iex.bat | 2 -- lib/elixir/lib/kernel/cli.ex | 9 --------- lib/iex/lib/iex.ex | 5 ++++- lib/iex/lib/iex/config.ex | 8 +++++++- lib/iex/lib/iex/mix_listener.ex | 5 ++--- lib/iex/mix.exs | 3 ++- 9 files changed, 29 insertions(+), 34 deletions(-) diff --git a/bin/elixir b/bin/elixir index f13bea48f93..79b74deb9e2 100755 --- a/bin/elixir +++ b/bin/elixir @@ -111,7 +111,7 @@ while [ $I -le $LENGTH ]; do C=1 MODE="iex" ;; - -v|--auto-reload|--no-halt) + -v|--no-halt) C=1 ;; -e|-r|-pr|-pa|-pz|--eval|--remsh|--dot-iex|--dbg) diff --git a/bin/elixir.bat b/bin/elixir.bat index 13aa50a0eb2..448e22f4fd3 100644 --- a/bin/elixir.bat +++ b/bin/elixir.bat @@ -97,20 +97,19 @@ rem ******* EXECUTION OPTIONS ********************** if !par!=="+iex" (set useIEx=1 && goto startloop) if !par!=="+elixirc" (goto startloop) rem ******* ELIXIR PARAMETERS ********************** -if ""==!par:-e=! (shift && goto startloop) -if ""==!par:--eval=! (shift && goto startloop) -if ""==!par:--rpc-eval=! (shift && shift && goto startloop) -if ""==!par:-r=! (shift && goto startloop) -if ""==!par:-pr=! (shift && goto startloop) -if ""==!par:-pa=! (shift && goto startloop) -if ""==!par:-pz=! (shift && goto startloop) -if ""==!par:-v=! (goto startloop) -if ""==!par:--version=! (goto startloop) -if ""==!par:--auto-reload=! (goto startloop) -if ""==!par:--no-halt=! (goto startloop) -if ""==!par:--remsh=! (shift && goto startloop) -if ""==!par:--dot-iex=! (shift && goto startloop) -if ""==!par:--dbg=! (shift && goto startloop) +if ""==!par:-e=! (shift && goto startloop) +if ""==!par:--eval=! (shift && goto startloop) +if ""==!par:--rpc-eval=! (shift && shift && goto startloop) +if ""==!par:-r=! (shift && goto startloop) +if ""==!par:-pr=! (shift && goto startloop) +if ""==!par:-pa=! (shift && goto startloop) +if ""==!par:-pz=! (shift && goto startloop) +if ""==!par:-v=! (goto startloop) +if ""==!par:--version=! (goto startloop) +if ""==!par:--no-halt=! (goto startloop) +if ""==!par:--remsh=! (shift && goto startloop) +if ""==!par:--dot-iex=! (shift && goto startloop) +if ""==!par:--dbg=! (shift && goto startloop) rem ******* ERLANG PARAMETERS ********************** if ""==!par:--boot=! (set "parsErlang=!parsErlang! -boot "%~1"" && shift && goto startloop) if ""==!par:--boot-var=! (set "parsErlang=!parsErlang! -boot_var "%~1" "%~2"" && shift && shift && goto startloop) diff --git a/bin/iex b/bin/iex index e3134b2a887..5bf60509369 100755 --- a/bin/iex +++ b/bin/iex @@ -7,8 +7,6 @@ Usage: $(basename "$0") [options] [.exs file] [data] The following options are exclusive to IEx: - --auto-reload Automatically purge in-memory modules that get invalidated - by a concurrent compilation. --dbg pry Sets the backend for Kernel.dbg/2 to IEx.pry/0 --dot-iex "FILE" Evaluates FILE, line by line, to set up IEx' environment. Defaults to evaluating .iex.exs or ~/.iex.exs, if any exists. diff --git a/bin/iex.bat b/bin/iex.bat index aa9245ff251..fc9f5d3f134 100644 --- a/bin/iex.bat +++ b/bin/iex.bat @@ -11,8 +11,6 @@ echo Usage: %~nx0 [options] [.exs file] [data] echo. echo The following options are exclusive to IEx: echo. -echo --auto-reload Automatically purge in-memory modules that get invalidated -echo by a concurrent compilation. echo --dbg pry Sets the backend for Kernel.dbg/2 to IEx.pry/0 echo --dot-iex "FILE" Evaluates FILE, line by line, to set up IEx' environment. echo Defaults to evaluating .iex.exs or ~/.iex.exs, if any exists. diff --git a/lib/elixir/lib/kernel/cli.ex b/lib/elixir/lib/kernel/cli.ex index 2825be13897..b9b0fd1fcbd 100644 --- a/lib/elixir/lib/kernel/cli.ex +++ b/lib/elixir/lib/kernel/cli.ex @@ -13,7 +13,6 @@ defmodule Kernel.CLI do verbose_compile: false, profile: nil, pry: false, - iex_auto_reload: false, mode: :elixir } @@ -31,10 +30,6 @@ defmodule Kernel.CLI do Application.put_env(:elixir, :dbg_callback, {IEx.Pry, :dbg, []}) end - if config.iex_auto_reload do - Application.put_env(:iex, :auto_reload, true) - end - fun = fn _ -> errors = process_commands(config) @@ -348,10 +343,6 @@ defmodule Kernel.CLI do end end - defp parse_argv([~c"--auto-reload" | t], %{mode: :iex} = config) do - parse_argv(t, %{config | iex_auto_reload: true}) - end - defp parse_argv([~c"--dot-iex", _ | t], %{mode: :iex} = config), do: parse_argv(t, config) defp parse_argv([~c"--remsh", _ | t], %{mode: :iex} = config), do: parse_argv(t, config) diff --git a/lib/iex/lib/iex.ex b/lib/iex/lib/iex.ex index 7215b5ef3cc..68a3dd31e72 100644 --- a/lib/iex/lib/iex.ex +++ b/lib/iex/lib/iex.ex @@ -357,7 +357,7 @@ defmodule IEx do 13 It is possible to load another file by configuring the `iex` application's `dot_iex` - value (`config :iex, dot_iex: "PATH"` or `IEx.Config.configure(dot_iex: "PATH")`) + value (`config :iex, dot_iex: "PATH"` or `IEx.configure(dot_iex: "PATH")`) or supplying the `--dot-iex` option to IEx. See `iex --help`. In case of remote nodes, the location of the `.iex.exs` files are taken @@ -488,6 +488,9 @@ defmodule IEx do * `:alive_continuation_prompt` - used when `Node.alive?/0` returns `true` and more input is expected + * `:auto_reload` - when set to `true`, automatically purges in-memory + modules when they get invalidated by a concurrent compilation + The following values in the prompt string will be replaced appropriately: * `%counter` - the index of the history diff --git a/lib/iex/lib/iex/config.ex b/lib/iex/lib/iex/config.ex index f94406e6f7c..863b30ecfa5 100644 --- a/lib/iex/lib/iex/config.ex +++ b/lib/iex/lib/iex/config.ex @@ -14,7 +14,8 @@ defmodule IEx.Config do :alive_continuation_prompt, :width, :parser, - :dot_iex + :dot_iex, + :auto_reload ] # Read API @@ -93,6 +94,10 @@ defmodule IEx.Config do Application.get_env(:iex, :dot_iex) end + def auto_reload?() do + Application.fetch_env!(:iex, :auto_reload) + end + # Used by default on evaluation cycle defp default_color(:eval_interrupt), do: [:yellow] defp default_color(:eval_result), do: [:yellow] @@ -199,6 +204,7 @@ defmodule IEx.Config do defp validate_option({:width, new}) when is_integer(new), do: :ok defp validate_option({:parser, tuple}) when tuple_size(tuple) == 3, do: :ok defp validate_option({:dot_iex, path}) when is_binary(path), do: :ok + defp validate_option({:auto_reload, enabled}) when is_boolean(enabled), do: :ok defp validate_option(option) do raise ArgumentError, "invalid configuration #{inspect(option)}" diff --git a/lib/iex/lib/iex/mix_listener.ex b/lib/iex/lib/iex/mix_listener.ex index dad04a46882..57f2e0f7f17 100644 --- a/lib/iex/lib/iex/mix_listener.ex +++ b/lib/iex/lib/iex/mix_listener.ex @@ -20,8 +20,7 @@ defmodule IEx.MixListener do @impl true def init({}) do - auto_reload = Application.get_env(:iex, :auto_reload, false) - {:ok, %{auto_reload: auto_reload, to_purge: MapSet.new()}} + {:ok, %{to_purge: MapSet.new()}} end @impl true @@ -40,7 +39,7 @@ defmodule IEx.MixListener do else %{changed: changed, removed: removed} = info.modules_diff - if state.auto_reload do + if IEx.Config.auto_reload?() do purge_modules(changed) purge_modules(removed) {:noreply, state} diff --git a/lib/iex/mix.exs b/lib/iex/mix.exs index 30e7c537d58..0493b7f1644 100644 --- a/lib/iex/mix.exs +++ b/lib/iex/mix.exs @@ -18,7 +18,8 @@ defmodule IEx.MixProject do inspect: [pretty: true], history_size: 20, default_prompt: "%prefix(%counter)>", - alive_prompt: "%prefix(%node)%counter>" + alive_prompt: "%prefix(%node)%counter>", + auto_reload: false ] ] end