From 085c380f4e0d903708e6a5af4256c07393ace6c3 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 | 64 ++++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 8a13db9f09..32c275f611 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -906,28 +906,42 @@ fn hide_lines(content: &str) -> String { } let mut result = String::with_capacity(content.len()); - for line in content.lines() { + let mut lines = content.lines(); + let last_line = lines.next_back(); + let mut handle_line = |line: &str, newline: &str| { if let Some(caps) = BORING_LINES_REGEX.captures(line) { if &caps[2] == "#" { result += &caps[1]; result += &caps[2]; result += &caps[3]; result += "\n"; - continue; - } else if &caps[2] != "!" && &caps[2] != "[" { + return; + } + + if &caps[2] != "!" && &caps[2] != "[" { result += ""; result += &caps[1]; if &caps[2] != " " { result += &caps[2]; } result += &caps[3]; - result += "\n"; + result += newline; result += ""; - continue; + return; } } + result += line; - result += "\n"; + result += newline; + }; + + // Iterate over all lines except the last: + for line in lines { + handle_line(line, "\n"); + } + // Handle the last line, if any: + if let Some(line) = last_line { + handle_line(line, ""); } result } @@ -1007,19 +1021,19 @@ mod tests { fn add_playground() { let inputs = [ ("x()", - "
\n#![allow(unused)]\nfn main() {\nx()\n}\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( @@ -1037,13 +1051,13 @@ mod tests { fn add_playground_edition2015() { let inputs = [ ("x()", - "
\n#![allow(unused)]\nfn main() {\nx()\n}\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( @@ -1061,13 +1075,13 @@ mod tests { fn add_playground_edition2018() { let inputs = [ ("x()", - "
\n#![allow(unused)]\nfn main() {\nx()\n}\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( @@ -1085,13 +1099,13 @@ mod tests { fn add_playground_edition2021() { let inputs = [ ("x()", - "
\n#![allow(unused)]\nfn main() {\nx()\n}\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(