Packages
livebook
0.16.3
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Current section
Files
Jump to
Current section
Files
lib/livebook/notebook/export/elixir.ex
defmodule Livebook.Notebook.Export.Elixir do
alias Livebook.Notebook
alias Livebook.Notebook.Cell
@doc """
Converts the given notebook into a Elixir source code.
"""
@spec notebook_to_elixir(Notebook.t()) :: String.t()
def notebook_to_elixir(notebook) do
iodata = render_notebook(notebook)
# Add trailing newline
IO.iodata_to_binary([iodata, "\n"])
end
defp render_notebook(notebook) do
%{setup_section: %{cells: setup_cells} = setup_section} = notebook
prelude = "# Run as: iex --dot-iex path/to/notebook.exs"
name = ["# Title: ", notebook.name]
setup_cells = render_setup_cells(setup_cells, setup_section)
sections = Enum.map(notebook.sections, &render_section(&1, notebook))
[prelude, name | setup_cells ++ sections]
|> Enum.reject(&is_nil/1)
|> Enum.intersperse("\n\n")
end
defp render_section(section, notebook) do
name = ["# ── ", section.name, " ──"]
name =
if section.parent_id do
{:ok, parent} = Notebook.fetch_section(notebook, section.parent_id)
[name, " (⎇ from ", parent.name, ")"]
else
name
end
cells =
section.cells
|> Enum.map(&render_cell(&1, section))
|> Enum.reject(&(&1 in ["", []]))
[name | cells]
|> Enum.intersperse("\n\n")
end
defp render_setup_cells([%{source: ""}], _section), do: []
defp render_setup_cells(cells, section) do
Enum.map(cells, fn cell ->
render_cell(cell, section)
end)
end
defp render_cell(%Cell.Markdown{} = cell, _section) do
cell.source
|> Livebook.LiveMarkdown.MarkdownHelpers.reformat()
|> String.split("\n")
|> Enum.map_intersperse("\n", &comment_out/1)
end
defp render_cell(%Cell.Code{language: :elixir} = cell, section) do
if section.parent_id do
cell.source
|> String.split("\n")
|> Enum.map_intersperse("\n", &comment_out/1)
else
cell.source
end
end
defp render_cell(%Cell.Code{language: :"pyproject.toml"} = cell, section) do
code =
{:__block__, [],
[
{{:., [], [{:__aliases__, [alias: false], [:Pythonx]}, :uv_init]}, [],
[{:<<>>, [delimiter: ~s["""]], [cell.source <> "\n"]}]},
{:import, [], [{:__aliases__, [], [:Pythonx]}]}
]}
|> Code.quoted_to_algebra()
|> Inspect.Algebra.format(90)
|> IO.iodata_to_binary()
render_cell(%{cell | language: :elixir, source: code}, section)
end
defp render_cell(%Cell.Code{language: :python} = cell, section) do
code =
{:sigil_PY, [delimiter: ~s["""]], [{:<<>>, [], [cell.source <> "\n"]}, []]}
|> Code.quoted_to_algebra()
|> Inspect.Algebra.format(90)
|> IO.iodata_to_binary()
render_cell(%{cell | language: :elixir, source: code}, section)
end
defp render_cell(%Cell.Code{} = cell, _section) do
code = cell.source
code
|> String.split("\n")
|> Enum.map_intersperse("\n", &comment_out/1)
end
defp render_cell(%Cell.Smart{} = cell, ctx) do
render_cell(%{Cell.Code.new() | source: cell.source}, ctx)
end
defp render_cell(_cell, _section), do: []
defp comment_out(""), do: ""
defp comment_out(line), do: ["# ", line]
end