Skip to content

Commit 31ef463

Browse files
committed
Shrink code block annotation after a comma
1 parent fb0c5f2 commit 31ef463

File tree

1 file changed

+46
-3
lines changed

1 file changed

+46
-3
lines changed

src/render.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Render README files to HTML.
22
33
use ammonia::{Builder, UrlRelative, UrlRelativeEvaluate};
4+
use comrak::nodes::{AstNode, NodeValue};
45
use htmlescape::encode_minimal;
56
use std::borrow::Cow;
67
use std::path::Path;
@@ -57,7 +58,10 @@ impl<'a> MarkdownRenderer<'a> {
5758

5859
/// Renders the given markdown to HTML using the current settings.
5960
fn to_html(&self, text: &str) -> String {
60-
use comrak::{ComrakExtensionOptions, ComrakOptions, ComrakRenderOptions};
61+
use comrak::{
62+
format_html, parse_document, Arena, ComrakExtensionOptions, ComrakOptions,
63+
ComrakRenderOptions,
64+
};
6165

6266
let options = ComrakOptions {
6367
render: ComrakRenderOptions {
@@ -75,11 +79,41 @@ impl<'a> MarkdownRenderer<'a> {
7579
},
7680
..ComrakOptions::default()
7781
};
78-
let rendered = comrak::markdown_to_html(text, &options);
82+
83+
let arena = Arena::new();
84+
let root = parse_document(&arena, text, &options);
85+
86+
// Tweak annotations of code blocks.
87+
iter_nodes(root, &|node| {
88+
if let NodeValue::CodeBlock(ref mut ncb) = node.data.borrow_mut().value {
89+
let mut orig_annot = String::from_utf8(ncb.info.to_vec()).unwrap();
90+
91+
// Ignore characters after a comma for syntax highlighting to work correctly.
92+
if let Some(offset) = orig_annot.find(',') {
93+
let _ = orig_annot.drain(offset..orig_annot.len());
94+
ncb.info = orig_annot.as_bytes().to_vec();
95+
}
96+
}
97+
});
98+
99+
let mut html = Vec::new();
100+
format_html(root, &options, &mut html).unwrap();
101+
let rendered = String::from_utf8(html).unwrap();
79102
self.html_sanitizer.clean(&rendered).to_string()
80103
}
81104
}
82105

106+
/// Iterate the nodes in the CommonMark AST, used in comrak.
107+
fn iter_nodes<'a, F>(node: &'a AstNode<'a>, f: &F)
108+
where
109+
F: Fn(&'a AstNode<'a>),
110+
{
111+
f(node);
112+
for c in node.children() {
113+
iter_nodes(c, f);
114+
}
115+
}
116+
83117
/// Add trailing slash and remove `.git` suffix of base URL.
84118
fn canon_base_url(mut base_url: String) -> String {
85119
if !base_url.ends_with('/') {
@@ -117,7 +151,7 @@ struct MediaUrl {
117151
add_sanitize_query: bool,
118152
}
119153

120-
/// Determine whether the given URL has a media file externsion.
154+
/// Determine whether the given URL has a media file extension.
121155
/// Also check if `sanitize=true` must be added to the query string,
122156
/// which is required to load SVGs properly from GitHub.
123157
fn is_media_url(url: &str) -> MediaUrl {
@@ -334,6 +368,15 @@ mod tests {
334368
assert!(result.contains("<code class=\"language-rust\">"));
335369
}
336370

371+
#[test]
372+
fn code_block_with_syntax_highlighting_even_if_annot_has_no_run() {
373+
let code_block = r#"```rust , no_run \
374+
println!("Hello World"); \
375+
```"#;
376+
let result = markdown_to_html(code_block, None);
377+
assert!(result.contains("<code class=\"language-rust\">"));
378+
}
379+
337380
#[test]
338381
fn text_with_forbidden_class_attribute() {
339382
let text = "<p class='bad-class'>Hello World!</p>";

0 commit comments

Comments
 (0)