From b1b12ae831cfd448bbd8e296338f5b4e1fbbad41 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Sat, 8 Aug 2026 13:10:42 +0700 Subject: [PATCH] fix(home): stop offering chords the empty window cannot honour The home page is what a window shows with no tabs open, and it listed Split Right and Split Down among the things you can do from there. Both ask the active tab for a pane to split and return without a word when there is none, so the two chords the screen taught did nothing on the one screen that taught them. Reopen Closed Tab had the same shape whenever the closed stack was empty. The splits leave the list, and Reopen Closed Tab appears only while there is something to reopen. A fresh window now offers four rows, and every one of them works. --- src/ui/home.rs | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/ui/home.rs b/src/ui/home.rs index 7bec8ed4..0cf6e32c 100644 --- a/src/ui/home.rs +++ b/src/ui/home.rs @@ -21,13 +21,16 @@ const LOGO: [&str; 4] = [ const LOGO_PX: f32 = 20.0; -const HOME_SHORTCUTS: [&str; 7] = [ +/// What a window with no tabs open can actually do. `SplitRight`/`SplitDown` +/// were listed here too, but both need a pane to split and return without a +/// word when there is none — the home page was advertising two chords that do +/// nothing from the only screen that offers them. `ReopenClosedTab` earns its +/// row only while something is on the closed stack. +const HOME_SHORTCUTS: [&str; 5] = [ "NewTab", "ReopenClosedTab", "ToggleSwitcher", "TogglePalette", - "SplitRight", - "SplitDown", "OpenSettings", ]; @@ -152,8 +155,12 @@ impl Tty7App { )); let closed_hint = self.closed.last().and_then(closed_tab_label); + let nothing_to_reopen = self.closed.is_empty(); let mut list = v_flex().gap_2().w(px(300.)).text_sm().text_color(muted); for action in HOME_SHORTCUTS { + if action == "ReopenClosedTab" && nothing_to_reopen { + continue; + } let emphasized = closed_hint.is_some() && action == "ReopenClosedTab"; let label = home_shortcut_label(action, closed_hint.as_deref()); list = list.child( @@ -389,6 +396,32 @@ mod tests { } } + #[test] + fn every_home_shortcut_ships_with_a_chord_to_show() { + let defaults = crate::ui::keymap::default_bindings(); + for action in HOME_SHORTCUTS { + let key = defaults + .iter() + .find(|(a, _)| *a == action) + .unwrap_or_else(|| panic!("{action} is not a bindable action")) + .1; + assert!( + !key.is_empty(), + "{action} has no default chord, so its home row would read as a bare label" + ); + } + } + + #[test] + fn the_home_list_leaves_out_what_an_empty_window_cannot_do() { + for action in ["SplitRight", "SplitDown", "CloseActiveTab", "RenameTab"] { + assert!( + !HOME_SHORTCUTS.contains(&action), + "{action} needs a pane, and the home page is what a window shows without one" + ); + } + } + #[test] fn logo_rows_never_exceed_the_first_row_width() { let width = LOGO[0].chars().count();