mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-05 19:25:28 +08:00
Fix output ambiguity in livemd import/export (#892)
* Fix output ambiguity in livemd import/export * Update test/livebook/live_markdown/import_test.exs Co-authored-by: José Valim <jose.valim@dashbit.co> Co-authored-by: José Valim <jose.valim@dashbit.co>
This commit is contained in:
parent
82f70e3c96
commit
6aaf1d5b58
6 changed files with 166 additions and 10 deletions
|
@ -36,6 +36,8 @@ defmodule Livebook.LiveMarkdown do
|
|||
# - `{"break_markdown":true}` - an annotation splitting the markdown content
|
||||
# into separate Markdown cells
|
||||
#
|
||||
# - `{"output":true}` - an annotation marking a code snippet as cell output
|
||||
#
|
||||
# - section metadata, recognised keys `branch_parent_index`
|
||||
#
|
||||
# - cell metadata, recognised keys: `disable_formatting`
|
||||
|
|
|
@ -161,13 +161,17 @@ defmodule Livebook.LiveMarkdown.Export do
|
|||
text = String.replace_suffix(text, "\n", "")
|
||||
delimiter = MarkdownHelpers.code_block_delimiter(text)
|
||||
text = strip_ansi(text)
|
||||
[delimiter, "output\n", text, "\n", delimiter]
|
||||
|
||||
[delimiter, "\n", text, "\n", delimiter]
|
||||
|> prepend_metadata(%{output: true})
|
||||
end
|
||||
|
||||
defp render_output({:text, text}, _ctx) do
|
||||
delimiter = MarkdownHelpers.code_block_delimiter(text)
|
||||
text = strip_ansi(text)
|
||||
[delimiter, "output\n", text, "\n", delimiter]
|
||||
|
||||
[delimiter, "\n", text, "\n", delimiter]
|
||||
|> prepend_metadata(%{output: true})
|
||||
end
|
||||
|
||||
defp render_output(
|
||||
|
@ -180,7 +184,10 @@ defmodule Livebook.LiveMarkdown.Export do
|
|||
|
||||
case encode_js_data(payload) do
|
||||
{:ok, binary} ->
|
||||
["```", info_string, "\n", binary, "\n", "```"]
|
||||
delimiter = MarkdownHelpers.code_block_delimiter(binary)
|
||||
|
||||
[delimiter, info_string, "\n", binary, "\n", delimiter]
|
||||
|> prepend_metadata(%{output: true})
|
||||
|
||||
_ ->
|
||||
:ignored
|
||||
|
|
|
@ -180,6 +180,7 @@ defmodule Livebook.LiveMarkdown.Import do
|
|||
end
|
||||
end
|
||||
|
||||
# Import ```output snippets for backward compatibility
|
||||
defp take_outputs(
|
||||
[{"pre", _, [{"code", [{"class", "output"}], [output], %{}}], %{}} | ast],
|
||||
outputs
|
||||
|
@ -187,6 +188,29 @@ defmodule Livebook.LiveMarkdown.Import do
|
|||
take_outputs(ast, [{:text, output} | outputs])
|
||||
end
|
||||
|
||||
defp take_outputs(
|
||||
[
|
||||
{:comment, _, [~s/livebook:{"output":true}/], %{comment: true}},
|
||||
{"pre", _, [{"code", [], [output], %{}}], %{}}
|
||||
| ast
|
||||
],
|
||||
outputs
|
||||
) do
|
||||
take_outputs(ast, [{:text, output} | outputs])
|
||||
end
|
||||
|
||||
# Ignore other exported outputs
|
||||
defp take_outputs(
|
||||
[
|
||||
{:comment, _, [~s/livebook:{"output":true}/], %{comment: true}},
|
||||
{"pre", _, [{"code", [{"class", _info_string}], [_output], %{}}], %{}}
|
||||
| ast
|
||||
],
|
||||
outputs
|
||||
) do
|
||||
take_outputs(ast, outputs)
|
||||
end
|
||||
|
||||
defp take_outputs(ast, outputs), do: {outputs, ast}
|
||||
|
||||
# Builds a notebook from the list of elements obtained in the previous step.
|
||||
|
|
|
@ -584,7 +584,9 @@ defmodule Livebook.LiveMarkdown.ExportTest do
|
|||
IO.puts("hey")
|
||||
```
|
||||
|
||||
```output
|
||||
<!-- livebook:{"output":true} -->
|
||||
|
||||
```
|
||||
hey
|
||||
```
|
||||
"""
|
||||
|
@ -624,11 +626,15 @@ defmodule Livebook.LiveMarkdown.ExportTest do
|
|||
IO.puts("hey")
|
||||
```
|
||||
|
||||
```output
|
||||
<!-- livebook:{"output":true} -->
|
||||
|
||||
```
|
||||
hey
|
||||
```
|
||||
|
||||
```output
|
||||
<!-- livebook:{"output":true} -->
|
||||
|
||||
```
|
||||
:ok
|
||||
```
|
||||
"""
|
||||
|
@ -754,6 +760,8 @@ defmodule Livebook.LiveMarkdown.ExportTest do
|
|||
:ok
|
||||
```
|
||||
|
||||
<!-- livebook:{"output":true} -->
|
||||
|
||||
```mermaid
|
||||
graph TD;
|
||||
A-->B;
|
||||
|
@ -802,6 +810,8 @@ defmodule Livebook.LiveMarkdown.ExportTest do
|
|||
:ok
|
||||
```
|
||||
|
||||
<!-- livebook:{"output":true} -->
|
||||
|
||||
```box
|
||||
{"height":50,"width":50}
|
||||
```
|
||||
|
@ -853,6 +863,8 @@ defmodule Livebook.LiveMarkdown.ExportTest do
|
|||
:ok
|
||||
```
|
||||
|
||||
<!-- livebook:{"output":true} -->
|
||||
|
||||
```vega-lite
|
||||
{"height":50,"width":50}
|
||||
```
|
||||
|
@ -897,7 +909,9 @@ defmodule Livebook.LiveMarkdown.ExportTest do
|
|||
IO.puts("hey")
|
||||
```
|
||||
|
||||
```output
|
||||
<!-- livebook:{"output":true} -->
|
||||
|
||||
```
|
||||
hey
|
||||
```
|
||||
"""
|
||||
|
|
|
@ -340,6 +340,8 @@ defmodule Livebook.LiveMarkdown.ImportTest do
|
|||
Enum.to_list(1..10)
|
||||
```
|
||||
|
||||
<!-- livebook:{"force_markdown":true} -->
|
||||
|
||||
```erlang
|
||||
spawn_link(fun() -> io:format("Hiya") end).
|
||||
```
|
||||
|
@ -566,11 +568,15 @@ defmodule Livebook.LiveMarkdown.ImportTest do
|
|||
IO.puts("hey")
|
||||
```
|
||||
|
||||
```output
|
||||
<!-- livebook:{"output":true} -->
|
||||
|
||||
```
|
||||
hey
|
||||
```
|
||||
|
||||
```output
|
||||
<!-- livebook:{"output":true} -->
|
||||
|
||||
```
|
||||
:ok
|
||||
```
|
||||
"""
|
||||
|
@ -596,6 +602,63 @@ defmodule Livebook.LiveMarkdown.ImportTest do
|
|||
} = notebook
|
||||
end
|
||||
|
||||
test "discards other output snippets" do
|
||||
markdown = """
|
||||
# My Notebook
|
||||
|
||||
## Section 1
|
||||
|
||||
```elixir
|
||||
IO.puts("hey")
|
||||
```
|
||||
|
||||
```elixir
|
||||
plot()
|
||||
```
|
||||
|
||||
<!-- livebook:{"output":true} -->
|
||||
|
||||
```vega-lite
|
||||
{}
|
||||
```
|
||||
|
||||
```elixir
|
||||
:ok
|
||||
```
|
||||
"""
|
||||
|
||||
{notebook, []} = Import.notebook_from_markdown(markdown)
|
||||
|
||||
assert %Notebook{
|
||||
name: "My Notebook",
|
||||
sections: [
|
||||
%Notebook.Section{
|
||||
name: "Section 1",
|
||||
cells: [
|
||||
%Cell.Elixir{
|
||||
source: """
|
||||
IO.puts("hey")\
|
||||
""",
|
||||
outputs: []
|
||||
},
|
||||
%Cell.Elixir{
|
||||
source: """
|
||||
plot()\
|
||||
""",
|
||||
outputs: []
|
||||
},
|
||||
%Cell.Elixir{
|
||||
source: """
|
||||
:ok\
|
||||
""",
|
||||
outputs: []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
} = notebook
|
||||
end
|
||||
|
||||
test "imports notebook :persist_outputs attribute" do
|
||||
markdown = """
|
||||
<!-- livebook:{"persist_outputs":true} -->
|
||||
|
@ -654,5 +717,49 @@ defmodule Livebook.LiveMarkdown.ImportTest do
|
|||
" Also, to make the input reactive you can use an automatically reevaluating cell"
|
||||
] == messages
|
||||
end
|
||||
|
||||
test "imports snippets with output info string" do
|
||||
# We now explicitly mark every output sinppet with <!-- livebook:{"output":true} -->
|
||||
# and use empty snippets for textual outputs, however previously
|
||||
# we supported ```output too, so let's ensure they still work
|
||||
|
||||
markdown = """
|
||||
# My Notebook
|
||||
|
||||
## Section 1
|
||||
|
||||
```elixir
|
||||
IO.puts("hey")
|
||||
```
|
||||
|
||||
```output
|
||||
hey
|
||||
```
|
||||
|
||||
```output
|
||||
:ok
|
||||
```
|
||||
"""
|
||||
|
||||
{notebook, []} = Import.notebook_from_markdown(markdown)
|
||||
|
||||
assert %Notebook{
|
||||
name: "My Notebook",
|
||||
sections: [
|
||||
%Notebook.Section{
|
||||
name: "Section 1",
|
||||
cells: [
|
||||
%Cell.Elixir{
|
||||
source: """
|
||||
IO.puts("hey")\
|
||||
""",
|
||||
outputs: [{0, {:text, ":ok"}}, {1, {:text, "hey"}}]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
output_counter: 2
|
||||
} = notebook
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -114,7 +114,9 @@ defmodule LivebookWeb.SessionControllerTest do
|
|||
IO.puts("hey")
|
||||
```
|
||||
|
||||
```output
|
||||
<!-- livebook:{"output":true} -->
|
||||
|
||||
```
|
||||
hey
|
||||
```
|
||||
"""
|
||||
|
|
Loading…
Add table
Reference in a new issue