feat(tui): add HtmlRenderer for HTML-to-ANSI terminal text conversion (GH-25) #54

Merged
KofTwentyTwo merged 1 commits from feature/GH-25-html-to-ansi-plaintext-converter into main 2026-07-23 00:52:17 +00:00
4 changed files with 42 additions and 2 deletions

No files matched your search

+2
View File
@@ -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"
+2
View File
@@ -15,3 +15,5 @@ tokio.workspace = true
ratatui.workspace = true
crossterm.workspace = true
tracing.workspace = true
html2text.workspace = true
+32
View File
@@ -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 = "<h1>Meeting Notes</h1><p>Discussing <b>Nuncio</b> release.</p>";
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("<p>test</p>", 0);
assert!(rendered.contains("test"));
}
}
+6 -2
View File
@@ -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("<h1>Nuncio</h1>", 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()
);
}