From 2dd8024ba73860efcc41f637696dd0b8fdf1c42f Mon Sep 17 00:00:00 2001 From: Dylan Owen Date: Sat, 23 Nov 2019 13:11:05 -0800 Subject: [PATCH 1/3] added blockquote test cases --- tests/fmt.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/fmt.rs b/tests/fmt.rs index aa33f11..a993cdb 100644 --- a/tests/fmt.rs +++ b/tests/fmt.rs @@ -319,6 +319,21 @@ mod blockquote { " > a\n > > \n > > b\n > \n > c", ) } + + #[test] + fn initially_nested() { + assert_eq!( + fmts(indoc!( + " + > > foo + > bar + > > baz + " + )) + .0, + " > > foo\n > > bar\n > > baz", + ) + } #[test] fn simple() { assert_eq!( @@ -337,6 +352,25 @@ mod blockquote { ) ) } + + #[test] + fn with_blank_line() { + assert_eq!( + fmts(indoc!( + " + > foo + + > bar" + )), + ( + " > foo\n\n > bar".into(), + State { + newlines_before_start: 2, + ..Default::default() + } + ) + ) + } } mod codeblock { From 6f0e4b547348da8e9d1f450ccb7183a7f4334287 Mon Sep 17 00:00:00 2001 From: Dylan Owen Date: Sun, 1 Dec 2019 14:15:35 -0800 Subject: [PATCH 2/3] better support for blockquotes --- src/fmt.rs | 26 ++- tests/display.rs | 2 +- .../snapshots/stupicat-ordered-output | 1 + tests/fixtures/snapshots/stupicat-output | 2 + .../fixtures/snapshots/stupicat-table-output | 1 + .../snapshots/stupicat-unordered-output | 1 + tests/fmt.rs | 209 ++++++++++++++---- 7 files changed, 197 insertions(+), 45 deletions(-) diff --git a/src/fmt.rs b/src/fmt.rs index 9335d5c..79a05e1 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -63,6 +63,7 @@ pub struct Options { pub newlines_after_html: usize, pub newlines_after_rule: usize, pub newlines_after_list: usize, + pub newlines_after_blockquote: usize, pub newlines_after_rest: usize, } @@ -76,6 +77,7 @@ impl Default for Options { newlines_after_html: 1, newlines_after_rule: 2, newlines_after_list: 2, + newlines_after_blockquote: 2, newlines_after_rest: 1, } } @@ -172,7 +174,6 @@ where .and_then(|_| formatter.write_char('`')), Start(ref tag) => { match *tag { - BlockQuote => state.padding.push(" > ".into()), List(ref list_type) => { state.list_stack.push(list_type.clone()); if state.list_stack.len() > 1 { @@ -183,7 +184,7 @@ where } _ => {} } - let left_on_padded_newlines = state.newlines_before_start != 0; + let consumed_newlines = state.newlines_before_start != 0; consume_newlines(&mut formatter, &mut state)?; match *tag { Item => match state.list_stack.last() { @@ -220,10 +221,18 @@ where formatter.write_char(' ') } BlockQuote => { - if !left_on_padded_newlines { - padding(&mut formatter, &state.padding) - } else { - Ok(()) + state.padding.push(" > ".into()); + state.newlines_before_start = 1; + + // if we consumed some newlines, we know that we can just write out the next + // level in our blockquote. This should work regardless if we have other + // padding or if we're in a list + if consumed_newlines { + formatter.write_str(" > ") + } + else { + formatter.write_char('\n') + .and(padding(&mut formatter, &state.padding)) } } CodeBlock(ref info) => formatter @@ -344,6 +353,11 @@ where } BlockQuote => { state.padding.pop(); + + if state.newlines_before_start < options.newlines_after_blockquote { + state.newlines_before_start = options.newlines_after_blockquote; + } + Ok(()) } FootnoteDefinition(_) => Ok(()), diff --git a/tests/display.rs b/tests/display.rs index 20613ce..5bfc19e 100644 --- a/tests/display.rs +++ b/tests/display.rs @@ -44,7 +44,7 @@ mod start { } #[test] fn blockquote() { - assert_eq!(s(Start(BlockQuote)), " > ") + assert_eq!(s(Start(BlockQuote)), "\n > ") } #[test] fn codeblock() { diff --git a/tests/fixtures/snapshots/stupicat-ordered-output b/tests/fixtures/snapshots/stupicat-ordered-output index 175aca5..73f068c 100644 --- a/tests/fixtures/snapshots/stupicat-ordered-output +++ b/tests/fixtures/snapshots/stupicat-ordered-output @@ -12,6 +12,7 @@ Ordered lists: 1. With Paragraphs and nested blocks: + > > A quote diff --git a/tests/fixtures/snapshots/stupicat-output b/tests/fixtures/snapshots/stupicat-output index dcb72b1..a673e17 100644 --- a/tests/fixtures/snapshots/stupicat-output +++ b/tests/fixtures/snapshots/stupicat-output @@ -48,6 +48,7 @@ Unordered lists: * With Paragraphs and nested blocks: + > > A quote @@ -93,6 +94,7 @@ And a mix of both: ## Block level elements Block quotes + > > Lorem ipsum dolor sit amet, *consetetur sadipscing elitr*, sed diam nonumy > eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam diff --git a/tests/fixtures/snapshots/stupicat-table-output b/tests/fixtures/snapshots/stupicat-table-output index 93608d5..0a41c51 100644 --- a/tests/fixtures/snapshots/stupicat-table-output +++ b/tests/fixtures/snapshots/stupicat-table-output @@ -9,6 +9,7 @@ Colons can be used to align columns. There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to make the raw Markdown line up prettily. You can also use inline Markdown. + > > |Markdown|Less|Pretty| > |--------|----|------| diff --git a/tests/fixtures/snapshots/stupicat-unordered-output b/tests/fixtures/snapshots/stupicat-unordered-output index 026280e..b8db678 100644 --- a/tests/fixtures/snapshots/stupicat-unordered-output +++ b/tests/fixtures/snapshots/stupicat-unordered-output @@ -10,6 +10,7 @@ Unordered lists: * With Paragraphs and nested blocks: + > > A quote diff --git a/tests/fmt.rs b/tests/fmt.rs index a993cdb..eade72e 100644 --- a/tests/fmt.rs +++ b/tests/fmt.rs @@ -25,6 +25,19 @@ fn fmte(e: &[Event]) -> (String, State<'static>) { (buf, s) } +/// Asserts that if we parse our `str` s into a series of events, then serialize them with `cmark` +/// that we'll get the same series of events when we parse them again. +fn assert_events_eq(s: &str) { + let before_events = Parser::new_ext(s, Options::all()); + + let mut buf = String::new(); + cmark(before_events.clone(), &mut buf, None).unwrap(); + + let after_events = Parser::new_ext(&buf, Options::all()); + println!("{}", buf); + assert_eq!(before_events.collect::>(), after_events.collect::>()); +} + mod lazy_newlines { use super::{fmte, fmts}; use super::{Event, LinkType, State, Tag}; @@ -34,7 +47,6 @@ mod lazy_newlines { for t in &[ Tag::Emphasis, Tag::Strong, - Tag::BlockQuote, Tag::Link(LinkType::Inline, "".into(), "".into()), Tag::Image(LinkType::Inline, "".into(), "".into()), Tag::FootnoteDefinition("".into()), @@ -243,6 +255,7 @@ mod inline_elements { mod blockquote { use super::{fmte, fmtes, fmts, Event, State, Tag}; + use assert_events_eq; #[test] fn it_pops_padding_on_quote_end() { @@ -256,6 +269,7 @@ mod blockquote { ) .1, State { + newlines_before_start: 2, padding: vec![], ..Default::default() } @@ -267,6 +281,7 @@ mod blockquote { assert_eq!( fmte(&[Event::Start(Tag::BlockQuote),]).1, State { + newlines_before_start: 1, padding: vec![" > ".into()], ..Default::default() } @@ -275,76 +290,108 @@ mod blockquote { #[test] fn with_html() { + let s = indoc!(" + > + >
+ "); + + assert_events_eq(s); + assert_eq!( - fmts(indoc!( - " - > - >
" - )) + fmts(s) .0, - " > \n >
", + "\n > \n > \n >
\n > ", ) } #[test] fn with_inlinehtml() { - assert_eq!(fmts(" >
").0, " >
",) + assert_eq!(fmts(" >
").0, "\n > \n >
") } #[test] fn with_codeblock() { - assert_eq!( - fmts(indoc!( - " + let s = indoc!(" > ```a > t1 > t2 > ``` - " - )) + "); + + assert_events_eq(s); + + assert_eq!( + fmts(s) .0, - " > ````a\n > t1\n > t2\n > ````", + "\n > \n > ````a\n > t1\n > t2\n > ````", ) } #[test] fn nested() { - assert_eq!( - fmts(indoc!( - " + let s = indoc!(" > a + > > > b > > c - " - )) + "); + + assert_events_eq(s); + + assert_eq!( + fmts(s) .0, - " > a\n > > \n > > b\n > \n > c", + "\n > \n > a\n > \n > > \n > > b\n > \n > c", ) } #[test] fn initially_nested() { - assert_eq!( - fmts(indoc!( - " + let s = indoc!(" > > foo > bar > > baz - " - )) + "); + + assert_events_eq(s); + + assert_eq!( + fmts(s) .0, - " > > foo\n > > bar\n > > baz", + "\n > \n > > \n > > foo\n > > bar\n > > baz", ) } + #[test] fn simple() { - assert_eq!( - fmts(indoc!( - " + let s = indoc!(" > a > b - > c" - )), + > c + "); + + assert_events_eq(s); + + assert_eq!( + fmts(s), + ( + "\n > \n > a\n > b \n > c".into(), + State { + newlines_before_start: 2, + ..Default::default() + } + ) + ) + } + + #[test] + fn empty() { + let s = " > "; + + assert_events_eq(s); + + assert_eq!( + fmts(s), ( - " > a\n > b \n > c".into(), + "\n > ".into(), State { newlines_before_start: 2, ..Default::default() @@ -355,15 +402,64 @@ mod blockquote { #[test] fn with_blank_line() { + let s = indoc!(" + > foo + + > bar + "); + + assert_events_eq(s); + assert_eq!( - fmts(indoc!( - " - > foo + fmts(s), + ( + "\n > \n > foo\n\n > \n > bar".into(), + State { + newlines_before_start: 2, + ..Default::default() + } + ) + ) + } - > bar" - )), + #[test] + fn with_lazy_continuation() { + let s = indoc!(" + > foo + baz + + > bar + "); + + assert_events_eq(s); + + + assert_eq!( + fmts(s), + ( + "\n > \n > foo\n > baz\n\n > \n > bar".into(), + State { + newlines_before_start: 2, + ..Default::default() + } + ) + ) + } + + #[test] + fn with_lists() { + let s = indoc!(" + - > * foo + > * baz + - > bar + "); + + assert_events_eq(s); + + assert_eq!( + fmts(s), ( - " > foo\n\n > bar".into(), + "* \n > \n > * foo\n > * baz\n \n * \n > \n > bar".into(), State { newlines_before_start: 2, ..Default::default() @@ -371,6 +467,43 @@ mod blockquote { ) ) } + + #[test] + fn complex_nesting() { + assert_events_eq(indoc!( + " + > one + > > two + > > three + > four + > + > > five + > + > > six + > seven + > > > eight + nine + + > ten + + > + + > + > > + + + > > + + > - eleven + > - twelve + > > thirteen + > - + + - > fourteen + - > fifteen + " + )); + } } mod codeblock { From 58e51373d1d517fc5e3f71ab1540411d17c87d2d Mon Sep 17 00:00:00 2001 From: Dylan Owen Date: Sun, 1 Dec 2019 14:17:56 -0800 Subject: [PATCH 3/3] updated authors --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d3fdb4b..12b0e16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "pulldown-cmark-to-cmark" version = "1.2.3" -authors = ["Sebastian Thiel "] +authors = ["Sebastian Thiel ", "Dylan Owen "] description = "Convert pulldown-cmark Events back to the string they were parsed from" license = "Apache-2.0"