From d1548bd0133dca80a7530e249d15104c4e0918b0 Mon Sep 17 00:00:00 2001 From: Arnesh Date: Fri, 24 Jul 2026 16:38:09 +0530 Subject: [PATCH] repl: Show add-cell controls in empty notebooks (#61329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Objective When a notebook has no cells, the editor renders a blank pane with no visible way to add one. Cells can only be added via the toolbar icons or keybindings, which aren't discoverable from an empty editor — so a newly created `.ipynb` looks broken. This is the follow-up direction suggested in #61296. ## Solution Render an empty-state in the editor body when the notebook has no cells, with "Add code cell" / "Add markdown cell" buttons (dispatching the existing `add_code_block` / `add_markdown_block` handlers), matching the affordance VSCode provides. ## Testing Tested locally on macOS with the notebook feature enabled (`LOCAL_NOTEBOOK_DEV=1`): - Opening an empty `.ipynb` shows the empty-state instead of a blank pane. - Clicking "Add code cell" inserts an editable code cell and marks the tab dirty. ## Showcase **Before** — empty notebook renders a blank pane: ![Before: blank pane](https://raw.githubusercontent.com/ArneshBanerjee/zed-jupyter/pr-assets/61329-before.png) **After** — empty notebook shows add-cell controls: ![After: add-cell controls](https://raw.githubusercontent.com/ArneshBanerjee/zed-jupyter/pr-assets/61329-after.png) Clicking "Add code cell" inserts a cell: ![After clicking Add code cell](https://raw.githubusercontent.com/ArneshBanerjee/zed-jupyter/pr-assets/61329-after-add-cell.png) Release Notes: - N/A --------- Co-authored-by: Claude Fable 5 Co-authored-by: Finn Evers --- crates/repl/src/notebook/notebook_ui.rs | 51 ++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/crates/repl/src/notebook/notebook_ui.rs b/crates/repl/src/notebook/notebook_ui.rs index a466f2b6ee..00b1f27704 100644 --- a/crates/repl/src/notebook/notebook_ui.rs +++ b/crates/repl/src/notebook/notebook_ui.rs @@ -18,7 +18,7 @@ use language::{Language, LanguageRegistry}; use log; use project::{Project, ProjectEntryId, ProjectPath}; use settings::Settings as _; -use ui::{CommonAnimationExt, Tooltip, prelude::*}; +use ui::{CommonAnimationExt, KeyBinding, Tooltip, prelude::*}; use workspace::item::{ItemEvent, SaveOptions, TabContentParams}; use workspace::searchable::SearchableItemHandle; use workspace::{Item, ItemHandle, Pane, ProjectItem, ToolbarItemLocation}; @@ -1278,6 +1278,44 @@ impl NotebookEditor { .size_full() } + fn render_empty_state(&self, cx: &mut Context) -> impl IntoElement { + v_flex() + .size_full() + .items_center() + .justify_center() + .gap_3() + .child(Label::new("This notebook is empty.").color(Color::Muted)) + .child( + h_flex() + .gap_2() + .child( + Button::new("empty-state-add-code", "Add code cell") + .start_icon(Icon::new(IconName::Code)) + .key_binding(KeyBinding::for_action_in( + &AddCodeBlock, + &self.focus_handle, + cx, + )) + .on_click( + cx.listener(|this, _, window, cx| this.add_code_block(window, cx)), + ), + ) + .child( + Button::new("empty-state-add-markdown", "Add markdown cell") + .style(ButtonStyle::Subtle) + .start_icon(Icon::new(IconName::FileMarkdown)) + .key_binding(KeyBinding::for_action_in( + &AddMarkdownBlock, + &self.focus_handle, + cx, + )) + .on_click(cx.listener(|this, _, window, cx| { + this.add_markdown_block(window, cx) + })), + ), + ) + } + fn cell_position(&self, index: usize) -> CellPosition { match index { 0 => CellPosition::First, @@ -1477,7 +1515,16 @@ impl Render for NotebookEditor { .w_full() .h_full() .gap_2() - .child(div().flex_1().h_full().child(self.cell_list(window, cx))) + .child( + div() + .flex_1() + .h_full() + .child(if self.cell_order.is_empty() { + self.render_empty_state(cx).into_any_element() + } else { + self.cell_list(window, cx).into_any_element() + }), + ) .child(self.render_notebook_controls(window, cx)), ) .child(self.render_kernel_status_bar(window, cx))