chore: TUI help menu
81491563
1 file(s) · +90 −24
| 5 | 5 | layout::{Constraint, Layout}, |
|
| 6 | 6 | style::{Color, Modifier, Style}, |
|
| 7 | 7 | text::{Line, Span, Text}, |
|
| 8 | - | widgets::{Block, Borders, List, ListItem, ListState, Paragraph}, |
|
| 8 | + | widgets::{Block, Borders, Clear, List, ListItem, ListState, Paragraph, Widget}, |
|
| 9 | 9 | }; |
|
| 10 | 10 | use sipp_rust::db::{self, Snippet}; |
|
| 11 | 11 | use std::time::{Duration, Instant}; |
|
| 27 | 27 | status_message: Option<(String, Instant)>, |
|
| 28 | 28 | focus: Focus, |
|
| 29 | 29 | content_scroll: u16, |
|
| 30 | + | show_help: bool, |
|
| 30 | 31 | syntax_set: SyntaxSet, |
|
| 31 | 32 | theme: Theme, |
|
| 32 | 33 | } |
|
| 49 | 50 | status_message: None, |
|
| 50 | 51 | focus: Focus::List, |
|
| 51 | 52 | content_scroll: 0, |
|
| 53 | + | show_help: false, |
|
| 52 | 54 | syntax_set, |
|
| 53 | 55 | theme, |
|
| 54 | 56 | } |
|
| 231 | 233 | .style(Style::default().fg(Color::Green).add_modifier(Modifier::BOLD)); |
|
| 232 | 234 | frame.render_widget(status, outer[1]); |
|
| 233 | 235 | } |
|
| 236 | + | ||
| 237 | + | if app.show_help { |
|
| 238 | + | let area = frame.area(); |
|
| 239 | + | let popup_width = 40u16.min(area.width.saturating_sub(4)); |
|
| 240 | + | let popup_height = 14u16.min(area.height.saturating_sub(4)); |
|
| 241 | + | let popup_area = ratatui::layout::Rect { |
|
| 242 | + | x: (area.width.saturating_sub(popup_width)) / 2, |
|
| 243 | + | y: (area.height.saturating_sub(popup_height)) / 2, |
|
| 244 | + | width: popup_width, |
|
| 245 | + | height: popup_height, |
|
| 246 | + | }; |
|
| 247 | + | ||
| 248 | + | let help_text = Text::from(vec![ |
|
| 249 | + | Line::from(""), |
|
| 250 | + | Line::from(vec![ |
|
| 251 | + | Span::styled(" j/↓ ", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)), |
|
| 252 | + | Span::raw("Move down / Scroll down"), |
|
| 253 | + | ]), |
|
| 254 | + | Line::from(vec![ |
|
| 255 | + | Span::styled(" k/↑ ", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)), |
|
| 256 | + | Span::raw("Move up / Scroll up"), |
|
| 257 | + | ]), |
|
| 258 | + | Line::from(vec![ |
|
| 259 | + | Span::styled(" Enter", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)), |
|
| 260 | + | Span::raw(" Focus content pane"), |
|
| 261 | + | ]), |
|
| 262 | + | Line::from(vec![ |
|
| 263 | + | Span::styled(" Esc ", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)), |
|
| 264 | + | Span::raw("Back / Quit"), |
|
| 265 | + | ]), |
|
| 266 | + | Line::from(vec![ |
|
| 267 | + | Span::styled(" y ", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)), |
|
| 268 | + | Span::raw("Copy snippet"), |
|
| 269 | + | ]), |
|
| 270 | + | Line::from(vec![ |
|
| 271 | + | Span::styled(" q ", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)), |
|
| 272 | + | Span::raw("Quit"), |
|
| 273 | + | ]), |
|
| 274 | + | Line::from(vec![ |
|
| 275 | + | Span::styled(" ? ", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)), |
|
| 276 | + | Span::raw("Toggle this help"), |
|
| 277 | + | ]), |
|
| 278 | + | Line::from(""), |
|
| 279 | + | Line::from(Span::styled( |
|
| 280 | + | " Press any key to close", |
|
| 281 | + | Style::default().fg(Color::DarkGray), |
|
| 282 | + | )), |
|
| 283 | + | ]); |
|
| 284 | + | ||
| 285 | + | Clear.render(popup_area, frame.buffer_mut()); |
|
| 286 | + | let help = Paragraph::new(help_text).block( |
|
| 287 | + | Block::default() |
|
| 288 | + | .title(" Keybindings ") |
|
| 289 | + | .borders(Borders::ALL) |
|
| 290 | + | .border_style(Style::default().fg(Color::Yellow)), |
|
| 291 | + | ); |
|
| 292 | + | frame.render_widget(help, popup_area); |
|
| 293 | + | } |
|
| 234 | 294 | })?; |
|
| 235 | 295 | ||
| 236 | 296 | if event::poll(Duration::from_millis(100))? { |
|
| 237 | 297 | if let Event::Key(key) = event::read()? { |
|
| 238 | - | match app.focus { |
|
| 239 | - | Focus::List => match key.code { |
|
| 240 | - | KeyCode::Char('q') => app.should_quit = true, |
|
| 241 | - | KeyCode::Char('j') | KeyCode::Down => app.move_down(), |
|
| 242 | - | KeyCode::Char('k') | KeyCode::Up => app.move_up(), |
|
| 243 | - | KeyCode::Char('y') => app.copy_selected(), |
|
| 244 | - | KeyCode::Enter => { |
|
| 245 | - | if app.selected_snippet().is_some() { |
|
| 246 | - | app.focus = Focus::Content; |
|
| 298 | + | if app.show_help { |
|
| 299 | + | app.show_help = false; |
|
| 300 | + | } else { |
|
| 301 | + | match app.focus { |
|
| 302 | + | Focus::List => match key.code { |
|
| 303 | + | KeyCode::Char('q') | KeyCode::Esc => app.should_quit = true, |
|
| 304 | + | KeyCode::Char('j') | KeyCode::Down => app.move_down(), |
|
| 305 | + | KeyCode::Char('k') | KeyCode::Up => app.move_up(), |
|
| 306 | + | KeyCode::Char('y') => app.copy_selected(), |
|
| 307 | + | KeyCode::Char('?') => app.show_help = true, |
|
| 308 | + | KeyCode::Enter => { |
|
| 309 | + | if app.selected_snippet().is_some() { |
|
| 310 | + | app.focus = Focus::Content; |
|
| 311 | + | } |
|
| 312 | + | } |
|
| 313 | + | _ => {} |
|
| 314 | + | }, |
|
| 315 | + | Focus::Content => match key.code { |
|
| 316 | + | KeyCode::Char(' ') | KeyCode::Esc | KeyCode::Char('q') => { |
|
| 317 | + | app.focus = Focus::List; |
|
| 318 | + | } |
|
| 319 | + | KeyCode::Char('j') | KeyCode::Down => { |
|
| 320 | + | app.scroll_down(content_line_count); |
|
| 247 | 321 | } |
|
| 248 | - | } |
|
| 249 | - | _ => {} |
|
| 250 | - | }, |
|
| 251 | - | Focus::Content => match key.code { |
|
| 252 | - | KeyCode::Char(' ') | KeyCode::Esc | KeyCode::Char('q') => { |
|
| 253 | - | app.focus = Focus::List; |
|
| 254 | - | } |
|
| 255 | - | KeyCode::Char('j') | KeyCode::Down => { |
|
| 256 | - | app.scroll_down(content_line_count); |
|
| 257 | - | } |
|
| 258 | - | KeyCode::Char('k') | KeyCode::Up => app.scroll_up(), |
|
| 259 | - | KeyCode::Char('y') => app.copy_selected(), |
|
| 260 | - | _ => {} |
|
| 261 | - | }, |
|
| 322 | + | KeyCode::Char('k') | KeyCode::Up => app.scroll_up(), |
|
| 323 | + | KeyCode::Char('y') => app.copy_selected(), |
|
| 324 | + | KeyCode::Char('?') => app.show_help = true, |
|
| 325 | + | _ => {} |
|
| 326 | + | }, |
|
| 327 | + | } |
|
| 262 | 328 | } |
|
| 263 | 329 | } |
|
| 264 | 330 | } |
|