diff --git a/lib/livebook/evaluator.ex b/lib/livebook/evaluator.ex index f6914de13..f1f895721 100644 --- a/lib/livebook/evaluator.ex +++ b/lib/livebook/evaluator.ex @@ -121,19 +121,22 @@ defmodule Livebook.Evaluator do file = Keyword.get(opts, :file, "nofile") context = put_in(context.env.file, file) - case eval(code, context.binding, context.env) do - {:ok, result, binding, env} -> - result_context = %{binding: binding, env: env} - new_contexts = Map.put(state.contexts, ref, result_context) - new_state = %{state | contexts: new_contexts} + {result_context, response} = + case eval(code, context.binding, context.env) do + {:ok, result, binding, env} -> + result_context = %{binding: binding, env: env} + response = {:ok, result} + {result_context, response} - send_evaluation_response(send_to, ref, {:ok, result}, state.formatter) - {:noreply, new_state} + {:error, kind, error, stacktrace} -> + response = {:error, kind, error, stacktrace} + {context, response} + end - {:error, kind, error, stacktrace} -> - send_evaluation_response(send_to, ref, {:error, kind, error, stacktrace}, state.formatter) - {:noreply, state} - end + send_evaluation_response(send_to, ref, response, state.formatter) + + new_state = put_in(state.contexts[ref], result_context) + {:noreply, new_state} end def handle_cast({:forget_evaluation, ref}, state) do diff --git a/test/livebook/evaluator_test.exs b/test/livebook/evaluator_test.exs index 9a9ee26d4..c9a3dbbb2 100644 --- a/test/livebook/evaluator_test.exs +++ b/test/livebook/evaluator_test.exs @@ -109,6 +109,30 @@ defmodule Livebook.EvaluatorTest do end) end + test "in case of an error uses own evaluation context as the resulting context", + %{evaluator: evaluator} do + code1 = """ + x = 2 + """ + + code2 = """ + raise ":<" + """ + + code3 = """ + x * x + """ + + Evaluator.evaluate_code(evaluator, self(), code1, :code_1) + assert_receive {:evaluation_response, :code_1, {:ok, _}} + + Evaluator.evaluate_code(evaluator, self(), code2, :code_2, :code_1) + assert_receive {:evaluation_response, :code_2, {:error, _, _, _}} + + Evaluator.evaluate_code(evaluator, self(), code3, :code_3, :code_2) + assert_receive {:evaluation_response, :code_3, {:ok, 4}} + end + test "given file option sets it in evaluation environment", %{evaluator: evaluator} do code = """ __DIR__