diff --git a/src/snapshots/rdbms_playground__ui__tests__default_advanced_dark.snap b/src/snapshots/rdbms_playground__ui__tests__default_advanced_dark.snap index 8bc79f9..46a7503 100644 --- a/src/snapshots/rdbms_playground__ui__tests__default_advanced_dark.snap +++ b/src/snapshots/rdbms_playground__ui__tests__default_advanced_dark.snap @@ -1,29 +1,29 @@ --- source: src/ui.rs -assertion_line: 1540 +assertion_line: 2326 expression: snapshot --- -╭ Tables ──────────────────╮╭ Output ──────────────────────────────────────────╮ -│(none yet) ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ ADVANCED ────────────────────────────────────────╮ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ Hint ────────────────────────────────────────────╮ -│ ││Type a command — press Tab for options, `help` │ -│ ││for a list │ -╰──────────────────────────╯╰──────────────────────────────────────────────────╯ +╭ Output ──────────────────────────────────────────────────────────────────────╮ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ +╭ ADVANCED ────────────────────────────────────────────────────────────────────╮ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ +╭ Hint ────────────────────────────────────────────────────────────────────────╮ +│Type a command — press Tab for options, `help` for a list │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ Project: Term Planner Enter submit · mode simple switch · Ctrl-C quit diff --git a/src/snapshots/rdbms_playground__ui__tests__default_simple_dark.snap b/src/snapshots/rdbms_playground__ui__tests__default_simple_dark.snap index 51a442a..c49a798 100644 --- a/src/snapshots/rdbms_playground__ui__tests__default_simple_dark.snap +++ b/src/snapshots/rdbms_playground__ui__tests__default_simple_dark.snap @@ -1,29 +1,29 @@ --- source: src/ui.rs -assertion_line: 1523 +assertion_line: 2309 expression: snapshot --- -╭ Tables ──────────────────╮╭ Output ──────────────────────────────────────────╮ -│(none yet) ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ SIMPLE ──────────────────────────────────────────╮ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ Hint ────────────────────────────────────────────╮ -│ ││Type a command — press Tab for options, `help` │ -│ ││for a list │ -╰──────────────────────────╯╰──────────────────────────────────────────────────╯ +╭ Output ──────────────────────────────────────────────────────────────────────╮ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ +╭ SIMPLE ──────────────────────────────────────────────────────────────────────╮ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ +╭ Hint ────────────────────────────────────────────────────────────────────────╮ +│Type a command — press Tab for options, `help` for a list │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ Project: Term Planner Enter submit · : advanced once · mode advanced switch · Ctrl-C quit diff --git a/src/snapshots/rdbms_playground__ui__tests__default_simple_light.snap b/src/snapshots/rdbms_playground__ui__tests__default_simple_light.snap index 7253e06..4a41ef7 100644 --- a/src/snapshots/rdbms_playground__ui__tests__default_simple_light.snap +++ b/src/snapshots/rdbms_playground__ui__tests__default_simple_light.snap @@ -1,29 +1,29 @@ --- source: src/ui.rs -assertion_line: 1531 +assertion_line: 2317 expression: snapshot --- -╭ Tables ──────────────────╮╭ Output ──────────────────────────────────────────╮ -│(none yet) ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ SIMPLE ──────────────────────────────────────────╮ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ Hint ────────────────────────────────────────────╮ -│ ││Type a command — press Tab for options, `help` │ -│ ││for a list │ -╰──────────────────────────╯╰──────────────────────────────────────────────────╯ +╭ Output ──────────────────────────────────────────────────────────────────────╮ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ +╭ SIMPLE ──────────────────────────────────────────────────────────────────────╮ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ +╭ Hint ────────────────────────────────────────────────────────────────────────╮ +│Type a command — press Tab for options, `help` for a list │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ Project: Term Planner Enter submit · : advanced once · mode advanced switch · Ctrl-C quit diff --git a/src/snapshots/rdbms_playground__ui__tests__highlighted_input_all_token_classes_dark.snap b/src/snapshots/rdbms_playground__ui__tests__highlighted_input_all_token_classes_dark.snap index ec4f4bf..34a6f6a 100644 --- a/src/snapshots/rdbms_playground__ui__tests__highlighted_input_all_token_classes_dark.snap +++ b/src/snapshots/rdbms_playground__ui__tests__highlighted_input_all_token_classes_dark.snap @@ -1,29 +1,29 @@ --- source: src/ui.rs -assertion_line: 2063 +assertion_line: 2369 expression: snapshot --- -╭ Tables ──────────────────╮╭ Output ──────────────────────────────────────────╮ -│(none yet) ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ SIMPLE ──────────────────────────────────────────╮ -│ ││ [([, ...])] [values] ([, ...]) │ +╰──────────────────────────────────────────────────────────────────────────────╯ Project: Term Planner Enter submit · : advanced once · mode advanced switch · Ctrl-C quit diff --git a/src/snapshots/rdbms_playground__ui__tests__one_shot_advanced_dark.snap b/src/snapshots/rdbms_playground__ui__tests__one_shot_advanced_dark.snap index 82e536b..5afcd79 100644 --- a/src/snapshots/rdbms_playground__ui__tests__one_shot_advanced_dark.snap +++ b/src/snapshots/rdbms_playground__ui__tests__one_shot_advanced_dark.snap @@ -1,29 +1,29 @@ --- source: src/ui.rs -assertion_line: 1992 +assertion_line: 2385 expression: snapshot --- -╭ Tables ──────────────────╮╭ Output ──────────────────────────────────────────╮ -│(none yet) ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ Advanced: ───────────────────────────────────────╮ -│ ││: sel │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ Hint ────────────────────────────────────────────╮ -│ ││select │ -│ ││ │ -╰──────────────────────────╯╰──────────────────────────────────────────────────╯ +╭ Output ──────────────────────────────────────────────────────────────────────╮ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ +╭ Advanced: ───────────────────────────────────────────────────────────────────╮ +│: sel │ +╰──────────────────────────────────────────────────────────────────────────────╯ +╭ Hint ────────────────────────────────────────────────────────────────────────╮ +│select │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ Project: Term Planner Enter submit · Backspace cancel one-shot · Ctrl-C quit diff --git a/src/snapshots/rdbms_playground__ui__tests__populated_with_table_dark.snap b/src/snapshots/rdbms_playground__ui__tests__populated_with_table_dark.snap index 4536ba5..aac58e2 100644 --- a/src/snapshots/rdbms_playground__ui__tests__populated_with_table_dark.snap +++ b/src/snapshots/rdbms_playground__ui__tests__populated_with_table_dark.snap @@ -1,29 +1,29 @@ --- source: src/ui.rs -assertion_line: 1841 +assertion_line: 2589 expression: snapshot --- -╭ Tables ──────────────────╮╭ Output ──────────────────────────────────────────╮ -│Customers ││[simple] create table Customers ✓ │ -│Orders ││[system] Customers │ -│ ││[system] id serial [PK] │ -│ ││[system] Name text │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ SIMPLE ──────────────────────────────────────────╮ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ Hint ────────────────────────────────────────────╮ -│ ││Type a command — press Tab for options, `help` │ -│ ││for a list │ -╰──────────────────────────╯╰──────────────────────────────────────────────────╯ -Project: Term Planner +╭ Tables ──────────────────╮╭ Output ────────────────────────────────────────────────────────────────────────╮ +│Customers ││[simple] create table Customers ✓ │ +│Orders ││[system] Customers │ +│ ││[system] id serial [PK] │ +│ ││[system] Name text │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ │╰────────────────────────────────────────────────────────────────────────────────╯ +│ │╭ SIMPLE ────────────────────────────────────────────────────────────────────────╮ +│ ││ │ +│ │╰────────────────────────────────────────────────────────────────────────────────╯ +│ │╭ Hint ──────────────────────────────────────────────────────────────────────────╮ +│ ││Type a command — press Tab for options, `help` for a list │ +│ ││ │ +╰──────────────────────────╯╰────────────────────────────────────────────────────────────────────────────────╯ +Project: Term Planner Enter submit · : advanced once · mode advanced switch · Ctrl-C quit diff --git a/src/snapshots/rdbms_playground__ui__tests__rebuild_confirm_modal_dark.snap b/src/snapshots/rdbms_playground__ui__tests__rebuild_confirm_modal_dark.snap index 8b3a591..2b36e30 100644 --- a/src/snapshots/rdbms_playground__ui__tests__rebuild_confirm_modal_dark.snap +++ b/src/snapshots/rdbms_playground__ui__tests__rebuild_confirm_modal_dark.snap @@ -1,15 +1,15 @@ --- source: src/ui.rs -assertion_line: 1613 +assertion_line: 2399 expression: snapshot --- -╭ Tables ──────────────────╮╭ Output ──────────────────────────────────────────╮ -│(none yet) ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ +╭ Output ──────────────────────────────────────────────────────────────────────╮ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ │ ╭ Rebuild project ─────────────────────────────────────────╮ │ │ │ │ │ │ │3 tables and 47 rows will be reconstructed; the existing │ │ @@ -17,13 +17,13 @@ expression: snapshot │ │ │ │ │ │Continue? │ │ │ │ │ │ -│ │[Y] Yes [N] No Esc cancel │─────────╯ -│ ╰──────────────────────────────────────────────────────────╯─────────╮ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ Hint ────────────────────────────────────────────╮ -│ ││Type a command — press Tab for options, `help` │ -│ ││for a list │ -╰──────────────────────────╯╰──────────────────────────────────────────────────╯ +╰─────────│[Y] Yes [N] No Esc cancel │─────────╯ +╭ SIMPLE ─╰──────────────────────────────────────────────────────────╯─────────╮ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ +╭ Hint ────────────────────────────────────────────────────────────────────────╮ +│Type a command — press Tab for options, `help` for a list │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ Project: Term Planner Enter submit · : advanced once · mode advanced switch · Ctrl-C quit diff --git a/src/snapshots/rdbms_playground__ui__tests__two_row_input_dark.snap b/src/snapshots/rdbms_playground__ui__tests__two_row_input_dark.snap index 91f7646..9168780 100644 --- a/src/snapshots/rdbms_playground__ui__tests__two_row_input_dark.snap +++ b/src/snapshots/rdbms_playground__ui__tests__two_row_input_dark.snap @@ -1,49 +1,49 @@ --- source: src/ui.rs -assertion_line: 2210 +assertion_line: 2265 expression: snapshot --- -╭ Tables ──────────────────╮╭ Output ──────────────────────────────────────────╮ -│(none yet) ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ ││ │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ SIMPLE ──────────────────────────────────────────╮ -│ ││select * from Customers where id = 12345 and │ -│ ││ name = 'Alice Wonderland' │ -│ │╰──────────────────────────────────────────────────╯ -│ │╭ Hint ────────────────────────────────────────────╮ -│ ││`select` is SQL — available in advanced mode. │ -│ ││Switch with `mode advanced`, or prefix the line │ -│ ││with `:` to run it once. │ -╰──────────────────────────╯╰──────────────────────────────────────────────────╯ -Project: Term Planner -Enter submit · : advanced once · mode advanced switch · Ctrl-C quit +╭ Output ──────────────────────────────────────────────────╮ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰──────────────────────────────────────────────────────────╯ +╭ SIMPLE ──────────────────────────────────────────────────╮ +│select * from Customers where id = 12345 and name = │ +│'Alice Wonderland' │ +╰──────────────────────────────────────────────────────────╯ +╭ Hint ────────────────────────────────────────────────────╮ +│`select` is SQL — available in advanced mode. Switch │ +│with `mode advanced`, or prefix the line with `:` to run… │ +╰──────────────────────────────────────────────────────────╯ +Project: Term Planner +Enter submit · : advanced once · mode advanced switch · diff --git a/src/ui.rs b/src/ui.rs index 23ece83..5642d48 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -23,6 +23,19 @@ use crate::theme::Theme; /// computation — without that feedback, scrolling past the top /// of the buffer would slide the visible window off and /// "eat" lines from the bottom on subsequent renders. +/// Minimum terminal width at which the schema sidebar (the left items +/// column) is shown by default (ADR-0046 DB1). At or below this the +/// sidebar is hidden so the output/input panels get the full width — +/// notably the 90-column screencasts. Tunable. +const SIDEBAR_MIN_WIDTH: u16 = 90; + +/// Whether the schema sidebar is visible — a pure function of terminal +/// width (ADR-0046 DB1). Phase C will also reveal it while a sidebar +/// panel is focused via the Ctrl-O peek. +const fn sidebar_visible(total_width: u16) -> bool { + total_width > SIDEBAR_MIN_WIDTH +} + pub fn render(app: &mut App, theme: &Theme, frame: &mut Frame<'_>) { let area = frame.area(); paint_background(theme, frame, area); @@ -39,13 +52,19 @@ pub fn render(app: &mut App, theme: &Theme, frame: &mut Frame<'_>) { ]) .split(area); - let columns = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Length(28), Constraint::Min(20)]) - .split(outer[0]); - - render_items_panel(app, theme, frame, columns[0]); - render_right_column(app, theme, frame, columns[1]); + // ADR-0046 DB1: on a wide terminal the schema sidebar takes a fixed + // left column; at or below SIDEBAR_MIN_WIDTH it is hidden and the + // right column spans the full width. + if sidebar_visible(area.width) { + let columns = Layout::default() + .direction(Direction::Horizontal) + .constraints([Constraint::Length(28), Constraint::Min(20)]) + .split(outer[0]); + render_items_panel(app, theme, frame, columns[0]); + render_right_column(app, theme, frame, columns[1]); + } else { + render_right_column(app, theme, frame, outer[0]); + } render_project_label(app, theme, frame, outer[1]); render_status_bar(app, theme, frame, outer[2]); @@ -2132,7 +2151,8 @@ mod tests { app.input.push_str(LONG_INPUT); app.input_cursor = app.input.len(); let theme = Theme::dark(); - let out = render_to_string(&mut app, &theme, 80, 24); + // Narrow (sidebar hidden, DB1) so the line overflows the field. + let out = render_to_string(&mut app, &theme, 60, 24); assert!( out.contains("'Alice Wonderland'"), "the tail around the cursor must be visible:\n{out}" @@ -2152,7 +2172,8 @@ mod tests { app.input.push_str(LONG_INPUT); app.input_cursor = 0; let theme = Theme::dark(); - let out = render_to_string(&mut app, &theme, 80, 24); + // Narrow (sidebar hidden, DB1) so the line overflows the field. + let out = render_to_string(&mut app, &theme, 60, 24); assert!(out.contains("select * from"), "head visible at Home:\n{out}"); assert!(out.contains('>'), "a right scroll marker signals the hidden tail:\n{out}"); assert!(!out.contains("Wonderland"), "the tail must be scrolled off:\n{out}"); @@ -2169,7 +2190,9 @@ mod tests { app.input.push_str(LONG_INPUT); app.input_cursor = app.input.len(); let theme = Theme::dark(); - let out = render_to_string(&mut app, &theme, 80, 44); + // Narrow (sidebar hidden, DB1) so the line wraps across the two + // rows rather than fitting on the first. + let out = render_to_string(&mut app, &theme, 60, 44); let head = out .lines() .position(|l| l.contains("select * from Customers")); @@ -2193,7 +2216,8 @@ mod tests { app.input.push_str(LONG_INPUT); app.input_cursor = app.input.len(); let theme = Theme::dark(); - let out = render_to_string(&mut app, &theme, 50, 44); + // Very narrow + tall: two rows, but the line exceeds both. + let out = render_to_string(&mut app, &theme, 38, 44); assert!(out.contains("Wonderland"), "the tail/cursor stays visible:\n{out}"); assert!(out.contains('<'), "a left marker signals the hidden head:\n{out}"); } @@ -2208,7 +2232,8 @@ mod tests { app.input_cursor = app.input.len(); app.input_indicator = Some(crate::dsl::walker::Severity::Error); let theme = Theme::dark(); - let out = render_to_string(&mut app, &theme, 80, 44); + // Narrow (sidebar hidden, DB1) so the line wraps across two rows. + let out = render_to_string(&mut app, &theme, 60, 44); let err_line = out .lines() .position(|l| l.contains("[ERR]")) @@ -2235,7 +2260,8 @@ mod tests { app.input.push_str(LONG_INPUT); app.input_cursor = app.input.len(); let theme = Theme::dark(); - let snapshot = render_to_string(&mut app, &theme, 80, 44); + // Narrow (sidebar hidden, DB1) so the command wraps across rows. + let snapshot = render_to_string(&mut app, &theme, 60, 44); insta::assert_snapshot!("two_row_input_dark", snapshot); } @@ -2557,7 +2583,9 @@ mod tests { }); let theme = Theme::dark(); - let snapshot = render_to_string(&mut app, &theme, 80, 24); + // Width > SIDEBAR_MIN_WIDTH so the sidebar (tables list) shows + // alongside the output panel (DB1). + let snapshot = render_to_string(&mut app, &theme, 110, 24); insta::assert_snapshot!("populated_with_table_dark", snapshot); } @@ -2577,10 +2605,34 @@ mod tests { ], ); let theme = Theme::dark(); - let out = render_to_string(&mut app, &theme, 80, 24); + // Width > SIDEBAR_MIN_WIDTH so the sidebar is shown (DB1). + let out = render_to_string(&mut app, &theme, 110, 24); assert!(out.contains("Customers"), "table listed:\n{out}"); assert!(out.contains("Orders"), "table listed:\n{out}"); assert!(out.contains("idx_email"), "index nested in panel:\n{out}"); assert!(out.contains("uidx_login [unique]"), "unique index marked:\n{out}"); } + + #[test] + fn sidebar_visible_is_width_gated() { + // ADR-0046 DB1: shown above SIDEBAR_MIN_WIDTH, hidden at/below. + assert!(!sidebar_visible(80)); + assert!(!sidebar_visible(90)); // the 90-col screencast: hidden + assert!(sidebar_visible(91)); + assert!(sidebar_visible(120)); + } + + #[test] + fn sidebar_hidden_at_or_below_threshold_width() { + // The Tables panel disappears at a narrow width (the output + // panel then spans the full width) and returns when wide. + let mut app = App::new(); + app.tables = vec!["Customers".to_string()]; + let theme = Theme::dark(); + let narrow = render_to_string(&mut app, &theme, 80, 24); + assert!(!narrow.contains("Tables"), "sidebar hidden at 80 wide:\n{narrow}"); + let wide = render_to_string(&mut app, &theme, 110, 24); + assert!(wide.contains("Tables"), "sidebar shown at 110 wide:\n{wide}"); + assert!(wide.contains("Customers"), "tables listed when shown:\n{wide}"); + } } diff --git a/tests/it/walking_skeleton.rs b/tests/it/walking_skeleton.rs index 24646e7..98b8400 100644 --- a/tests/it/walking_skeleton.rs +++ b/tests/it/walking_skeleton.rs @@ -301,7 +301,8 @@ fn create_table_flow_updates_tables_list_and_structure_view() { assert_eq!(app.tables, vec!["Customers".to_string()]); assert_eq!(app.current_table, Some(desc)); - let rendered = rendered_text(&mut app, &theme, 80, 24); + // Width > 90 so the sidebar (items panel) is shown (ADR-0046 DB1). + let rendered = rendered_text(&mut app, &theme, 110, 24); assert!( rendered.contains("Customers"), "items panel should list Customers:\n{rendered}" @@ -397,7 +398,8 @@ fn drop_table_flow_clears_items_list() { assert!(app.tables.is_empty()); assert!(app.current_table.is_none()); - let rendered = rendered_text(&mut app, &Theme::dark(), 80, 24); + // Width > 90 so the (now-empty) sidebar is shown (ADR-0046 DB1). + let rendered = rendered_text(&mut app, &Theme::dark(), 110, 24); assert!(rendered.contains("(none yet)")); // ADR-0040: `drop table` is content-less, so the echo's ✓ marker // is the entire success signal (replacing `[ok] drop table …`).