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.
This commit is contained in:
Robin Krahl 2020-10-06 12:19:34 +02:00
parent 6ea5f070d2
commit 4260aab85a
No known key found for this signature in database
GPG Key ID: 8E9B0870524F69D8
4 changed files with 60 additions and 19 deletions

View File

@ -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);

View File

@ -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(), ())

View File

@ -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))?;

View File

@ -287,20 +287,44 @@ fn print_heading<M: ManRenderer + ?Sized>(
/// 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<String>,
}
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) {
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_string(),
text_renderer::RichAnnotation::Link(url.to_string()),
"[".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<text_renderer::TaggedLine<text_renderer::RichAnnotation>> {
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)
}
}