From ca1868e2a42ea9d9b1d96139cb58aa8aef4e08e6 Mon Sep 17 00:00:00 2001 From: Fernando Tapia Rico Date: Tue, 10 Dec 2019 15:33:15 +0100 Subject: [PATCH] Allow customization of the continuation prompt on IEx (#9620) It allows users to further customize IEx. For example, it could be useful to include additional information in the prompt: Erlang/OTP X [erts-x.x] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] Interactive Elixir (1.x.x) - press Ctrl+C to exit (type h() ENTER for help) production - read-only session - i-abc435123asd12323 - eu-west-1 iex(1)> if true do ...(1)> :ok ...(1)> end :ok production - read-only session - i-abc435123asd12323 - eu-west-1 iex(2)> --- lib/iex/lib/iex.ex | 11 ++++++++++- lib/iex/lib/iex/config.ex | 21 ++++++++++++++++++++- lib/iex/lib/iex/server.ex | 25 ++++++++++++++++++------- lib/iex/test/iex/interaction_test.exs | 5 +++++ 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/lib/iex/lib/iex.ex b/lib/iex/lib/iex.ex index d77bd2f181..d7a1b05fb9 100644 --- a/lib/iex/lib/iex.ex +++ b/lib/iex/lib/iex.ex @@ -338,7 +338,9 @@ defmodule IEx do * `:width` * `:history_size` * `:default_prompt` + * `:continuation_prompt` * `:alive_prompt` + * `:alive_continuation_prompt` They are discussed individually in the sections below. @@ -420,7 +422,14 @@ defmodule IEx do The value is a keyword list with two possible keys representing prompt types: * `:default_prompt` - used when `Node.alive?/0` returns `false` - * `:alive_prompt` - used when `Node.alive?/0` returns `true` + + * `:continuation_prompt` - used when `Node.alive?/0` returns `false` + and more input is expected + + * `:alive_prompt` - used when `Node.alive?/0` returns `true` + + * `:alive_continuation_prompt` - used when `Node.alive?/0` returns + `true` and more input is expected The following values in the prompt string will be replaced appropriately: diff --git a/lib/iex/lib/iex/config.ex b/lib/iex/lib/iex/config.ex index 844e3733aa..a8d0225968 100644 --- a/lib/iex/lib/iex/config.ex +++ b/lib/iex/lib/iex/config.ex @@ -4,7 +4,16 @@ defmodule IEx.Config do @table __MODULE__ @agent __MODULE__ - @keys [:colors, :inspect, :history_size, :default_prompt, :alive_prompt, :width] + @keys [ + :colors, + :inspect, + :history_size, + :default_prompt, + :continuation_prompt, + :alive_prompt, + :alive_continuation_prompt, + :width + ] # Read API @@ -37,10 +46,18 @@ defmodule IEx.Config do Application.fetch_env!(:iex, :default_prompt) end + def continuation_prompt() do + Application.get_env(:iex, :continuation_prompt, default_prompt()) + end + def alive_prompt() do Application.fetch_env!(:iex, :alive_prompt) end + def alive_continuation_prompt() do + Application.get_env(:iex, :alive_continuation_prompt, alive_prompt()) + end + def color(color) do color(color, Application.get_env(:iex, :colors, [])) end @@ -176,7 +193,9 @@ defmodule IEx.Config do defp merge_option(:inspect, old, new) when is_list(new), do: Keyword.merge(old, new) defp merge_option(:history_size, _old, new) when is_integer(new), do: new defp merge_option(:default_prompt, _old, new) when is_binary(new), do: new + defp merge_option(:continuation_prompt, _old, new) when is_binary(new), do: new defp merge_option(:alive_prompt, _old, new) when is_binary(new), do: new + defp merge_option(:alive_continuation_prompt, _old, new) when is_binary(new), do: new defp merge_option(:width, _old, new) when is_integer(new), do: new defp merge_option(key, _old, new) do diff --git a/lib/iex/lib/iex/server.ex b/lib/iex/lib/iex/server.ex index 89357a6109..e1ec0b2d27 100644 --- a/lib/iex/lib/iex/server.ex +++ b/lib/iex/lib/iex/server.ex @@ -117,9 +117,15 @@ defmodule IEx.Server do defp loop(state, evaluator, evaluator_ref) do self_pid = self() counter = state.counter - prefix = if state.cache != [], do: "...", else: state.prefix - input = spawn(fn -> io_get(self_pid, prefix, counter) end) + {prompt_type, prefix} = + if state.cache != [] do + {:continuation_prompt, "..."} + else + {:prompt, state.prefix} + end + + input = spawn(fn -> io_get(self_pid, prompt_type, prefix, counter) end) wait_input(state, evaluator, evaluator_ref, input) end @@ -316,17 +322,17 @@ defmodule IEx.Server do ## IO - defp io_get(pid, prefix, counter) do - prompt = prompt(prefix, counter) + defp io_get(pid, prompt_type, prefix, counter) do + prompt = prompt(prompt_type, prefix, counter) send(pid, {:input, self(), IO.gets(:stdio, prompt)}) end - defp prompt(prefix, counter) do + defp prompt(prompt_type, prefix, counter) do {mode, prefix} = if Node.alive?() do - {:alive_prompt, prefix || remote_prefix()} + {prompt_mode(prompt_type, :alive), prefix || remote_prefix()} else - {:default_prompt, prefix || "iex"} + {prompt_mode(prompt_type, :default), prefix || "iex"} end prompt = @@ -338,6 +344,11 @@ defmodule IEx.Server do prompt <> " " end + defp prompt_mode(:prompt, :default), do: :default_prompt + defp prompt_mode(:prompt, :alive), do: :alive_prompt + defp prompt_mode(:continuation_prompt, :default), do: :continuation_prompt + defp prompt_mode(:continuation_prompt, :alive), do: :alive_continuation_prompt + defp io_error(result) do IO.puts(:stdio, IEx.color(:eval_error, result)) end diff --git a/lib/iex/test/iex/interaction_test.exs b/lib/iex/test/iex/interaction_test.exs index 3794ab340e..4571618f46 100644 --- a/lib/iex/test/iex/interaction_test.exs +++ b/lib/iex/test/iex/interaction_test.exs @@ -83,6 +83,11 @@ defmodule IEx.InteractionTest do assert capture_iex("1\n", opts, [], true) == "prompt(1)> 1\nprompt(2)>" end + test "continuation prompt" do + opts = [default_prompt: "%prefix(%counter)>", continuation_prompt: "%prefix(%counter)>>>"] + assert capture_iex("[\n1\n]\n", opts, [], true) == "iex(1)> ...(1)>>> ...(1)>>> [1]\niex(2)>" + end + if IO.ANSI.enabled?() do test "color" do opts = [colors: [enabled: true, eval_result: [:red]]]