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) } }