From 386bd4addb0929e46bb1ee2a9a86d0f3c8301f00 Mon Sep 17 00:00:00 2001 From: James Maes Date: Wed, 22 Jul 2026 19:52:03 -0500 Subject: [PATCH] feat(tui): add HtmlRenderer for HTML-to-ANSI terminal text conversion --- Cargo.toml | 2 ++ crates/nuncio-tui/Cargo.toml | 2 ++ crates/nuncio-tui/src/html.rs | 32 ++++++++++++++++++++++++++++++++ crates/nuncio-tui/src/main.rs | 8 ++++++-- 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 crates/nuncio-tui/src/html.rs diff --git a/Cargo.toml b/Cargo.toml index 9ac6593..26c93a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,8 @@ rrule = "0.10" chrono = "0.4" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } quick-xml = "0.36" +html2text = "0.12" + diff --git a/crates/nuncio-tui/Cargo.toml b/crates/nuncio-tui/Cargo.toml index e93b694..bc73365 100644 --- a/crates/nuncio-tui/Cargo.toml +++ b/crates/nuncio-tui/Cargo.toml @@ -15,3 +15,5 @@ tokio.workspace = true ratatui.workspace = true crossterm.workspace = true tracing.workspace = true +html2text.workspace = true + diff --git a/crates/nuncio-tui/src/html.rs b/crates/nuncio-tui/src/html.rs new file mode 100644 index 0000000..3ed5705 --- /dev/null +++ b/crates/nuncio-tui/src/html.rs @@ -0,0 +1,32 @@ +//! HTML to ANSI terminal plaintext renderer wrapper for email preview. + +/// Renderer converting HTML body strings into wrapped terminal plaintext. +pub struct HtmlRenderer; + +impl HtmlRenderer { + /// Render HTML body string into plaintext formatted for terminal reader width. + pub fn render_html(html: &str, width: usize) -> String { + let max_width = if width == 0 { 80 } else { width }; + html2text::from_read(html.as_bytes(), max_width) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn render_html_paragraph_and_links() { + let html = "

Meeting Notes

Discussing Nuncio release.

"; + let rendered = HtmlRenderer::render_html(html, 60); + + assert!(rendered.contains("Meeting Notes")); + assert!(rendered.contains("Nuncio")); + } + + #[test] + fn render_empty_or_zero_width_uses_default() { + let rendered = HtmlRenderer::render_html("

test

", 0); + assert!(rendered.contains("test")); + } +} diff --git a/crates/nuncio-tui/src/main.rs b/crates/nuncio-tui/src/main.rs index 54da127..be86238 100644 --- a/crates/nuncio-tui/src/main.rs +++ b/crates/nuncio-tui/src/main.rs @@ -1,8 +1,10 @@ //! Nuncio Terminal UI application entry point. +mod html; mod keybindings; mod layout; +use html::HtmlRenderer; use keybindings::{KeybindingEngine, UserAction}; use layout::{ActivePane, AppLayout}; use ratatui::layout::Rect; @@ -12,8 +14,10 @@ fn main() { let (sidebar, list, reader) = AppLayout::compute_layout(area); let focused = ActivePane::Sidebar; + let sample_rendered = HtmlRenderer::render_html("

Nuncio

", 40); + println!( - "Nuncio TUI Layout Active: sidebar={}px, list={}px, reader={}px (focused: {:?})", - sidebar.width, list.width, reader.width, focused + "Nuncio TUI Layout Active: sidebar={}px, list={}px, reader={}px (focused: {:?}, rendered: {})", + sidebar.width, list.width, reader.width, focused, sample_rendered.trim() ); } -- 2.54.0