diff --git a/bench/benches/html_rendering.rs b/bench/benches/html_rendering.rs index 788866eb..a440c324 100644 --- a/bench/benches/html_rendering.rs +++ b/bench/benches/html_rendering.rs @@ -101,6 +101,74 @@ This is a [link](example.com). **Cool!** b.iter(|| Parser::new_ext(input, Options::empty()).count()); }); + + c.bench_function("html_block_type_1", |b| { + let input = concat!( + "", + ); + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("html_block_type_2", |b| { + let input = concat!( + "", + ); + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("html_block_type_3", |b| { + let input = concat!( + "", + include_str!("../third_party/markdown-it/lorem1.md"), + "?>", + ); + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("html_block_type_4", |b| { + let input = concat!( + "", + ); + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("html_block_type_5", |b| { + let input = concat!( + "", + ); + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("html_block_type_6", |b| { + let input = concat!( + "
+alert(1) + + +# Title + +`, ``, ``, +`` ends a block started by any of the four. + +```````````````````````````````` example + +*b* +. +", "", ""]; + +/// Whether `line` meets the end condition of an HTML block whose start gave `html_end_tag`. +/// For blocks started by `text+*emphasis* +. + +Title
+text+emphasis
+```````````````````````````````` + +The end tag need not match the start tag: any of `
`, `?>`, `]]>`, `>`) have no letters.
+fn ends_html_block(line: &[u8], block_type: HtmlBlockType1Through5) -> bool {
+ let end_condition_without_gt: &[u8] = match block_type {
+ HtmlBlockType1Through5::Type1 => {
+ // Every type 1 end tag starts with `<`: try all four at each `<` in one pass.
+ return memchr::memchr_iter(b'<', line).any(|i| {
+ HTML_BLOCK_TYPE_1_END_TAGS.iter().any(|tag| {
+ line.get(i..i + tag.len()).map_or(false, |candidate| {
+ candidate.eq_ignore_ascii_case(tag.as_bytes())
+ })
+ })
+ });
+ }
+ HtmlBlockType1Through5::Type2 => b"--",
+ HtmlBlockType1Through5::Type3 => b"?",
+ HtmlBlockType1Through5::Type4 => b"",
+ HtmlBlockType1Through5::Type5 => b"]]",
+ };
+ memchr::memchr_iter(b'>', line).any(|i| {
+ line[..i].ends_with(end_condition_without_gt)
+ })
+}
+
+///
+#[derive(Clone, Copy)]
+pub(crate) enum HtmlBlockType1Through5 {
+ /// Start condition: line begins with the string , or the end of the line.
+ ///
+ /// End condition: line contains an end tag
, , , or
+ /// (case-insensitive; it need not match the start tag).
+ Type1,
+ /// Start condition: line begins with the string .
+ Type2,
+ /// Start condition: line begins with the string .
+ ///
+ /// End condition: line contains the string ?>.
+ Type3,
+ /// Start condition: line begins with the string .
+ Type4,
+ /// Start condition: line begins with the string .
+ Type5,
+}
+
/// Assumes `text_bytes` is preceded by `<`.
-fn get_html_end_tag(text_bytes: &[u8]) -> Option<&'static str> {
+fn get_html_block_type_1_through_5(text_bytes: &[u8]) -> Option {
+ use HtmlBlockType1Through5::*;
static BEGIN_TAGS: &[&[u8]; 4] = &[b"pre", b"style", b"script", b"textarea"];
static ST_BEGIN_TAGS: &[&[u8]; 3] = &[b"!--", b"?", b"![CDATA["];
- for (beg_tag, end_tag) in BEGIN_TAGS
- .iter()
- .zip([" ", "", "", ""].iter())
- {
+ for beg_tag in BEGIN_TAGS {
let tag_len = beg_tag.len();
if text_bytes.len() < tag_len {
@@ -2420,24 +2473,24 @@ fn get_html_end_tag(text_bytes: &[u8]) -> Option<&'static str> {
// Must either be the end of the line...
if text_bytes.len() == tag_len {
- return Some(end_tag);
+ return Some(Type1);
}
// ...or be followed by whitespace, newline, or '>'.
let s = text_bytes[tag_len];
if is_ascii_whitespace(s) || s == b'>' {
- return Some(end_tag);
+ return Some(Type1);
}
}
- for (beg_tag, end_tag) in ST_BEGIN_TAGS.iter().zip(["-->", "?>", "]]>"].iter()) {
+ for (beg_tag, block_type) in ST_BEGIN_TAGS.iter().zip([Type2, Type3, Type5].iter()) {
if text_bytes.starts_with(beg_tag) {
- return Some(end_tag);
+ return Some(*block_type);
}
}
if text_bytes.len() > 1 && text_bytes[0] == b'!' && text_bytes[1].is_ascii_alphabetic() {
- Some(">")
+ Some(Type4)
} else {
None
}
diff --git a/pulldown-cmark/tests/suite/regression.rs b/pulldown-cmark/tests/suite/regression.rs
index c703fbad..55f6f5bb 100644
--- a/pulldown-cmark/tests/suite/regression.rs
+++ b/pulldown-cmark/tests/suite/regression.rs
@@ -3965,3 +3965,85 @@ fn regression_test_249() {
test_markdown_html(original, expected, false, false, false, false, false, false, false, false, false);
}
+
+#[test]
+fn regression_test_250() {
+ let original = r##"
+
+# Title
+
+text+*emphasis* +"##; + let expected = r##" +
text+
emphasis
+"##; + + test_markdown_html(original, expected, false, false, false, false, false, false, false, false, false); +} + +#[test] +fn regression_test_251() { + let original = r##" +*b* +"##; + let expected = r##"