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