From 5a7662ca79840f31cb4682ab23c0176ba2b711fb Mon Sep 17 00:00:00 2001 From: Joe Neeman Date: Fri, 5 Apr 2024 19:29:10 -0500 Subject: [PATCH] Avoid backslashes before a new block. --- fuzz/Cargo.lock | 2 +- src/cm.rs | 15 ++++++++++++--- src/tests/commonmark.rs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 74bb410a..5e73097d 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -128,7 +128,7 @@ checksum = "4f0807fb6f644c83f3e4ec014fec9858c1c8b26a7db8eb5f0bde5817df9c1df7" [[package]] name = "comrak" -version = "0.20.0" +version = "0.22.0" dependencies = [ "arbitrary", "clap", diff --git a/src/cm.rs b/src/cm.rs index 3c2cfbc4..17b30888 100644 --- a/src/cm.rs +++ b/src/cm.rs @@ -326,6 +326,9 @@ impl<'a, 'o> CommonMarkFormatter<'a, 'o> { ) && self.get_in_tight_list_item(node); } + let next_is_block = node + .next_sibling() + .map_or(true, |next| next.data.borrow().value.block()); match node.data.borrow().value { NodeValue::Document => (), @@ -345,7 +348,7 @@ impl<'a, 'o> CommonMarkFormatter<'a, 'o> { NodeValue::Text(ref literal) => { self.format_text(literal.as_bytes(), allow_wrap, entering) } - NodeValue::LineBreak => self.format_line_break(entering), + NodeValue::LineBreak => self.format_line_break(entering, next_is_block), NodeValue::SoftBreak => self.format_soft_break(allow_wrap, entering), NodeValue::Code(ref code) => { self.format_code(code.literal.as_bytes(), allow_wrap, entering) @@ -571,10 +574,16 @@ impl<'a, 'o> CommonMarkFormatter<'a, 'o> { } } - fn format_line_break(&mut self, entering: bool) { + fn format_line_break(&mut self, entering: bool, next_is_block: bool) { if entering { if !self.options.render.hardbreaks { - write!(self, "\\").unwrap(); + if !next_is_block { + // If the next element is a block, a backslash means a + // literal backslash instead of a line break. In this case + // we can just skip the line break since it's meaningless + // before a block. + write!(self, "\\").unwrap(); + } } self.cr(); } diff --git a/src/tests/commonmark.rs b/src/tests/commonmark.rs index 622b4d81..3f297e02 100644 --- a/src/tests/commonmark.rs +++ b/src/tests/commonmark.rs @@ -1,3 +1,7 @@ +use std::cell::RefCell; + +use self::nodes::{Ast, LineColumn}; + use super::*; use ntest::test_case; @@ -11,6 +15,36 @@ fn commonmark_removes_redundant_strong() { commonmark(input, output, Some(&options)); } +#[test] +fn commonmark_avoids_spurious_backslash() { + let arena = Arena::new(); + let options = Options::default(); + let empty = LineColumn { line: 0, column: 0 }; + + let ast = |val: NodeValue| arena.alloc(AstNode::new(RefCell::new(Ast::new(val, empty)))); + let root = ast(NodeValue::Document); + + let p1 = ast(NodeValue::Paragraph); + p1.append(ast(NodeValue::Text("Line 1".to_owned()))); + root.append(p1); + + root.append(ast(NodeValue::LineBreak)); + + let p2 = ast(NodeValue::Paragraph); + p2.append(ast(NodeValue::Text("Line 2".to_owned()))); + root.append(p2); + + let mut output = vec![]; + cm::format_document(root, &options, &mut output).unwrap(); + + compare_strs( + &String::from_utf8(output).unwrap(), + "Line 1\n\nLine 2\n", + "rendered", + "", + ); +} + #[test_case("$$x^2$$ and $1 + 2$ and $`y^2`$", "$$x^2$$ and $1 + 2$ and $`y^2`$\n")] #[test_case("$$\nx^2\n$$", "$$\nx^2\n$$\n")] #[test_case("```math\nx^2\n```", "``` math\nx^2\n```\n")]