From 4260aab85aa5e2d22058d5f91585072524172535 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 6 Oct 2020 12:19:34 +0200 Subject: [PATCH] Display link targets in rich viewer Previously, we only used the underline effect to highlight links in the rich viewer, but we did not provide any information about their target. With this patch, we print a list of link at the end of a block, similar to the plain text viewer. --- src/viewer/text/mod.rs | 12 +++++++++ src/viewer/text/plain.rs | 11 +-------- src/viewer/text/rich.rs | 3 ++- src/viewer/utils.rs | 53 ++++++++++++++++++++++++++++++++++------ 4 files changed, 60 insertions(+), 19 deletions(-) diff --git a/src/viewer/text/mod.rs b/src/viewer/text/mod.rs index d892b92..9544aa5 100644 --- a/src/viewer/text/mod.rs +++ b/src/viewer/text/mod.rs @@ -70,6 +70,18 @@ fn ignore_pipe_error(error: io::Error) -> io::Result<()> { } } +/// Decides whether a link to the given URL should be included in the link list that is displayed +/// at the end of the block. +/// +/// We only list absolute URLs because relative URLs are not useful in a non-interactive viewer. +/// Also, we skip links to the Rust playground because they are typically very long and therefore +/// hard to read and display. +pub fn list_link(url: &str) -> bool { + (url.starts_with("http") || url.starts_with("https")) + && !url.starts_with("http://play.rust-lang.org") + && !url.starts_with("https://play.rust-lang.org") +} + pub fn format_title(line_length: usize, left: &str, middle: &str, right: &str) -> String { let mut s = String::with_capacity(line_length); diff --git a/src/viewer/text/plain.rs b/src/viewer/text/plain.rs index a06504a..9597a7d 100644 --- a/src/viewer/text/plain.rs +++ b/src/viewer/text/plain.rs @@ -69,22 +69,13 @@ impl Decorator { pub fn new() -> Self { Decorator::default() } - - 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) { + if super::list_link(url) { self.ignore_next_link = false; self.links.push(url.to_string()); ("[".to_owned(), ()) diff --git a/src/viewer/text/rich.rs b/src/viewer/text/rich.rs index 8047b07..30bf922 100644 --- a/src/viewer/text/rich.rs +++ b/src/viewer/text/rich.rs @@ -40,8 +40,9 @@ impl utils::ManRenderer for RichTextRenderer { } else { indent }; + let decorator = utils::RichDecorator::new(super::list_link); let lines = html2text::parse(s.html.as_bytes()) - .render(self.line_length - indent, utils::RichDecorator) + .render(self.line_length - indent, decorator) .into_lines(); for line in utils::highlight_html(&lines, self.highlighter.as_ref()) { write!(io::stdout(), "{}", " ".repeat(indent))?; diff --git a/src/viewer/utils.rs b/src/viewer/utils.rs index f38983d..8c9ec30 100644 --- a/src/viewer/utils.rs +++ b/src/viewer/utils.rs @@ -287,20 +287,44 @@ fn print_heading( /// A decorator that generates rich text. #[derive(Clone)] -pub struct RichDecorator; +pub struct RichDecorator { + link_filter: fn(&str) -> bool, + ignore_next_link: bool, + links: Vec, +} + +impl RichDecorator { + pub fn new(link_filter: fn(&str) -> bool) -> RichDecorator { + RichDecorator { + link_filter, + ignore_next_link: false, + links: Vec::new(), + } + } +} impl text_renderer::TextDecorator for RichDecorator { type Annotation = text_renderer::RichAnnotation; fn decorate_link_start(&mut self, url: &str) -> (String, Self::Annotation) { - ( - "".to_string(), - text_renderer::RichAnnotation::Link(url.to_string()), - ) + self.ignore_next_link = !(self.link_filter)(url); + if self.ignore_next_link { + (String::new(), text_renderer::RichAnnotation::Default) + } else { + self.links.push(url.to_owned()); + ( + "[".to_owned(), + text_renderer::RichAnnotation::Link(url.to_owned()), + ) + } } fn decorate_link_end(&mut self) -> String { - "".to_string() + if self.ignore_next_link { + String::new() + } else { + format!("][{}]", self.links.len() - 1) + } } fn decorate_em_start(&mut self) -> (String, Self::Annotation) { @@ -348,11 +372,24 @@ impl text_renderer::TextDecorator for RichDecorator { } fn finalise(self) -> Vec> { - Vec::new() + let mut lines = Vec::new(); + for (idx, link) in self.links.into_iter().enumerate() { + let mut line = text_renderer::TaggedLine::new(); + line.push_str(text_renderer::TaggedString { + s: format!("[{}] ", idx), + tag: text_renderer::RichAnnotation::Default, + }); + line.push_str(text_renderer::TaggedString { + s: link.clone(), + tag: text_renderer::RichAnnotation::Link(link), + }); + lines.push(line); + } + lines } fn make_subblock_decorator(&self) -> Self { - RichDecorator + RichDecorator::new(self.link_filter) } }