Skip to main content

iris_reader/ui/
help.rs

1use ratatui::{
2    Frame,
3    layout::Rect,
4    text::{Line, Span},
5    widgets::{Block, Borders, Clear, Paragraph},
6};
7
8use crate::theme::Theme;
9
10pub fn render(frame: &mut Frame, theme: &Theme, markdown: bool) {
11    let area = centered(frame.area(), 76, if markdown { 38 } else { 30 });
12    frame.render_widget(Clear, area);
13
14    let mut lines = Vec::new();
15    section(&mut lines, "Navigation", theme);
16    shortcut(&mut lines, "j / ↓", "Scroll down", theme);
17    shortcut(&mut lines, "k / ↑", "Scroll up", theme);
18    shortcut(&mut lines, "h / ←", "Scroll left", theme);
19    shortcut(&mut lines, "l / →", "Scroll right", theme);
20    shortcut(&mut lines, "PgDn / PgUp", "Page down / up", theme);
21    shortcut(&mut lines, "g / G", "Top / bottom", theme);
22
23    section(&mut lines, "Search", theme);
24    shortcut(&mut lines, "/", "Search", theme);
25    shortcut(&mut lines, "n / N", "Next / previous match", theme);
26    shortcut(&mut lines, "Enter", "Accept search", theme);
27    shortcut(&mut lines, "Esc", "Clear search / highlights", theme);
28
29    if markdown {
30        section(&mut lines, "Headings & links", theme);
31        shortcut(&mut lines, "]h / [h", "Next / previous heading", theme);
32        shortcut(&mut lines, "Left click", "Open a link or image", theme);
33    }
34
35    section(&mut lines, "Display & mouse", theme);
36    shortcut(&mut lines, "w", "Toggle prose wrapping", theme);
37    shortcut(&mut lines, "Wheel", "Scroll vertically", theme);
38    shortcut(&mut lines, "Shift+Wheel", "Scroll horizontally", theme);
39    shortcut(
40        &mut lines,
41        "Trackpad",
42        "Scroll vertically / horizontally",
43        theme,
44    );
45
46    section(&mut lines, "General", theme);
47    shortcut(&mut lines, "? / Esc", "Close help", theme);
48    shortcut(&mut lines, "q", "Quit IRIS", theme);
49
50    lines.push(Line::from(""));
51    lines.push(Line::from(Span::styled(
52        "Press ? or Esc to close",
53        theme.status,
54    )));
55
56    let block = Block::default()
57        .title(" IRIS Help ")
58        .borders(Borders::ALL)
59        .border_style(theme.help_border)
60        .style(theme.help);
61    frame.render_widget(Paragraph::new(lines).block(block), area);
62}
63
64fn section(lines: &mut Vec<Line<'static>>, title: &str, theme: &Theme) {
65    if !lines.is_empty() {
66        lines.push(Line::from(""));
67    }
68    lines.push(Line::from(Span::styled(
69        title.to_string(),
70        theme.help_heading,
71    )));
72}
73
74fn shortcut(lines: &mut Vec<Line<'static>>, key: &str, description: &str, theme: &Theme) {
75    lines.push(Line::from(vec![
76        Span::raw("  "),
77        Span::styled(format!("{key:<18}"), theme.help_key),
78        Span::styled(description.to_string(), theme.help),
79    ]));
80}
81
82fn centered(area: Rect, desired_width: u16, desired_height: u16) -> Rect {
83    let width = desired_width.min(area.width.saturating_sub(2)).max(1);
84    let height = desired_height.min(area.height.saturating_sub(2)).max(1);
85    Rect::new(
86        area.x + area.width.saturating_sub(width) / 2,
87        area.y + area.height.saturating_sub(height) / 2,
88        width,
89        height,
90    )
91}