Add syntax highlighting for doc comments

This patch adds syntax highlighting for code blocks in the doc comments.
Previously, we only highlighted the definition of the documented
elements.  With this patch, we also highlight code blocks in the doc
blocks, like examples.
This commit is contained in:
Robin Krahl 2020-10-03 19:06:21 +02:00
parent ecc05ddc7d
commit ecf810929a
No known key found for this signature in database
GPG Key ID: 8E9B0870524F69D8
2 changed files with 57 additions and 14 deletions

View File

@ -11,6 +11,7 @@ SPDX-License-Identifier: MIT
- Use the `merge` crate to merge the command-line arguments and the settings in
the configuration file.
- Add `merge` dependency in version 0.1.0.
- Add syntax highlighting for code snippets in the doc comments.
## v0.3.0 (2020-09-11)

View File

@ -10,6 +10,7 @@ use crate::doc;
use crate::viewer::utils;
type RichString = text_renderer::TaggedString<Vec<text_renderer::RichAnnotation>>;
type RichLine = text_renderer::TaggedLine<Vec<text_renderer::RichAnnotation>>;
#[derive(Debug)]
pub struct RichTextRenderer {
@ -24,6 +25,41 @@ impl RichTextRenderer {
highlighter: utils::get_highlighter(&args)?,
})
}
fn prepare_html<'s>(&self, html: &'s [RichLine]) -> Vec<Vec<text_style::StyledStr<'s>>> {
let mut lines = Vec::new();
let mut highlight_lines = None;
for line in html {
let mut styled_strings = Vec::new();
for ts in line.iter().filter_map(|tle| match tle {
text_renderer::TaggedLineElement::Str(ts) => Some(ts),
_ => None,
}) {
if let Some(highlighter) = &self.highlighter {
if is_pre(ts) {
let h = highlight_lines
.get_or_insert_with(|| highlighter.get_highlight_lines("rs"));
let highlighted_strings = h.highlight(&ts.s, &highlighter.syntax_set);
styled_strings.extend(
highlighted_strings
.iter()
.map(text_style::StyledStr::from)
.map(reset_background),
);
} else {
highlight_lines = None;
styled_strings.push(style_rich_string(ts));
}
} else {
styled_strings.push(style_rich_string(ts));
}
}
lines.push(styled_strings);
}
lines
}
}
impl utils::ManRenderer for RichTextRenderer {
@ -43,16 +79,9 @@ impl utils::ManRenderer for RichTextRenderer {
indent
};
let lines = html2text::from_read_rich(s.html.as_bytes(), self.line_length - indent);
for line in lines {
for line in self.prepare_html(&lines) {
write!(io::stdout(), "{}", " ".repeat(indent))?;
render_iter(
line.iter()
.filter_map(|tle| match tle {
text_renderer::TaggedLineElement::Str(ts) => Some(ts),
_ => None,
})
.map(style_rich_string),
)?;
render_iter(line)?;
writeln!(io::stdout())?;
}
Ok(())
@ -64,10 +93,11 @@ impl utils::ManRenderer for RichTextRenderer {
for line in highlighter.highlight(code.as_ref()) {
write!(io::stdout(), "{}", " ".repeat(indent))?;
// We remove the background as we want to use the terminal background
render_iter(line.iter().map(text_style::StyledStr::from).map(|mut s| {
s.style_mut().bg = None;
s
}))?;
render_iter(
line.iter()
.map(text_style::StyledStr::from)
.map(reset_background),
)?;
}
writeln!(io::stdout())?;
} else {
@ -90,7 +120,19 @@ impl utils::ManRenderer for RichTextRenderer {
}
}
pub fn style_rich_string(ts: &RichString) -> text_style::StyledStr<'_> {
fn reset_background(mut s: text_style::StyledStr<'_>) -> text_style::StyledStr<'_> {
s.style_mut().bg = None;
s
}
fn is_pre(ts: &RichString) -> bool {
ts.tag.iter().any(|annotation| match annotation {
text_renderer::RichAnnotation::Preformat(_) => true,
_ => false,
})
}
fn style_rich_string(ts: &RichString) -> text_style::StyledStr<'_> {
use text_renderer::RichAnnotation;
let mut s = text_style::StyledStr::plain(&ts.s);