Skip to main content

html_markdown/
main.rs

1//! Markdown with raw HTML blocks in it, rendered through the seam.
2//!
3//! ```bash
4//! cargo run -p tuika-html --example html_markdown          # a real terminal (q quits)
5//! cargo run -p tuika-html --example html_markdown -- --dump  # one frame as text
6//! ```
7//!
8//! It runs as an actual app rather than printing a grid, because half of what
9//! this crate does is *styling* — headings, inline code, links, the table's
10//! bold header — and a plain-text dump throws every bit of that away.
11//! `scripts/gen-html-demo.sh` records this same binary.
12
13use tuika::components::Markdown;
14use tuika::prelude::*;
15use tuika::testing::{grid, render};
16use tuika_html::HtmlRenderer;
17
18/// Shared with the demo generator so the recording cannot drift from the app.
19const DOCUMENT: &str = include_str!("document.md");
20
21fn scene() -> Element {
22    // The renderer is `Copy` and holds no state, so the view can own one per
23    // frame; a host with a configured `Limits` would keep one beside its state.
24    element(Padded)
25}
26
27/// The document, inset from the terminal edges.
28struct Padded;
29
30impl View for Padded {
31    fn measure(&self, available: Size, _ctx: &RenderCtx) -> Size {
32        available
33    }
34
35    fn render(&self, area: ratatui_core::layout::Rect, surface: &mut Surface, ctx: &RenderCtx) {
36        let html = HtmlRenderer::new();
37        let inner = ratatui_core::layout::Rect {
38            x: area.x.saturating_add(2),
39            y: area.y.saturating_add(1),
40            width: area.width.saturating_sub(4),
41            height: area.height.saturating_sub(2),
42        };
43        Markdown::new(DOCUMENT)
44            .block_renderer(&html)
45            .render(inner, surface, ctx);
46    }
47}
48
49fn main() -> std::io::Result<()> {
50    let theme = Theme::default();
51    if std::env::args().any(|a| a == "--dump") {
52        let buffer = render(scene().as_ref(), 76, 22, &theme);
53        for line in grid(&buffer).lines() {
54            println!("{}", line.trim_end());
55        }
56        return Ok(());
57    }
58
59    let runner = Runner::new(RunnerConfig::default());
60    runner.run(
61        &theme,
62        &mut (),
63        |(), _frame| scene(),
64        |(), signal| match signal {
65            Signal::Event(Event::Key(key))
66                if matches!(key.code, KeyCode::Char('q') | KeyCode::Esc) =>
67            {
68                UpdateResult::Exit
69            }
70            _ => UpdateResult::Clean,
71        },
72    )
73}