Skip to content

Commit de33d57

Browse files
committed
Do not perform completion on evaluated prompts, closes #12191
1 parent 4779459 commit de33d57

File tree

4 files changed

+43
-59
lines changed

4 files changed

+43
-59
lines changed

lib/iex/lib/iex.ex

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -858,8 +858,8 @@ defmodule IEx do
858858
_ -> :init.wait_until_started()
859859
end
860860

861+
:ok = :io.setopts(binary: true, encoding: :unicode)
861862
:ok = start_iex()
862-
:ok = set_expand_fun()
863863
:ok = run_after_spawn()
864864
IEx.Server.run_from_shell(opts, mfa)
865865
end)
@@ -875,23 +875,6 @@ defmodule IEx do
875875
:ok
876876
end
877877

878-
defp set_expand_fun do
879-
gl = Process.group_leader()
880-
881-
expand_fun =
882-
if node(gl) != node() do
883-
IEx.Autocomplete.remsh(node())
884-
else
885-
&IEx.Autocomplete.expand/1
886-
end
887-
888-
# expand_fun is not supported by a shell variant
889-
# on Windows, so we do two IO calls, not caring
890-
# about the result of the expand_fun one.
891-
_ = :io.setopts(gl, expand_fun: expand_fun)
892-
:io.setopts(gl, binary: true, encoding: :unicode)
893-
end
894-
895878
defp run_after_spawn do
896879
_ = for fun <- Enum.reverse(after_spawn()), do: fun.()
897880
:ok

lib/iex/lib/iex/evaluator.ex

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,9 @@ defmodule IEx.Evaluator do
183183

184184
defp loop(%{server: server, ref: ref} = state) do
185185
receive do
186-
{:eval, ^server, code, iex_state} ->
187-
{result, status, state} = parse_eval_inspect(code, iex_state, state)
188-
send(server, {:evaled, self(), status, result})
186+
{:eval, ^server, code, counter, parser_state} ->
187+
{status, parser_state, state} = parse_eval_inspect(code, counter, parser_state, state)
188+
send(server, {:evaled, self(), status, parser_state})
189189
loop(state)
190190

191191
{:fields_from_env, ^server, ref, receiver, fields} ->
@@ -285,30 +285,30 @@ defmodule IEx.Evaluator do
285285
end
286286
end
287287

288-
defp parse_eval_inspect(code, iex_state, state) do
288+
defp parse_eval_inspect(code, counter, parser_state, state) do
289289
try do
290290
{parser_module, parser_fun, args} = IEx.Config.parser()
291-
args = [code, [line: iex_state.counter, file: "iex"], iex_state.parser_state | args]
292-
eval_and_inspect_parsed(apply(parser_module, parser_fun, args), iex_state, state)
291+
args = [code, [line: counter, file: "iex"], parser_state | args]
292+
eval_and_inspect_parsed(apply(parser_module, parser_fun, args), counter, state)
293293
catch
294294
kind, error ->
295295
print_error(kind, error, __STACKTRACE__)
296-
{%{iex_state | parser_state: ""}, :ok, state}
296+
{:error, "", state}
297297
end
298298
end
299299

300-
defp eval_and_inspect_parsed({:ok, forms, parser_state}, iex_state, state) do
300+
defp eval_and_inspect_parsed({:ok, forms, parser_state}, counter, state) do
301301
put_history(state)
302302
put_whereami(state)
303-
state = eval_and_inspect(forms, iex_state.counter, state)
304-
{%{iex_state | parser_state: parser_state, counter: iex_state.counter + 1}, :ok, state}
303+
state = eval_and_inspect(forms, counter, state)
304+
{:ok, parser_state, state}
305305
after
306306
Process.delete(:iex_history)
307307
Process.delete(:iex_whereami)
308308
end
309309

310-
defp eval_and_inspect_parsed({:incomplete, parser_state}, iex_state, state) do
311-
{%{iex_state | parser_state: parser_state}, :incomplete, state}
310+
defp eval_and_inspect_parsed({:incomplete, parser_state}, _counter, state) do
311+
{:incomplete, parser_state, state}
312312
end
313313

314314
defp put_history(%{history: history}) do

lib/iex/lib/iex/server.ex

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,3 @@
1-
defmodule IEx.State do
2-
@moduledoc false
3-
# This state is exchanged between IEx.Server and
4-
# IEx.Evaluator which is why it is a struct.
5-
defstruct parser_state: "",
6-
counter: 1,
7-
prefix: "iex",
8-
on_eof: :stop_evaluator,
9-
evaluator_options: [],
10-
previous_state: nil
11-
12-
@type t :: %{
13-
__struct__: __MODULE__,
14-
parser_state: binary(),
15-
counter: pos_integer(),
16-
prefix: binary(),
17-
on_eof: :stop_evaluator | :halt,
18-
evaluator_options: keyword(),
19-
previous_state: nil | t()
20-
}
21-
end
22-
231
defmodule IEx.Server do
242
@moduledoc """
253
The IEx.Server.
@@ -32,6 +10,15 @@ defmodule IEx.Server do
3210
3311
"""
3412

13+
@doc false
14+
defstruct parser_state: "",
15+
counter: 1,
16+
prefix: "iex",
17+
on_eof: :stop_evaluator,
18+
evaluator_options: [],
19+
expand_fun: nil,
20+
previous_state: nil
21+
3522
@doc """
3623
Starts a new IEx server session.
3724
@@ -137,14 +124,16 @@ defmodule IEx.Server do
137124
write_prompt(:prompt, state.prefix, counter)
138125
end
139126

127+
:io.setopts(expand_fun: state.expand_fun)
140128
input = input || io_get()
141129
wait_input(state, evaluator, evaluator_ref, input)
142130
end
143131

144132
defp wait_input(state, evaluator, evaluator_ref, input) do
145133
receive do
146134
{:io_reply, ^input, code} when is_binary(code) ->
147-
send(evaluator, {:eval, self(), code, state})
135+
:io.setopts(expand_fun: fn _ -> {:yes, [], []} end)
136+
send(evaluator, {:eval, self(), code, state.counter, state.parser_state})
148137
wait_eval(state, evaluator, evaluator_ref)
149138

150139
{:io_reply, ^input, :eof} ->
@@ -176,8 +165,10 @@ defmodule IEx.Server do
176165

177166
defp wait_eval(state, evaluator, evaluator_ref) do
178167
receive do
179-
{:evaled, ^evaluator, status, new_state} ->
180-
loop(new_state, status, evaluator, evaluator_ref, nil)
168+
{:evaled, ^evaluator, status, parser_state} ->
169+
counter = if(status == :ok, do: state.counter + 1, else: state.counter)
170+
state = %{state | counter: counter, parser_state: parser_state}
171+
loop(state, status, evaluator, evaluator_ref, nil)
181172

182173
msg ->
183174
handle_take_over(msg, state, evaluator, evaluator_ref, nil, fn state ->
@@ -358,9 +349,19 @@ defmodule IEx.Server do
358349
prefix = Keyword.get(opts, :prefix, "iex")
359350
on_eof = Keyword.get(opts, :on_eof, :stop_evaluator)
360351

361-
%IEx.State{
352+
gl = Process.group_leader()
353+
354+
expand_fun =
355+
if node(gl) != node() do
356+
IEx.Autocomplete.remsh(node())
357+
else
358+
&IEx.Autocomplete.expand/1
359+
end
360+
361+
%IEx.Server{
362362
prefix: prefix,
363363
on_eof: on_eof,
364+
expand_fun: expand_fun,
364365
previous_state: Keyword.get(opts, :previous_state),
365366
evaluator_options: Keyword.take(opts, [:dot_iex_path])
366367
}

lib/iex/test/iex/autocomplete_test.exs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ defmodule IEx.AutocompleteTest do
1313
ExUnit.CaptureIO.capture_io(fn ->
1414
evaluator = Process.get(:evaluator)
1515
Process.group_leader(evaluator, Process.group_leader())
16-
send(evaluator, {:eval, self(), line <> "\n", %IEx.State{}})
16+
send(evaluator, {:eval, self(), line <> "\n", 1, ""})
1717
assert_receive {:evaled, _, _, _}
1818
end)
1919
end
@@ -391,11 +391,11 @@ defmodule IEx.AutocompleteTest do
391391
assert {:yes, ~c"", entries} = expand(~c"%")
392392
assert ~c"URI" in entries
393393
assert ~c"IEx.History" in entries
394-
assert ~c"IEx.State" in entries
394+
assert ~c"IEx.Server" in entries
395395

396396
assert {:yes, ~c"", entries} = expand(~c"%IEx.")
397397
assert ~c"IEx.History" in entries
398-
assert ~c"IEx.State" in entries
398+
assert ~c"IEx.Server" in entries
399399

400400
assert expand(~c"%IEx.AutocompleteTe") == {:yes, ~c"st.MyStruct{", []}
401401
assert expand(~c"%IEx.AutocompleteTest.MyStr") == {:yes, ~c"uct{", []}

0 commit comments

Comments
 (0)