Repository: kivikakk/comrak (Rust)

Issue:
Code blocks contain invalid preceding and trailing newlines
````markdown
```rust
fn foo() {}
```
````
currently generates
```html
<pre style="background-color:#2b303b;"><code class="language-rust">
<span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">foo</span><span style="color:#c0c5ce;">() {}
</span>
</code></pre>
```
rather than
```html
<pre style="background-color:#2b303b;"><code class="language-rust"><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">foo</span><span style="color:#c0c5ce;">() {}</span></code></pre>
```

This causes an extra newline at the start and end of each code block. This happens in the CLI and the library.

Current behaviour:
![image](https://user-images.githubusercontent.com/30854646/218685293-83d29207-2bd3-421d-a3b3-41a3c72618b9.png)
Correct behaviour:
![image](https://user-images.githubusercontent.com/30854646/218685379-26ddc86e-3e01-4709-b217-ca81b29b24d6.png)



Discussion:
Thanks so much for this report — you're absolutely right. I'll push a fix shortly, though I'm not sure when I'll next be able to make a release.



Patch:
diff --git a/src/plugins/syntect.rs b/src/plugins/syntect.rs
index b9a0abe6..270ca4b0 100644
--- a/src/plugins/syntect.rs
+++ b/src/plugins/syntect.rs
@@ -1,12 +1,16 @@
 //! Adapter for the Syntect syntax highlighter plugin.
 
 use adapters::SyntaxHighlighterAdapter;
-use regex::Regex;
 use std::collections::HashMap;
 use strings::{build_opening_tag, extract_attributes_from_tag};
-use syntect::highlighting::ThemeSet;
-use syntect::html::highlighted_html_for_string;
-use syntect::parsing::SyntaxSet;
+use syntect::easy::HighlightLines;
+use syntect::highlighting::{Color, ThemeSet};
+use syntect::html::{
+    append_highlighted_html_for_styled_line, highlighted_html_for_string, IncludeBackground,
+};
+use syntect::parsing::{SyntaxReference, SyntaxSet};
+use syntect::util::LinesWithEndings;
+use syntect::Error;
 
 #[derive(Debug)]
 /// Syntect syntax highlighter plugin.
@@ -39,12 +43,22 @@ impl<'a> SyntectAdapter<'a> {
         }
     }
 
-    fn remove_pre_tag(&self, highlighted_code: String) -> String {
-        let re: Regex = Regex::new("<pre[\\s]+.*?>").unwrap();
-
-        re.replace_all(highlighted_code.as_str(), "")
-            .to_string()
-            .replace("</pre>", "")
+    fn highlight_html(&self, code: &str, syntax: &SyntaxReference) -> Result<String, Error> {
+        // syntect::html::highlighted_html_for_string, without the opening/closing <pre>.
+        let theme = &self.theme_set.themes[self.theme];
+        let mut highlighter = HighlightLines::new(syntax, theme);
+        let mut output = String::new();
+        let bg = theme.settings.background.unwrap_or(Color::WHITE);
+
+        for line in LinesWithEndings::from(code) {
+            let regions = highlighter.highlight_line(line, &self.syntax_set)?;
+            append_highlighted_html_for_styled_line(
+                &regions[..],
+                IncludeBackground::IfDifferent(bg),
+                &mut output,
+            )?;
+        }
+        Ok(output)
     }
 }
 
@@ -72,13 +86,8 @@ impl SyntaxHighlighterAdapter for SyntectAdapter<'_> {
                     .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text())
             });
 
-        match highlighted_html_for_string(
-            code,
-            &self.syntax_set,
-            syntax,
-            &self.theme_set.themes[self.theme],
-        ) {
-            Ok(highlighted_code) => self.remove_pre_tag(highlighted_code),
+        match self.highlight_html(code, syntax) {
+            Ok(highlighted_code) => highlighted_code,
             Err(_) => code.into(),
         }
     }


Test patch:
diff --git a/src/tests.rs b/src/tests.rs
index bac78588..1cc1efd4 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -262,9 +262,9 @@ fn syntect_plugin() {
 
     let input = concat!("```rust\n", "fn main<'a>();\n", "```\n");
     let expected = concat!(
-        "<pre style=\"background-color:#2b303b;\"><code class=\"language-rust\">\n",
+        "<pre style=\"background-color:#2b303b;\"><code class=\"language-rust\">",
         "<span style=\"color:#b48ead;\">fn </span><span style=\"color:#8fa1b3;\">main</span><span style=\"color:#c0c5ce;\">",
-        "&lt;</span><span style=\"color:#b48ead;\">&#39;a</span><span style=\"color:#c0c5ce;\">&gt;();\n</span>\n",
+        "&lt;</span><span style=\"color:#b48ead;\">&#39;a</span><span style=\"color:#c0c5ce;\">&gt;();\n</span>",
         "</code></pre>\n"
     );