From 217546c2a056be7a95d029b3265bce66bd79cee4 Mon Sep 17 00:00:00 2001 From: Martin Geisler Date: Wed, 29 Jun 2022 10:31:44 +0200 Subject: [PATCH] Trim trailing whitespace in Rust code blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before, a code block would always end with a final newline. The newline was added unconditionally by `hide_lines`. When the code block is syntax highlighted by highlight.js, this is not a problem, no empty line is added for a final trailing `\n` character. However, when the code block is editable and thus handled by the ACE editor, a trailing newline _is_ significant. I believe this issue is most closely described by https://github.com/ajaxorg/ace/issues/2083 in the upstream repository. The effect of the way ACE handles newlines is that a code block like
      Some code
    
will create an editor with _two_ lines, not just one. By trimming trailing whitespace, we ensure that we don’t accidentally create more lines in the ACE editor than necessary. --- src/renderer/html_handlebars/hbs_renderer.rs | 49 +++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 26f1432c..6debd669 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -903,13 +903,16 @@ fn hide_lines(content: &str) -> String { } let mut result = String::with_capacity(content.len()); - for line in content.lines() { + let mut lines = content.lines().peekable(); + while let Some(line) = lines.next() { + // Don't include newline on the last line. + let newline = if lines.peek().is_none() { "" } else { "\n" }; if let Some(caps) = BORING_LINES_REGEX.captures(line) { if &caps[2] == "#" { result += &caps[1]; result += &caps[2]; result += &caps[3]; - result += "\n"; + result += newline; continue; } else if &caps[2] != "!" && &caps[2] != "[" { result += ""; @@ -918,13 +921,13 @@ fn hide_lines(content: &str) -> String { result += &caps[2]; } result += &caps[3]; - result += "\n"; + result += newline; result += ""; continue; } } result += line; - result += "\n"; + result += newline; } result } @@ -1004,19 +1007,19 @@ mod tests { fn add_playground() { let inputs = [ ("x()", - "
#![allow(unused)]\nfn main() {\nx()\n}\n
"), + "
#![allow(unused)]\nfn main() {\nx()\n}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("let s = \"foo\n # bar\n\";", - "
let s = \"foo\n bar\n\";\n
"), + "
let s = \"foo\n bar\n\";
"), ("let s = \"foo\n ## bar\n\";", - "
let s = \"foo\n # bar\n\";\n
"), + "
let s = \"foo\n # bar\n\";
"), ("let s = \"foo\n # bar\n#\n\";", - "
let s = \"foo\n bar\n\n\";\n
"), + "
let s = \"foo\n bar\n\n\";
"), ("let s = \"foo\n # bar\n\";", - "let s = \"foo\n bar\n\";\n"), + "let s = \"foo\n bar\n\";"), ("#![no_std]\nlet s = \"foo\";\n #[some_attr]", - "
#![no_std]\nlet s = \"foo\";\n #[some_attr]\n
"), + "
#![no_std]\nlet s = \"foo\";\n #[some_attr]
"), ]; for (src, should_be) in &inputs { let got = add_playground_pre( @@ -1034,13 +1037,13 @@ mod tests { fn add_playground_edition2015() { let inputs = [ ("x()", - "
#![allow(unused)]\nfn main() {\nx()\n}\n
"), + "
#![allow(unused)]\nfn main() {\nx()\n}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ]; for (src, should_be) in &inputs { let got = add_playground_pre( @@ -1058,13 +1061,13 @@ mod tests { fn add_playground_edition2018() { let inputs = [ ("x()", - "
#![allow(unused)]\nfn main() {\nx()\n}\n
"), + "
#![allow(unused)]\nfn main() {\nx()\n}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ]; for (src, should_be) in &inputs { let got = add_playground_pre( @@ -1082,13 +1085,13 @@ mod tests { fn add_playground_edition2021() { let inputs = [ ("x()", - "
#![allow(unused)]\nfn main() {\nx()\n}\n
"), + "
#![allow(unused)]\nfn main() {\nx()\n}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ("fn main() {}", - "
fn main() {}\n
"), + "
fn main() {}
"), ]; for (src, should_be) in &inputs { let got = add_playground_pre(