Make frame and text stream updates implicit (#2451)

This commit is contained in:
Jonatan Kłosko 2024-01-26 09:17:46 +01:00 committed by GitHub
parent 8431401df1
commit 9bc0832e03
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 98 additions and 62 deletions

View file

@ -410,11 +410,11 @@ defmodule LivebookWeb.AppSessionLive do
changed_input_ids = Session.Data.changed_input_ids(data)
for {{idx, frame}, cell} <- Notebook.find_frame_outputs(data.notebook, ref) do
input_views = input_views_for_cell(cell, data, changed_input_ids)
send_update(LivebookWeb.Output.FrameComponent,
id: "outputs-#{idx}-output",
outputs: frame.outputs,
update_type: update_type,
input_views: input_views_for_cell(cell, data, changed_input_ids)
event: {:update, update_type, frame.outputs, input_views}
)
end
@ -432,7 +432,7 @@ defmodule LivebookWeb.AppSessionLive do
:markdown -> LivebookWeb.Output.MarkdownComponent
end
send_update(module, id: "outputs-#{idx}-output", text: output.text)
send_update(module, id: "outputs-#{idx}-output", event: {:append, output.text})
data_view
_ ->

View file

@ -7,19 +7,11 @@ defmodule LivebookWeb.Output.FrameComponent do
end
@impl true
def update(assigns, socket) do
{update_type, assigns} = Map.pop(assigns, :update_type, nil)
{outputs, assigns} = Map.pop!(assigns, :outputs)
socket = assign(socket, assigns)
socket = assign_new(socket, :num_outputs, fn -> length(outputs) end)
def update(%{event: {:update, update_type, outputs, input_views}}, socket) do
socket = assign(socket, input_views: input_views)
socket =
case update_type do
nil ->
stream(socket, :outputs, stream_items(outputs))
:replace ->
socket
|> assign(num_outputs: length(outputs))
@ -34,6 +26,17 @@ defmodule LivebookWeb.Output.FrameComponent do
{:ok, socket}
end
def update(assigns, socket) do
{outputs, assigns} = Map.pop!(assigns, :outputs)
socket = assign(socket, assigns)
socket = assign_new(socket, :num_outputs, fn -> length(outputs) end)
socket = stream(socket, :outputs, stream_items(outputs))
{:ok, socket}
end
defp stream_items(outputs) do
for {idx, output} <- Enum.reverse(outputs) do
%{id: Integer.to_string(idx), idx: idx, output: output}

View file

@ -5,24 +5,34 @@ defmodule LivebookWeb.Output.MarkdownComponent do
def mount(socket) do
{:ok,
socket
|> assign(allowed_uri_schemes: Livebook.Config.allowed_uri_schemes())
|> assign(allowed_uri_schemes: Livebook.Config.allowed_uri_schemes(), initialized: false)
|> stream(:chunks, [])}
end
@impl true
def update(%{event: {:append, text}}, socket) do
{:ok, append_text(socket, text)}
end
def update(assigns, socket) do
{text, assigns} = Map.pop(assigns, :text)
socket = assign(socket, assigns)
if text do
chunk = %{id: Livebook.Utils.random_long_id(), text: text}
{:ok, stream_insert(socket, :chunks, chunk)}
else
if socket.assigns.initialized do
{:ok, socket}
else
{:ok,
socket
|> append_text(text)
|> assign(:initialized, true)}
end
end
defp append_text(socket, text) do
chunk = %{id: Livebook.Utils.random_long_id(), text: text}
stream_insert(socket, :chunks, chunk)
end
@impl true
def render(assigns) do
~H"""

View file

@ -3,23 +3,36 @@ defmodule LivebookWeb.Output.PlainTextComponent do
@impl true
def mount(socket) do
{:ok, stream(socket, :chunks, [])}
{:ok,
socket
|> assign(initialized: false)
|> stream(:chunks, [])}
end
@impl true
def update(%{event: {:append, text}}, socket) do
{:ok, append_text(socket, text)}
end
def update(assigns, socket) do
{text, assigns} = Map.pop(assigns, :text)
socket = assign(socket, assigns)
if text do
chunk = %{id: Livebook.Utils.random_long_id(), text: text}
{:ok, stream_insert(socket, :chunks, chunk)}
else
if socket.assigns.initialized do
{:ok, socket}
else
{:ok,
socket
|> append_text(text)
|> assign(:initialized, true)}
end
end
defp append_text(socket, text) do
chunk = %{id: Livebook.Utils.random_long_id(), text: text}
stream_insert(socket, :chunks, chunk)
end
@impl true
def render(assigns) do
~H"""

View file

@ -5,47 +5,57 @@ defmodule LivebookWeb.Output.TerminalTextComponent do
def mount(socket) do
{:ok,
socket
|> assign(modifiers: [], last_line: nil, last_html_line: nil)
|> assign(modifiers: [], last_line: nil, last_html_line: nil, initialized: false)
|> stream(:html_lines, [])}
end
@impl true
def update(%{event: {:append, text}}, socket) do
{:ok, append_text(socket, text)}
end
def update(assigns, socket) do
{text, assigns} = Map.pop(assigns, :text)
socket = assign(socket, assigns)
if text do
text = (socket.assigns.last_line || "") <> text
text = Livebook.Notebook.normalize_terminal_text(text)
last_line =
case Livebook.Utils.split_at_last_occurrence(text, "\n") do
:error -> text
{:ok, _, last_line} -> last_line
end
{html_lines, modifiers} =
LivebookWeb.ANSIHelpers.ansi_string_to_html_lines_step(text, socket.assigns.modifiers)
{html_lines, [last_html_line]} = Enum.split(html_lines, -1)
stream_items =
for html_line <- html_lines, do: %{id: Livebook.Utils.random_long_id(), html: html_line}
socket = stream(socket, :html_lines, stream_items)
{:ok,
assign(socket,
last_html_line: last_html_line,
last_line: last_line,
modifiers: modifiers
)}
else
if socket.assigns.initialized do
{:ok, socket}
else
{:ok,
socket
|> append_text(text)
|> assign(:initialized, true)}
end
end
defp append_text(socket, text) do
text = (socket.assigns.last_line || "") <> text
text = Livebook.Notebook.normalize_terminal_text(text)
last_line =
case Livebook.Utils.split_at_last_occurrence(text, "\n") do
:error -> text
{:ok, _, last_line} -> last_line
end
{html_lines, modifiers} =
LivebookWeb.ANSIHelpers.ansi_string_to_html_lines_step(text, socket.assigns.modifiers)
{html_lines, [last_html_line]} = Enum.split(html_lines, -1)
stream_items =
for html_line <- html_lines, do: %{id: Livebook.Utils.random_long_id(), html: html_line}
socket = stream(socket, :html_lines, stream_items)
assign(socket,
last_html_line: last_html_line,
last_line: last_line,
modifiers: modifiers
)
end
@impl true
def render(assigns) do
~H"""

View file

@ -2923,14 +2923,14 @@ defmodule LivebookWeb.SessionLive do
changed_input_ids = Session.Data.changed_input_ids(data)
for {{idx, frame}, cell} <- Notebook.find_frame_outputs(data.notebook, ref) do
# Note that we are not updating data_view to avoid re-render,
# but any change that causes frame to re-render will update
# data_view first
input_views = input_views_for_cell(cell, data, changed_input_ids)
send_update(LivebookWeb.Output.FrameComponent,
id: "outputs-#{idx}-output",
outputs: frame.outputs,
update_type: update_type,
# Note that we are not updating data_view to avoid re-render,
# but any change that causes frame to re-render will update
# data_view first
input_views: input_views_for_cell(cell, data, changed_input_ids)
event: {:update, update_type, frame.outputs, input_views}
)
end
@ -2948,7 +2948,7 @@ defmodule LivebookWeb.SessionLive do
:markdown -> LivebookWeb.Output.MarkdownComponent
end
send_update(module, id: "outputs-#{idx}-output", text: output.text)
send_update(module, id: "outputs-#{idx}-output", event: {:append, output.text})
data_view
_ ->