Suggest restarting runtime on Mix.install error and add restart shortcut (#418)

* Suggest restarting runtime on Mix.install error and add restart shortcut

* Apply review comments
This commit is contained in:
Jonatan Kłosko 2021-07-01 13:23:07 +02:00 committed by GitHub
parent 6515629156
commit 20ff5c95b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 81 additions and 4 deletions

View file

@ -301,6 +301,8 @@ function handleDocumentKeyDown(hook, event) {
showBin(hook);
} else if (keyBuffer.tryMatch(["e", "x"])) {
cancelFocusedCellEvaluation(hook);
} else if (keyBuffer.tryMatch(["0", "0"])) {
restartRuntime(hook);
} else if (keyBuffer.tryMatch(["?"])) {
showShortcuts(hook);
} else if (keyBuffer.tryMatch(["i"])) {
@ -594,6 +596,10 @@ function cancelFocusedCellEvaluation(hook) {
}
}
function restartRuntime(hook) {
hook.pushEvent("restart_runtime", {});
}
function showShortcuts(hook) {
hook.pushEvent("show_shortcuts", {});
}

View file

@ -27,7 +27,7 @@ defmodule Livebook.Evaluator.DefaultFormatter do
def format_response({:error, kind, error, stacktrace}) do
formatted = Exception.format(kind, error, stacktrace)
{:error, formatted}
{:error, formatted, error_type(error)}
end
@compile {:no_warn_undefined, {Kino.Render, :to_livebook, 1}}
@ -80,4 +80,17 @@ defmodule Livebook.Evaluator.DefaultFormatter do
reset: :reset
]
end
defp error_type(error) do
cond do
mix_install_vm_error?(error) -> :runtime_restart_required
true -> :other
end
end
defp mix_install_vm_error?(exception) do
is_struct(exception, Mix.Error) and
Exception.message(exception) =~
"Mix.install/2 can only be called with the same dependencies"
end
end

View file

@ -38,7 +38,7 @@ defmodule Livebook.Notebook.Cell.Elixir do
# Interactive data table
| {:table_dynamic, widget_process :: pid()}
# Internal output format for errors
| {:error, message :: binary()}
| {:error, message :: binary(), type :: :other | :runtime_restart_required}
@doc """
Returns an empty cell.

View file

@ -106,4 +106,10 @@ defprotocol Livebook.Runtime do
container_ref,
evaluation_ref
)
@doc """
Synchronously starts a runtime of the same type with the same parameters.
"""
@spec duplicate(Runtime.t()) :: {:ok, Runtime.t()} | {:error, String.t()}
def duplicate(runtime)
end

View file

@ -89,4 +89,8 @@ defimpl Livebook.Runtime, for: Livebook.Runtime.Attached do
evaluation_ref
)
end
def duplicate(_runtime) do
{:error, "attached runtime is connected to a specific VM and cannot be duplicated"}
end
end

View file

@ -113,4 +113,8 @@ defimpl Livebook.Runtime, for: Livebook.Runtime.ElixirStandalone do
evaluation_ref
)
end
def duplicate(_runtime) do
Livebook.Runtime.ElixirStandalone.init()
end
end

View file

@ -95,4 +95,9 @@ defimpl Livebook.Runtime, for: Livebook.Runtime.Embedded do
evaluation_ref
)
end
def duplicate(_runtime) do
{:error,
"embedded runtime is connected to the Livebook application VM and cannot be duplicated"}
end
end

View file

@ -166,4 +166,8 @@ defimpl Livebook.Runtime, for: Livebook.Runtime.MixStandalone do
evaluation_ref
)
end
def duplicate(runtime) do
Livebook.Runtime.MixStandalone.init(runtime.project_path)
end
end

View file

@ -566,6 +566,24 @@ defmodule LivebookWeb.SessionLive do
push_patch(socket, to: Routes.session_path(socket, :bin, socket.assigns.session_id))}
end
def handle_event("restart_runtime", %{}, socket) do
socket =
if runtime = socket.private.data.runtime do
case Runtime.duplicate(runtime) do
{:ok, new_runtime} ->
Session.connect_runtime(socket.assigns.session_id, new_runtime)
socket
{:error, message} ->
put_flash(socket, :error, "Failed to setup runtime - #{message}")
end
else
socket
end
{:noreply, socket}
end
def handle_event("completion_request", %{"hint" => hint, "cell_id" => cell_id}, socket) do
data = socket.private.data

View file

@ -337,7 +337,22 @@ defmodule LivebookWeb.SessionLive.CellComponent do
)
end
defp render_output(_socket, {:error, formatted}, _id) do
defp render_output(_socket, {:error, formatted, :runtime_restart_required}, _id) do
assigns = %{formatted: formatted}
~L"""
<div class="flex flex-col space-y-4">
<%= render_error_message_output(@formatted) %>
<div>
<button class="button button-gray" phx-click="restart_runtime">
Restart runtime
</button>
</div>
</div>
"""
end
defp render_output(_socket, {:error, formatted, _type}, _id) do
render_error_message_output(formatted)
end

View file

@ -44,7 +44,8 @@ defmodule LivebookWeb.SessionLive.ShortcutsComponent do
%{seq: ["s", "s"], desc: "Toggle sections panel"},
%{seq: ["s", "u"], desc: "Toggle users panel"},
%{seq: ["s", "r"], desc: "Show runtime settings"},
%{seq: ["s", "b"], desc: "Show bin"}
%{seq: ["s", "b"], desc: "Show bin"},
%{seq: ["0", "0"], desc: "Restart current runtime"}
],
universal: [
%{seq: ["ctrl", "s"], seq_mac: ["", "s"], press_all: true, desc: "Save notebook"}

View file

@ -15,5 +15,6 @@ defmodule Livebook.Runtime.NoopRuntime do
def forget_evaluation(_, _, _), do: :ok
def drop_container(_, _), do: :ok
def request_completion_items(_, _, _, _, _, _), do: :ok
def duplicate(_), do: {:ok, Livebook.Runtime.NoopRuntime.new()}
end
end