From 7c228e500935209c8c9a4f089c9e7d03007afb4b Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Thu, 16 Jul 2020 22:57:19 +0200 Subject: [PATCH] Add custom TextDecorator implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit html2text’s PlainDecorator that is used to produce plain text prints all link targets at the end of a block. While this is generally useful, listing all local links makes the output hard to read. JavaScript and Rust plaground links are generally not very useful in this context. Therefore we implement a custom TextDecorator that only lists external links (http or https) and ignores links to the Rust playground. --- src/viewer/text.rs | 98 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/src/viewer/text.rs b/src/viewer/text.rs index 3d14e0c..a59bcbe 100644 --- a/src/viewer/text.rs +++ b/src/viewer/text.rs @@ -1,19 +1,29 @@ // SPDX-FileCopyrightText: 2020 Robin Krahl // SPDX-License-Identifier: MIT +use html2text::render::text_renderer; + use crate::doc; use crate::viewer; #[derive(Clone, Debug)] pub struct TextViewer {} +struct Decorator { + links: Vec, + ignore_next_link: bool, +} + impl TextViewer { pub fn new() -> Self { Self {} } fn print(&self, s: &str) { - println!("{}", html2text::from_read(s.as_bytes(), 100)); + println!( + "{}", + html2text::from_read_with_decorator(s.as_bytes(), 100, Decorator::new()) + ); } fn print_opt(&self, s: Option<&str>) { @@ -31,3 +41,89 @@ impl viewer::Viewer for TextViewer { Ok(()) } } + +impl Decorator { + pub fn new() -> Self { + Self { + links: Vec::new(), + ignore_next_link: false, + } + } + + fn show_link(&self, url: &str) -> bool { + // only show absolute links -- local links are most likely not helpful + (url.starts_with("http") || url.starts_with("https")) && + // ignore playground links -- typically, these links are too long to display in a + // sensible fasshion + !url.starts_with("http://play.rust-lang.org") && + !url.starts_with("https://play.rust-lang.org") + } +} + +impl text_renderer::TextDecorator for Decorator { + type Annotation = (); + + fn decorate_link_start(&mut self, url: &str) -> (String, Self::Annotation) { + if self.show_link(url) { + self.ignore_next_link = false; + self.links.push(url.to_string()); + ("[".to_owned(), ()) + } else { + self.ignore_next_link = true; + (String::new(), ()) + } + } + + fn decorate_link_end(&mut self) -> String { + if self.ignore_next_link { + String::new() + } else { + format!("][{}]", self.links.len()) + } + } + + fn decorate_em_start(&mut self) -> (String, Self::Annotation) { + ("*".to_owned(), ()) + } + + fn decorate_em_end(&mut self) -> String { + "*".to_owned() + } + + fn decorate_strong_start(&mut self) -> (String, Self::Annotation) { + ("**".to_owned(), ()) + } + + fn decorate_strong_end(&mut self) -> String { + "**".to_owned() + } + + fn decorate_code_start(&mut self) -> (String, Self::Annotation) { + ("`".to_owned(), ()) + } + + fn decorate_code_end(&mut self) -> String { + "`".to_owned() + } + + fn decorate_preformat_first(&mut self) -> Self::Annotation {} + fn decorate_preformat_cont(&mut self) -> Self::Annotation {} + + fn decorate_image(&mut self, title: &str) -> (String, Self::Annotation) { + (format!("[{}]", title), ()) + } + + fn finalise(self) -> Vec> { + self.links + .into_iter() + .enumerate() + .map(|(idx, s)| { + text_renderer::TaggedLine::from_string(format!("[{}] {}", idx + 1, s), &()) + }) + .collect() + } + + fn make_subblock_decorator(&self) -> Self { + Decorator::new() + } +}