@@ -848,22 +848,101 @@ defmodule IEx do
848848 @ spec break! ( module , atom , arity , non_neg_integer ) :: IEx.Pry . id ( )
849849 defdelegate break! ( module , function , arity , stops \\ 1 ) , to: IEx.Pry
850850
851- ## Callbacks
851+ @ doc false
852+ def dont_display_result , do: :"do not show this result in output"
853+
854+ ## CLI
855+
856+ @ compile { :no_warn_undefined , { :shell , :start_interactive , 1 } }
852857
853858 # This is a callback invoked by Erlang shell utilities
854- # when someone presses Ctrl+G and adds 's Elixir.IEx'.
859+ # when someone presses Ctrl+G and adds `s ' Elixir.IEx'` .
855860 @ doc false
856861 def start ( opts \\ [ ] , mfa \\ { IEx , :dont_display_result , [ ] } ) do
857- spawn ( fn ->
858- { :ok , _ } = Application . ensure_all_started ( :elixir )
859- System . wait_until_booted ( )
860- :ok = :io . setopts ( binary: true , encoding: :unicode )
861- { :ok , _ } = Application . ensure_all_started ( :iex )
862- _ = for fun <- Enum . reverse ( after_spawn ( ) ) , do: fun . ( )
863- IEx.Server . run_from_shell ( opts , mfa )
864- end )
862+ # TODO: Keep only this branch, delete optional args and mfa,
863+ # and delete IEx.Server.run_from_shell/2 on Erlang/OTP 26+
864+ if Code . ensure_loaded? ( :prim_tty ) do
865+ spawn ( fn ->
866+ { :ok , _ } = Application . ensure_all_started ( :iex )
867+ _ = for fun <- Enum . reverse ( after_spawn ( ) ) , do: fun . ( )
868+ IEx.Server . run ( [ register: false ] ++ opts )
869+ end )
870+ else
871+ spawn ( fn ->
872+ { :ok , _ } = Application . ensure_all_started ( :elixir )
873+ System . wait_until_booted ( )
874+ :ok = :io . setopts ( binary: true , encoding: :unicode )
875+ { :ok , _ } = Application . ensure_all_started ( :iex )
876+ _ = for fun <- Enum . reverse ( after_spawn ( ) ) , do: fun . ( )
877+ IEx.Server . run_from_shell ( opts , mfa )
878+ end )
879+ end
865880 end
866881
882+ # Manual tests for changing the CLI boot.
883+ #
884+ # 1. In some situations, we cannot read inputs as IEx boots:
885+ #
886+ # $ iex -e ":io.get_line(:foo)"
887+ #
888+ # 2. In some situations, connecting to a remote node via --remsh
889+ # is not possible. This can be tested by starting two IEx nodes:
890+ #
891+ # $ iex --sname foo
892+ # $ iex --sname bar --remsh foo
893+ #
894+ # 3. When still using --remsh, we need to guarantee the arguments
895+ # are processed on the local node and not the remote one. For such,
896+ # one can replace the last line above by:
897+ #
898+ # $ iex --sname bar --remsh foo -e 'IO.inspect node()'
899+ #
900+ # And verify that the local node name is printed.
901+ #
902+ # 4. Finally, in some other circumstances, printing messages may become
903+ # borked. This can be verified with:
904+ #
905+ # $ iex -e ":logger.info('foo~nbar', [])"
906+ #
907+ # By the time those instructions have been written, all tests above pass.
867908 @ doc false
868- def dont_display_result , do: :"do not show this result in output"
909+ def cli ( opts \\ [ ] ) do
910+ args = :init . get_plain_arguments ( )
911+ opts = opts ++ [ dot_iex_path: find_dot_iex ( args ) , on_eof: :halt ]
912+
913+ ref = make_ref ( )
914+ mfa = { __MODULE__ , :__cli__ , [ self ( ) , ref , opts ] }
915+
916+ shell =
917+ if remote = get_remsh ( args ) do
918+ { :remote , remote , mfa }
919+ else
920+ mfa
921+ end
922+
923+ :ok = :shell . start_interactive ( shell )
924+
925+ receive do
926+ { ^ ref , shell } -> shell
927+ after
928+ 15_000 ->
929+ IO . puts ( :stderr , "Could not start the shell after 15 seconds, aborting..." )
930+ System . halt ( 1 )
931+ end
932+ end
933+
934+ @ doc false
935+ def __cli__ ( parent , ref , opts ) do
936+ pid = start ( opts )
937+ send ( parent , { ref , pid } )
938+ pid
939+ end
940+
941+ defp find_dot_iex ( [ ~c" --dot-iex" , h | _ ] ) , do: List . to_string ( h )
942+ defp find_dot_iex ( [ _ | t ] ) , do: find_dot_iex ( t )
943+ defp find_dot_iex ( [ ] ) , do: nil
944+
945+ defp get_remsh ( [ ~c" --remsh" , h | _ ] ) , do: h
946+ defp get_remsh ( [ _ | t ] ) , do: get_remsh ( t )
947+ defp get_remsh ( [ ] ) , do: nil
869948end
0 commit comments