From eb68d7a41cb35f0f6a22477ca6f05ec3a006bb3c Mon Sep 17 00:00:00 2001 From: muk Date: Sat, 21 Feb 2026 21:30:03 +0000 Subject: [PATCH] Fix UI layout: dynamic editor/results split and scrollable help - Autocomplete popup now uses the dynamic editor_height_percent instead of a hardcoded 40% for positioning, so it tracks the actual editor pane when resized with Ctrl+Shift+Up/Down - Help overlay adapts to small terminals by using available height and supports scrolling with Up/Down/PageUp/PageDown - Added scroll hint to help overlay footer Closes #61 Co-Authored-By: Claude Opus 4.6 --- src/ui/app.rs | 15 +++++++++++++++ src/ui/components.rs | 37 ++++++++++++++++++++++++++----------- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/ui/app.rs b/src/ui/app.rs index cec50b6..091e50a 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -139,6 +139,7 @@ pub struct App { // Help pub show_help: bool, + pub help_scroll: usize, // Autocomplete pub autocomplete: AutocompleteState, @@ -410,6 +411,7 @@ impl App { loading_message: String::new(), spinner_frame: 0, show_help: false, + help_scroll: 0, autocomplete: AutocompleteState::default(), explain_plans: Vec::new(), @@ -1130,8 +1132,21 @@ impl App { match key.code { KeyCode::Esc | KeyCode::Char('?') | KeyCode::Char('q') => { self.show_help = false; + self.help_scroll = 0; self.focus = Focus::Editor; } + KeyCode::Up => { + self.help_scroll = self.help_scroll.saturating_sub(1); + } + KeyCode::Down => { + self.help_scroll += 1; + } + KeyCode::PageUp => { + self.help_scroll = self.help_scroll.saturating_sub(10); + } + KeyCode::PageDown => { + self.help_scroll += 10; + } _ => {} } Ok(()) diff --git a/src/ui/components.rs b/src/ui/components.rs index 88c3fe0..d251a79 100644 --- a/src/ui/components.rs +++ b/src/ui/components.rs @@ -46,7 +46,10 @@ pub fn draw(frame: &mut Frame, app: &App) { // Compute the editor inner area to position the popup let editor_chunks = Layout::default() .direction(Direction::Vertical) - .constraints([Constraint::Percentage(40), Constraint::Min(0)]) + .constraints([ + Constraint::Percentage(app.editor_height_percent), + Constraint::Min(0), + ]) .split(main_chunks[1]); let editor_inner = Block::default() .borders(Borders::ALL) @@ -1596,16 +1599,6 @@ fn draw_help_overlay(frame: &mut Frame, app: &App) { let theme = &app.theme; let area = frame.area(); - let help_width = 50.min(area.width - 4); - let help_height = 25.min(area.height - 4); - - let help_x = (area.width - help_width) / 2; - let help_y = (area.height - help_height) / 2; - - let help_area = Rect::new(help_x, help_y, help_width, help_height); - - frame.render_widget(Clear, help_area); - let help_text = vec![ "", " KEYBOARD SHORTCUTS", @@ -1649,10 +1642,32 @@ fn draw_help_overlay(frame: &mut Frame, app: &App) { " Ctrl+[/] Prev/Next result set", " PageUp/Down Scroll results", "", + " ↑/↓/PgUp/PgDn to scroll | Esc/? to close", ]; + let help_width = 50.min(area.width.saturating_sub(4)); + // Use all available height if the terminal is small + let help_height = area + .height + .saturating_sub(4) + .min(help_text.len() as u16 + 2); + + let help_x = (area.width.saturating_sub(help_width)) / 2; + let help_y = (area.height.saturating_sub(help_height)) / 2; + + let help_area = Rect::new(help_x, help_y, help_width, help_height); + + frame.render_widget(Clear, help_area); + + // Apply scrolling so help is usable on small terminals + let inner_height = help_height.saturating_sub(2) as usize; // borders + let max_scroll = help_text.len().saturating_sub(inner_height); + let scroll = app.help_scroll.min(max_scroll); + let text: Vec = help_text .iter() + .skip(scroll) + .take(inner_height) .map(|s| Line::from(Span::styled(*s, Style::default().fg(theme.text_primary)))) .collect();