defmodule LivebookWeb.CellComponent do use LivebookWeb, :live_component def render(assigns) do ~L"""
<%= render_cell_content(assigns) %>
""" end def render_cell_content(%{cell: %{type: :markdown}} = assigns) do ~L"""
<%= render_editor(@cell, @cell_info) %>
<%= render_markdown_content_placeholder(@cell.source) %>
""" end def render_cell_content(%{cell: %{type: :elixir}} = assigns) do ~L"""
<%= if @cell_info.evaluation_status == :ready do %> <% else %> <% end %>
<%= live_patch to: Routes.session_path(@socket, :cell_settings, @session_id, @cell.id) do %> <%= remix_icon("list-settings-line", class: "text-xl action-icon") %> <% end %>
<%= render_editor(@cell, @cell_info, show_status: true) %> <%= if @cell.outputs != [] do %>
<%= render_outputs(@cell.outputs, @cell.id) %>
<% end %>
""" end defp render_editor(cell, cell_info, opts \\ []) do show_status = Keyword.get(opts, :show_status, false) assigns = %{cell: cell, cell_info: cell_info, show_status: show_status} ~L"""
<%= render_editor_content_placeholder(@cell.source) %>
<%= if @show_status do %>
<%= render_cell_status(@cell_info) %>
<% end %>
""" end # The whole page has to load and then hooks are mounded. # There may be a tiny delay before the markdown is rendered # or and editors are mounted, so show neat placeholders immediately. defp render_markdown_content_placeholder("" = _content) do assigns = %{} ~L"""
""" end defp render_markdown_content_placeholder(_content) do assigns = %{} ~L"""
""" end defp render_editor_content_placeholder("" = _content) do assigns = %{} ~L"""
""" end defp render_editor_content_placeholder(_content) do assigns = %{} ~L"""
""" end defp render_outputs(outputs, cell_id) do assigns = %{outputs: outputs, cell_id: cell_id} ~L"""
<%= for {output, index} <- @outputs |> Enum.reverse() |> Enum.with_index(), output != :ignored do %>
<%= render_output(output, "#{@cell_id}-output#{index}") %>
<% end %>
""" end defp render_output(output, id) when is_binary(output) do lines = ansi_to_html_lines(output) assigns = %{lines: lines, id: id} ~L"""
""" end defp render_output({:inspect, inspected}, id) do lines = ansi_to_html_lines(inspected) assigns = %{lines: lines, id: id} ~L"""
""" end defp render_output({:error, formatted}, _id) do assigns = %{formatted: formatted} ~L"""
<%= @formatted %>
""" end defp ansi_to_html_lines(string) do string |> ansi_string_to_html( # Make sure every line is styled separately, # so tht later we can safely split the whole HTML # into valid HTML lines. renderer: fn style, content -> content |> IO.iodata_to_binary() |> String.split("\n") |> Enum.map(&[~s{}, &1, ~s{}]) |> Enum.intersperse("\n") end ) |> Phoenix.HTML.safe_to_string() |> String.split("\n") end defp render_cell_status(%{evaluation_status: :evaluating}) do assigns = %{} ~L"""
Evaluating
""" end defp render_cell_status(%{evaluation_status: :queued}) do assigns = %{} ~L"""
Queued
""" end defp render_cell_status(%{validity_status: :evaluated}) do assigns = %{} ~L"""
Evaluated
""" end defp render_cell_status(%{validity_status: :stale}) do assigns = %{} ~L"""
Stale
""" end defp render_cell_status(_), do: nil end