<%= live_component @socket, LiveBookWeb.SectionComponent,
id: section.id,
+ session_id: @session_id,
section: section,
selected: section.id == @selected_section_id,
cell_infos: @data.cell_infos,
@@ -168,6 +177,11 @@ defmodule LiveBookWeb.SessionLive do
end
@impl true
+ def handle_params(%{"cell_id" => cell_id}, _url, socket) do
+ {:ok, cell, _} = Notebook.fetch_cell_and_section(socket.assigns.data.notebook, cell_id)
+ {:noreply, assign(socket, cell: cell)}
+ end
+
def handle_params(_params, _url, socket) do
{:noreply, socket}
end
diff --git a/lib/live_book_web/live/session_live/cell_settings_component.ex b/lib/live_book_web/live/session_live/cell_settings_component.ex
new file mode 100644
index 000000000..92ad7da95
--- /dev/null
+++ b/lib/live_book_web/live/session_live/cell_settings_component.ex
@@ -0,0 +1,55 @@
+defmodule LiveBookWeb.SessionLive.CellSettingsComponent do
+ use LiveBookWeb, :live_component
+
+ alias LiveBook.Session
+
+ @impl true
+ def update(assigns, socket) do
+ metadata = assigns.cell.metadata
+
+ assigns =
+ Map.merge(assigns, %{disable_formatting: Map.get(metadata, "disable_formatting", false)})
+
+ {:ok, assign(socket, assigns)}
+ end
+
+ @impl true
+ def render(assigns) do
+ ~L"""
+
+ """
+ end
+
+ @impl true
+ def handle_event("save", params, socket) do
+ metadata = update_metadata(socket.assigns.cell.metadata, params)
+ Session.set_cell_metadata(socket.assigns.session_id, socket.assigns.cell.id, metadata)
+ {:noreply, push_patch(socket, to: socket.assigns.return_to)}
+ end
+
+ defp update_metadata(metadata, form_data) do
+ if Map.has_key?(form_data, "disable_formatting") do
+ Map.put(metadata, "disable_formatting", true)
+ else
+ Map.delete(metadata, "disable_formatting")
+ end
+ end
+end
diff --git a/lib/live_book_web/live/session_live/persistence_component.ex b/lib/live_book_web/live/session_live/persistence_component.ex
index c6e722d8d..34682a616 100644
--- a/lib/live_book_web/live/session_live/persistence_component.ex
+++ b/lib/live_book_web/live/session_live/persistence_component.ex
@@ -78,8 +78,7 @@ defmodule LiveBookWeb.SessionLive.PersistenceComponent do
path = normalize_path(socket.assigns.path)
Session.set_path(socket.assigns.session_id, path)
- {:noreply,
- push_patch(socket, to: Routes.session_path(socket, :page, socket.assigns.session_id))}
+ {:noreply, push_patch(socket, to: socket.assigns.return_to)}
end
defp default_path() do
diff --git a/lib/live_book_web/router.ex b/lib/live_book_web/router.ex
index 69c0fc0a6..931a55713 100644
--- a/lib/live_book_web/router.ex
+++ b/lib/live_book_web/router.ex
@@ -22,5 +22,6 @@ defmodule LiveBookWeb.Router do
live "/sessions/:id/file", SessionLive, :file
live "/sessions/:id/runtime", SessionLive, :runtime
live "/sessions/:id/shortcuts", SessionLive, :shortcuts
+ live "/sessions/:id/cell-settings/:cell_id", SessionLive, :cell_settings
end
end
diff --git a/test/live_book/live_markdown/export_test.exs b/test/live_book/live_markdown/export_test.exs
index da100a480..82057b725 100644
--- a/test/live_book/live_markdown/export_test.exs
+++ b/test/live_book/live_markdown/export_test.exs
@@ -295,4 +295,83 @@ defmodule LiveBook.LiveMarkdown.ExportTest do
assert expected_document == document
end
+
+ test "formats code in Elixir cells" do
+ notebook = %{
+ Notebook.new()
+ | name: "My Notebook",
+ metadata: %{},
+ sections: [
+ %{
+ Notebook.Section.new()
+ | name: "Section 1",
+ metadata: %{},
+ cells: [
+ %{
+ Notebook.Cell.new(:elixir)
+ | metadata: %{},
+ source: """
+ [1,2,3] # Comment
+ """
+ }
+ ]
+ }
+ ]
+ }
+
+ expected_document = """
+ # My Notebook
+
+ ## Section 1
+
+ ```elixir
+ # Comment
+ [1, 2, 3]
+ ```
+ """
+
+ document = Export.notebook_to_markdown(notebook)
+
+ assert expected_document == document
+ end
+
+ test "does not format code in Elixir cells which explicitly state so in metadata" do
+ notebook = %{
+ Notebook.new()
+ | name: "My Notebook",
+ metadata: %{},
+ sections: [
+ %{
+ Notebook.Section.new()
+ | name: "Section 1",
+ metadata: %{},
+ cells: [
+ %{
+ Notebook.Cell.new(:elixir)
+ | metadata: %{"disable_formatting" => true},
+ source: """
+ [1,2,3] # Comment\
+ """
+ }
+ ]
+ }
+ ]
+ }
+
+ expected_document = """
+ # My Notebook
+
+ ## Section 1
+
+
+
+ ```elixir
+ [1,2,3] # Comment
+ ```
+ """
+
+ document = Export.notebook_to_markdown(notebook)
+
+ assert expected_document == document
+ end
end
diff --git a/test/live_book/session/data_test.exs b/test/live_book/session/data_test.exs
index d3a722e37..84143c86b 100644
--- a/test/live_book/session/data_test.exs
+++ b/test/live_book/session/data_test.exs
@@ -1053,6 +1053,33 @@ defmodule LiveBook.Session.DataTest do
end
end
+ describe "apply_operation/2 given :set_cell_metadata" do
+ test "returns an error given invalid cell id" do
+ data = Data.new()
+
+ operation = {:set_cell_metadata, self(), "nonexistent", %{}}
+ assert :error = Data.apply_operation(data, operation)
+ end
+
+ test "updates cell metadata with the given map" do
+ data =
+ data_after_operations!([
+ {:insert_section, self(), 0, "s1"},
+ {:insert_cell, self(), "s1", 0, :elixir, "c1"}
+ ])
+
+ metadata = %{"disable_formatting" => true}
+ operation = {:set_cell_metadata, self(), "c1", metadata}
+
+ assert {:ok,
+ %{
+ notebook: %{
+ sections: [%{cells: [%{metadata: ^metadata}]}]
+ }
+ }, _} = Data.apply_operation(data, operation)
+ end
+ end
+
describe "apply_operation/2 given :set_runtime" do
test "updates data with the given runtime" do
data = Data.new()
diff --git a/test/live_book/session_test.exs b/test/live_book/session_test.exs
index f4b3a2b03..d536a20c5 100644
--- a/test/live_book/session_test.exs
+++ b/test/live_book/session_test.exs
@@ -112,7 +112,7 @@ defmodule LiveBook.SessionTest do
end
end
- describe "apply_cell_delta/5" do
+ describe "apply_cell_delta/4" do
test "sends a cell delta operation to subscribers", %{session_id: session_id} do
Phoenix.PubSub.subscribe(LiveBook.PubSub, "sessions:#{session_id}")
pid = self()
@@ -127,6 +127,32 @@ defmodule LiveBook.SessionTest do
end
end
+ describe "report_cell_revision/3" do
+ test "sends a revision report operation to subscribers", %{session_id: session_id} do
+ Phoenix.PubSub.subscribe(LiveBook.PubSub, "sessions:#{session_id}")
+ pid = self()
+
+ {_section_id, cell_id} = insert_section_and_cell(session_id)
+ revision = 1
+
+ Session.report_cell_revision(session_id, cell_id, revision)
+ assert_receive {:operation, {:report_cell_revision, ^pid, ^cell_id, ^revision}}
+ end
+ end
+
+ describe "set_cell_metadata/3" do
+ test "sends a metadata update operation to subscribers", %{session_id: session_id} do
+ Phoenix.PubSub.subscribe(LiveBook.PubSub, "sessions:#{session_id}")
+ pid = self()
+
+ {_section_id, cell_id} = insert_section_and_cell(session_id)
+ metadata = %{"disable_formatting" => true}
+
+ Session.set_cell_metadata(session_id, cell_id, metadata)
+ assert_receive {:operation, {:set_cell_metadata, ^pid, ^cell_id, ^metadata}}
+ end
+ end
+
describe "connect_runtime/2" do
test "sends a runtime update operation to subscribers", %{session_id: session_id} do
Phoenix.PubSub.subscribe(LiveBook.PubSub, "sessions:#{session_id}")