From 23d25fb66721aa5bd0901f8daac283dd1ac45eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Mon, 4 Nov 2024 14:04:27 +0100 Subject: [PATCH 1/3] fix(examples/html2term): more (vim-alike) keybinds --- examples/html2term.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/html2term.rs b/examples/html2term.rs index a1c2937..5982a01 100644 --- a/examples/html2term.rs +++ b/examples/html2term.rs @@ -300,7 +300,7 @@ mod top { } } } - Key::Char(' ') | Key::PageDown => { + Key::Char(' ') | Key::PageDown | Key::Ctrl('f') => { // Ideally, move both the cursor and the top // visible line down by a whole page doc_y += height; @@ -313,17 +313,17 @@ mod top { // will take care of the rest of the special // cases. } - Key::PageUp => { + Key::PageUp | Key::Ctrl('b') => { // Ideally, move both the cursor and the top // visible line up by a whole page. But bound // both at zero. doc_y = std::cmp::max(doc_y, height) - height; top_y = std::cmp::max(top_y, height) - height; } - Key::Home => { + Key::Home | Key::Char('g') => { doc_y = 0; } - Key::End => { + Key::End | Key::Char('G') => { doc_y = max_y; } Key::Char('\t') => {} From 27aaeb2afde114eb0e1cfb09ca6a49cde7e471b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Mon, 4 Nov 2024 14:05:36 +0100 Subject: [PATCH 2/3] fix(examples/html2text): use `yansi` instead of `termion` for colouring --- Cargo.toml | 1 + examples/html2text.rs | 76 ++++++++++++++++++++----------------------- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c581ab4..993af0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ path = "examples/html2text.rs" env_logger = "0.10.1" argparse = "0.2.2" log = "0.4.20" +yansi = { version = "1.0.1", features = ["hyperlink"] } [target.'cfg(unix)'.dev-dependencies] termion = "4.0" diff --git a/examples/html2text.rs b/examples/html2text.rs index b69c288..75d2fc2 100644 --- a/examples/html2text.rs +++ b/examples/html2text.rs @@ -7,88 +7,84 @@ use log::trace; use std::io; use std::io::Write; -#[cfg(unix)] use html2text::render::RichAnnotation; -#[cfg(unix)] fn default_colour_map( annotations: &[RichAnnotation], s: &str, use_css_colours: bool, no_default_colours: bool, ) -> String { - use termion::color::*; + use yansi::{hyperlink::HyperlinkExt, Paint}; use RichAnnotation::*; // Explicit CSS colours override any other colours let mut have_explicit_colour = no_default_colours; - let mut start = Vec::new(); - let mut finish = Vec::new(); + let mut styled = s.to_string(); trace!("default_colour_map: str={s}, annotations={annotations:?}"); for annotation in annotations.iter() { - match annotation { - Default => {} - Link(_) => { - start.push(format!("{}", termion::style::Underline)); - finish.push(format!("{}", termion::style::Reset)); - } - Image(_) => { + styled = match annotation { + Default => styled, + Link(url) => styled.link(url).blue().underline().to_string(), + Image(img) => { if !have_explicit_colour { - start.push(format!("{}", Fg(Blue))); - finish.push(format!("{}", Fg(Reset))); + format!( + "{} {}", + styled.yellow().italic(), + "img".underline().blue().link(img) + ) + } else { + styled } } - Emphasis => { - start.push(format!("{}", termion::style::Bold)); - finish.push(format!("{}", termion::style::Reset)); - } + Emphasis => styled.italic().to_string(), Strong => { if !have_explicit_colour { - start.push(format!("{}", Fg(LightYellow))); - finish.push(format!("{}", Fg(Reset))); + styled.bold().to_string() + } else { + styled } } Strikeout => { if !have_explicit_colour { - start.push(format!("{}", Fg(LightBlack))); - finish.push(format!("{}", Fg(Reset))); + styled.strike().to_string() + } else { + styled } } Code => { if !have_explicit_colour { - start.push(format!("{}", Fg(Blue))); - finish.push(format!("{}", Fg(Reset))); + styled.blue().to_string() + } else { + styled } } Preformat(_) => { if !have_explicit_colour { - start.push(format!("{}", Fg(Blue))); - finish.push(format!("{}", Fg(Reset))); + styled.blue().to_string() + } else { + styled } } Colour(c) => { if use_css_colours { - start.push(format!("{}", Fg(Rgb(c.r, c.g, c.b)))); - finish.push(format!("{}", Fg(Reset))); have_explicit_colour = true; + styled.rgb(c.r, c.g, c.b).to_string() + } else { + styled } } BgColour(c) => { if use_css_colours { - start.push(format!("{}", Bg(Rgb(c.r, c.g, c.b)))); - finish.push(format!("{}", Bg(Reset))); + styled.on_rgb(c.r, c.g, c.b).to_string() + } else { + styled } } - _ => {} + _ => styled, } } // Reverse the finish sequences - finish.reverse(); - let mut result = start.join(""); - result.push_str(s); - for s in finish { - result.push_str(&s); - } - trace!("default_colour_map: output={result}"); - result + trace!("default_colour_map: output={styled}"); + styled } fn update_config(mut config: Config, flags: &Flags) -> Config { @@ -106,7 +102,6 @@ fn translate(input: R, flags: Flags, literal: bool) -> String where R: io::Read, { - #[cfg(unix)] { if flags.use_colour { let conf = config::rich(); @@ -225,7 +220,6 @@ fn main() { StoreTrue, "Output only literal text (no decorations)", ); - #[cfg(unix)] ap.refer(&mut flags.use_colour).add_option( &["--colour"], StoreTrue, From b6a0eea50e542214c6629ee9d7c23d8d44f62ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeromos=20Kov=C3=A1cs?= Date: Mon, 2 Dec 2024 16:04:55 +0100 Subject: [PATCH 3/3] fix(examples/html2text): make hyperlinking optional --- examples/html2text.rs | 30 ++++++++++++++++++++++-------- src/render/text_renderer.rs | 5 ----- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/examples/html2text.rs b/examples/html2text.rs index 75d2fc2..66426ab 100644 --- a/examples/html2text.rs +++ b/examples/html2text.rs @@ -13,6 +13,7 @@ fn default_colour_map( s: &str, use_css_colours: bool, no_default_colours: bool, + hyperlinks: bool, ) -> String { use yansi::{hyperlink::HyperlinkExt, Paint}; use RichAnnotation::*; @@ -23,14 +24,20 @@ fn default_colour_map( for annotation in annotations.iter() { styled = match annotation { Default => styled, - Link(url) => styled.link(url).blue().underline().to_string(), + Link(url) => { + if hyperlinks { + styled.link(url).blue().underline().to_string() + } else if !have_explicit_colour { + styled.blue().underline().to_string() + } else { + styled + } + } Image(img) => { - if !have_explicit_colour { - format!( - "{} {}", - styled.yellow().italic(), - "img".underline().blue().link(img) - ) + if hyperlinks { + styled.underline().blue().italic().link(img).to_string() + } else if !have_explicit_colour { + styled.yellow().italic().to_string() } else { styled } @@ -116,7 +123,7 @@ where let use_only_css = false; return conf .coloured(input, flags.width, move |anns, s| { - default_colour_map(anns, s, use_css_colours, use_only_css) + default_colour_map(anns, s, use_css_colours, use_only_css, flags.hyperlinks) }) .unwrap(); } @@ -168,6 +175,7 @@ struct Flags { show_render: bool, #[cfg(feature = "css")] show_css: bool, + hyperlinks: bool, } fn main() { @@ -190,6 +198,7 @@ fn main() { show_render: false, #[cfg(feature = "css")] show_css: false, + hyperlinks: false, }; let mut literal: bool = false; @@ -253,6 +262,11 @@ fn main() { StoreTrue, "Show the parsed CSS instead of rendered output", ); + ap.refer(&mut flags.hyperlinks).add_option( + &["--hyperlinks"], + StoreTrue, + "Show clickable, proper hyperlinks", + ); ap.parse_args_or_exit(); } diff --git a/src/render/text_renderer.rs b/src/render/text_renderer.rs index 063ba1b..53c8212 100644 --- a/src/render/text_renderer.rs +++ b/src/render/text_renderer.rs @@ -1174,11 +1174,6 @@ fn filter_text_strikeout(s: &str) -> Option { let mut result = String::new(); for c in s.chars() { result.push(c); - if UnicodeWidthChar::width(c).unwrap_or(0) > 0 { - // This is a character with width (not a combining or other character) - // so add a strikethrough combiner. - result.push('\u{336}'); - } } Some(result) }