diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock
index edf650e3..06300fd2 100644
--- a/fuzz/Cargo.lock
+++ b/fuzz/Cargo.lock
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
-version = 3
+version = 4
[[package]]
name = "adler"
@@ -116,6 +116,31 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+[[package]]
+name = "bon"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a636f83af97c6946f3f5cf5c268ec02375bf5efd371110292dfd57961f57a509"
+dependencies = [
+ "bon-macros",
+ "rustversion",
+]
+
+[[package]]
+name = "bon-macros"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7eaf1bfaa5b8d512abfd36d0c432591fef139d3de9ee54f1f839ea109d70d33"
+dependencies = [
+ "darling",
+ "ident_case",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
[[package]]
name = "bumpalo"
version = "3.16.0"
@@ -198,12 +223,12 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "comrak"
-version = "0.29.0"
+version = "0.30.0"
dependencies = [
"arbitrary",
+ "bon",
"caseless",
"clap",
- "derive_builder",
"emojis",
"entities",
"memchr",
@@ -237,9 +262,9 @@ dependencies = [
[[package]]
name = "darling"
-version = "0.20.9"
+version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1"
+checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
dependencies = [
"darling_core",
"darling_macro",
@@ -247,9 +272,9 @@ dependencies = [
[[package]]
name = "darling_core"
-version = "0.20.9"
+version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120"
+checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
dependencies = [
"fnv",
"ident_case",
@@ -261,9 +286,9 @@ dependencies = [
[[package]]
name = "darling_macro"
-version = "0.20.9"
+version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178"
+checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
@@ -290,37 +315,6 @@ dependencies = [
"syn",
]
-[[package]]
-name = "derive_builder"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7"
-dependencies = [
- "derive_builder_macro",
-]
-
-[[package]]
-name = "derive_builder_core"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d"
-dependencies = [
- "darling",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "derive_builder_macro"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b"
-dependencies = [
- "derive_builder_core",
- "syn",
-]
-
[[package]]
name = "deunicode"
version = "1.4.4"
@@ -561,11 +555,21 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+[[package]]
+name = "prettyplease"
+version = "0.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
[[package]]
name = "proc-macro2"
-version = "1.0.81"
+version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
@@ -630,6 +634,12 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "rustversion"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
+
[[package]]
name = "ryu"
version = "1.0.17"
@@ -706,9 +716,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
-version = "2.0.60"
+version = "2.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
+checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
dependencies = [
"proc-macro2",
"quote",
diff --git a/script/cibuild b/script/cibuild
index 794441cc..64016bb7 100755
--- a/script/cibuild
+++ b/script/cibuild
@@ -48,6 +48,8 @@ python3 spec_tests.py --no-normalize --spec ../../../src/tests/fixtures/wikilink
|| failed=1
python3 spec_tests.py --no-normalize --spec ../../../src/tests/fixtures/wikilinks_title_before_pipe.md "$PROGRAM_ARG -e wikilinks-title-before-pipe" \
|| failed=1
+python3 spec_tests.py --no-normalize --spec ../../../src/tests/fixtures/description_lists.md "$PROGRAM_ARG -e description-lists" \
+ || failed=1
python3 spec_tests.py --no-normalize --spec regression.txt "$PROGRAM_ARG" \
|| failed=1
diff --git a/src/html.rs b/src/html.rs
index eb542c5d..0d633c6b 100644
--- a/src/html.rs
+++ b/src/html.rs
@@ -479,7 +479,7 @@ impl<'o> HtmlFormatter<'o> {
self.cr()?;
self.output.write_all(b"
")?;
+ self.output.write_all(b">\n")?;
} else {
self.output.write_all(b"
\n")?;
}
@@ -663,6 +663,7 @@ impl<'o> HtmlFormatter<'o> {
.map(|n| n.data.borrow().value.clone())
{
Some(NodeValue::List(nl)) => nl.tight,
+ Some(NodeValue::DescriptionItem(nd)) => nd.tight,
_ => false,
};
diff --git a/src/nodes.rs b/src/nodes.rs
index ec6e549c..85407a7a 100644
--- a/src/nodes.rs
+++ b/src/nodes.rs
@@ -313,6 +313,10 @@ pub struct NodeDescriptionItem {
/// Number of characters between the start of the list marker and the item text (including the list marker(s)).
pub padding: usize,
+
+ /// Whether the list is [tight](https://github.github.com/gfm/#tight), i.e. whether the
+ /// paragraphs are wrapped in `` tags when formatted as HTML.
+ pub tight: bool,
}
/// The type of list.
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index e08fdc01..2c233981 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -334,7 +334,7 @@ pub struct ExtensionOptions {
/// let mut options = Options::default();
/// options.extension.description_lists = true;
/// assert_eq!(markdown_to_html("Term\n\n: Definition", &options),
- /// "
- Term
\n- \n
Definition
\n \n
\n");
+ /// "\n- Term
\n- \n
Definition
\n \n
\n");
/// ```
#[builder(default)]
pub description_lists: bool,
@@ -1636,10 +1636,13 @@ impl<'a, 'o> Parser<'a, 'o> {
container.data.borrow_mut().internal_offset = matched;
} else if !indented
&& self.options.extension.description_lists
- && line[self.first_nonspace] == b':'
- && self.parse_desc_list_details(container)
+ && unwrap_into(
+ scanners::description_item_start(&line[self.first_nonspace..]),
+ &mut matched,
+ )
+ && self.parse_desc_list_details(container, matched)
{
- let offset = self.first_nonspace + 1 - self.offset;
+ let offset = self.first_nonspace + matched - self.offset;
self.advance_offset(line, offset, false);
if strings::is_space_or_tab(line[self.offset]) {
self.advance_offset(line, 1, true);
@@ -1881,10 +1884,28 @@ impl<'a, 'o> Parser<'a, 'o> {
}
}
- fn parse_desc_list_details(&mut self, container: &mut &'a AstNode<'a>) -> bool {
+ fn parse_desc_list_details(&mut self, container: &mut &'a AstNode<'a>, matched: usize) -> bool {
+ let mut tight = false;
let last_child = match container.last_child() {
Some(lc) => lc,
- None => return false,
+ None => {
+ // Happens when the detail line is directly after the term,
+ // without a blank line between.
+ if !node_matches!(container, NodeValue::Paragraph) {
+ // If the container is not a paragraph, then this can't
+ // be a description list item.
+ return false;
+ }
+
+ let parent = container.parent();
+ if parent.is_none() {
+ return false;
+ }
+
+ tight = true;
+ *container = parent.unwrap();
+ container.last_child().unwrap()
+ }
};
if node_matches!(last_child, NodeValue::Paragraph) {
@@ -1908,7 +1929,7 @@ impl<'a, 'o> Parser<'a, 'o> {
// All are incorrect; they all give the start line/col of
// the DescriptionDetails, and the end line/col is completely off.
//
- // descriptionDetails:
+ // DescriptionDetails:
// Same as the DescriptionItem. All but last, the end line/col
// is (l+1):0.
//
@@ -1931,7 +1952,8 @@ impl<'a, 'o> Parser<'a, 'o> {
let metadata = NodeDescriptionItem {
marker_offset: self.indent,
- padding: 2,
+ padding: matched,
+ tight,
};
let item = self.add_child(
@@ -1948,6 +1970,31 @@ impl<'a, 'o> Parser<'a, 'o> {
*container = details;
+ true
+ } else if node_matches!(last_child, NodeValue::DescriptionItem(..)) {
+ let parent = last_child.parent().unwrap();
+ let tight = match last_child.data.borrow().value {
+ NodeValue::DescriptionItem(ref ndi) => ndi.tight,
+ _ => false,
+ };
+
+ let metadata = NodeDescriptionItem {
+ marker_offset: self.indent,
+ padding: matched,
+ tight,
+ };
+
+ let item = self.add_child(
+ parent,
+ NodeValue::DescriptionItem(metadata),
+ self.first_nonspace + 1,
+ );
+
+ let details =
+ self.add_child(item, NodeValue::DescriptionDetails, self.first_nonspace + 1);
+
+ *container = details;
+
true
} else {
false
diff --git a/src/scanners.re b/src/scanners.re
index 35bbc4f6..f665f854 100644
--- a/src/scanners.re
+++ b/src/scanners.re
@@ -431,4 +431,13 @@ pub fn tasklist(s: &[u8]) -> Option<(usize, u8)> {
*/
}
+pub fn description_item_start(s: &[u8]) -> Option {
+ let mut cursor = 0;
+ let len = s.len();
+/*!re2c
+ [:~] ([ \t]+) { return Some(cursor); }
+ * { return None; }
+*/
+}
+
// vim: set ft=rust:
diff --git a/src/scanners.rs b/src/scanners.rs
index 52b2a747..29eca63b 100644
--- a/src/scanners.rs
+++ b/src/scanners.rs
@@ -1,4 +1,4 @@
-/* Generated by re2c 3.1 */
+/* Generated by re2rust 4.0 */
pub fn atx_heading_start(s: &[u8]) -> Option {
let mut cursor = 0;
@@ -246,9 +246,7 @@ pub fn atx_heading_start(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -2065,9 +2063,7 @@ pub fn html_block_end_1(s: &[u8]) -> bool {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -2747,9 +2743,7 @@ pub fn html_block_end_2(s: &[u8]) -> bool {
25 => {
return true;
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -3369,9 +3363,7 @@ pub fn html_block_end_3(s: &[u8]) -> bool {
24 => {
return true;
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -3900,9 +3892,7 @@ pub fn html_block_end_4(s: &[u8]) -> bool {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -4582,9 +4572,7 @@ pub fn html_block_end_5(s: &[u8]) -> bool {
25 => {
return true;
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -5280,9 +5268,7 @@ pub fn open_code_fence(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -5544,9 +5530,7 @@ pub fn close_code_fence(s: &[u8]) -> Option {
return Some(cursor);
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -9164,9 +9148,7 @@ pub fn html_block_start(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -10279,9 +10261,7 @@ pub fn html_block_start_7(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -10509,9 +10489,7 @@ pub fn setext_heading_line(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -10845,9 +10823,7 @@ pub fn footnote_definition(s: &[u8]) -> Option {
17 => {
return Some(cursor);
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -11690,9 +11666,7 @@ pub fn scheme(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -12735,9 +12709,7 @@ pub fn autolink_uri(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -16586,9 +16558,7 @@ pub fn autolink_email(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -17635,9 +17605,7 @@ pub fn html_tag(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -18030,9 +17998,7 @@ pub fn html_comment(s: &[u8]) -> Option {
15 => {
return Some(cursor);
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -18559,9 +18525,7 @@ pub fn html_processing_instruction(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -18868,9 +18832,7 @@ pub fn html_declaration(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -19347,9 +19309,7 @@ pub fn html_cdata(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -19411,9 +19371,7 @@ pub fn spacechars(s: &[u8]) -> Option {
3 => {
return Some(cursor);
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -20588,9 +20546,7 @@ pub fn link_title(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -21372,9 +21328,7 @@ pub fn dangerous_url(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -21703,9 +21657,7 @@ pub fn table_start(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -22279,9 +22231,7 @@ pub fn table_cell(s: &[u8], spoiler: bool) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -22781,9 +22731,7 @@ pub fn table_cell(s: &[u8], spoiler: bool) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -22846,9 +22794,7 @@ pub fn table_cell_end(s: &[u8]) -> Option {
3 => {
return Some(cursor);
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -23000,9 +22946,7 @@ pub fn table_row_end(s: &[u8]) -> Option {
}
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -23102,9 +23046,7 @@ pub fn shortcode(s: &[u8]) -> Option {
7 => {
return Some(cursor);
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -23258,9 +23200,7 @@ pub fn open_multiline_block_quote_fence(s: &[u8]) -> Option {
return Some(cursor);
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -23414,9 +23354,7 @@ pub fn close_multiline_block_quote_fence(s: &[u8]) -> Option {
return Some(cursor);
}
}
- _ => {
- panic!("internal lexer error")
- }
+ _ => panic!("internal lexer error"),
}
}
}
@@ -23840,9 +23778,93 @@ pub fn tasklist(s: &[u8]) -> Option<(usize, u8)> {
return Some((cursor, s[t1]));
}
}
- _ => {
- panic!("internal lexer error")
+ _ => panic!("internal lexer error"),
+ }
+ }
+ }
+}
+
+pub fn description_item_start(s: &[u8]) -> Option {
+ let mut cursor = 0;
+ let len = s.len();
+
+ {
+ #[allow(unused_assignments)]
+ let mut yych: u8 = 0;
+ let mut yystate: usize = 0;
+ 'yyl: loop {
+ match yystate {
+ 0 => {
+ yych = unsafe {
+ if cursor < len {
+ *s.get_unchecked(cursor)
+ } else {
+ 0
+ }
+ };
+ cursor += 1;
+ match yych {
+ 0x3A | 0x7E => {
+ yystate = 3;
+ continue 'yyl;
+ }
+ _ => {
+ yystate = 1;
+ continue 'yyl;
+ }
+ }
+ }
+ 1 => {
+ yystate = 2;
+ continue 'yyl;
+ }
+ 2 => {
+ return None;
+ }
+ 3 => {
+ yych = unsafe {
+ if cursor < len {
+ *s.get_unchecked(cursor)
+ } else {
+ 0
+ }
+ };
+ match yych {
+ 0x09 | 0x20 => {
+ cursor += 1;
+ yystate = 4;
+ continue 'yyl;
+ }
+ _ => {
+ yystate = 2;
+ continue 'yyl;
+ }
+ }
+ }
+ 4 => {
+ yych = unsafe {
+ if cursor < len {
+ *s.get_unchecked(cursor)
+ } else {
+ 0
+ }
+ };
+ match yych {
+ 0x09 | 0x20 => {
+ cursor += 1;
+ yystate = 4;
+ continue 'yyl;
+ }
+ _ => {
+ yystate = 5;
+ continue 'yyl;
+ }
+ }
+ }
+ 5 => {
+ return Some(cursor);
}
+ _ => panic!("internal lexer error"),
}
}
}
diff --git a/src/tests/description_lists.rs b/src/tests/description_lists.rs
index 06970fc0..e2bd23cd 100644
--- a/src/tests/description_lists.rs
+++ b/src/tests/description_lists.rs
@@ -1,7 +1,7 @@
use super::*;
#[test]
-fn description_lists() {
+fn description_lists_loose() {
html_opts!(
[extension.description_lists],
concat!(
@@ -14,7 +14,7 @@ fn description_lists() {
": Definition 2\n"
),
concat!(
- "",
+ "\n",
"- Term 1
\n",
"- \n",
"
Definition 1
\n",
@@ -41,7 +41,7 @@ fn description_lists() {
"\n",
"- \n",
"
Nested
\n",
- "",
+ "\n",
"- Term 1
\n",
"- \n",
"
Definition 1
\n",
@@ -57,6 +57,89 @@ fn description_lists() {
);
}
+#[test]
+fn description_lists_tight() {
+ html_opts!(
+ [extension.description_lists],
+ concat!(
+ "Term 1\n",
+ ": Definition 1\n",
+ "\n",
+ "Term 2 with *inline markup*\n",
+ ": Definition 2\n"
+ ),
+ concat!(
+ "\n",
+ "- Term 1
\n",
+ "- Definition 1
\n",
+ "- Term 2 with inline markup
\n",
+ "- Definition 2
\n",
+ "
\n",
+ ),
+ no_roundtrip,
+ );
+
+ html_opts!(
+ [extension.description_lists],
+ concat!(
+ "* Nested\n",
+ "\n",
+ " Term 1\n",
+ " : Definition 1\n\n",
+ " Term 2 with *inline markup*\n",
+ " : Definition 2\n\n"
+ ),
+ concat!(
+ "\n",
+ "- \n",
+ "
Nested
\n",
+ "\n",
+ "- Term 1
\n",
+ "- Definition 1
\n",
+ "- Term 2 with inline markup
\n",
+ "- Definition 2
\n",
+ "
\n",
+ " \n",
+ "
\n",
+ ),
+ no_roundtrip,
+ );
+}
+#[test]
+fn description_lists_edge_cases() {
+ html_opts!(
+ [extension.description_lists],
+ concat!(":"),
+ concat!(":
\n"),
+ );
+
+ html_opts!(
+ [extension.description_lists],
+ concat!(": foo"),
+ concat!(": foo
\n"),
+ );
+
+ html_opts!(
+ [extension.description_lists],
+ concat!("a\n:"),
+ concat!("a\n:
\n"),
+ );
+
+ html_opts!(
+ [extension.description_lists],
+ concat!("- foo\n", "- : bar\n", " - baz\n",),
+ concat!(
+ "\n",
+ "- foo
\n",
+ "- : bar\n",
+ "\n",
+ "
\n",
+ "
\n",
+ ),
+ );
+}
#[test]
fn sourcepos() {
// TODO There's plenty of work to do here still. The test currently represents
diff --git a/src/tests/fixtures/description_lists.md b/src/tests/fixtures/description_lists.md
new file mode 100644
index 00000000..5f689014
--- /dev/null
+++ b/src/tests/fixtures/description_lists.md
@@ -0,0 +1,298 @@
+---
+title: Description / defintition lists
+based_on: https://github.com/jgm/commonmark-hs/blob/master/commonmark-extensions/test/definition_lists.md
+---
+
+## Definition lists
+
+The term is given on a line by itself, followed by
+one or more definitions. Each definition must begin
+with `:` (after 0-2 spaces); subsequent lines must
+be indented unless they are lazy paragraph
+continuations.
+
+The list is tight if there is no blank line between
+the term and the first definition, otherwise loose.
+
+```````````````````````````````` example
+apple
+: red fruit
+
+orange
+: orange fruit
+.
+
+- apple
+- red fruit
+- orange
+- orange fruit
+
+````````````````````````````````
+
+Loose:
+
+```````````````````````````````` example
+apple
+
+: red fruit
+
+orange
+
+: orange fruit
+.
+
+- apple
+-
+
red fruit
+
+- orange
+-
+
orange fruit
+
+
+````````````````````````````````
+
+Indented marker:
+
+```````````````````````````````` example
+apple
+ : red fruit
+
+orange
+ : orange fruit
+.
+
+- apple
+- red fruit
+- orange
+- orange fruit
+
+````````````````````````````````
+
+```````````````````````````````` example
+apple
+
+ : red fruit
+
+orange
+
+ : orange fruit
+.
+
+- apple
+-
+
red fruit
+
+- orange
+-
+
orange fruit
+
+
+````````````````````````````````
+
+Multiple blocks in a definition:
+
+```````````````````````````````` example
+*apple*
+
+: red fruit
+
+ contains seeds,
+ crisp, pleasant to taste
+
+*orange*
+
+: orange fruit
+
+ { orange code block }
+
+ > orange block quote
+.
+
+- apple
+-
+
red fruit
+contains seeds,
+crisp, pleasant to taste
+
+- orange
+-
+
orange fruit
+{ orange code block }
+
+
+orange block quote
+
+
+
+````````````````````````````````
+
+Nested lists:
+
+```````````````````````````````` example
+term
+
+: 1. Para one
+
+ Para two
+.
+
+- term
+-
+
+-
+
Para one
+Para two
+
+
+
+
+````````````````````````````````
+
+Multiple definitions, tight:
+
+```````````````````````````````` example
+apple
+: red fruit
+: computer company
+
+orange
+: orange fruit
+: telecom company
+.
+
+- apple
+- red fruit
+- computer company
+- orange
+- orange fruit
+- telecom company
+
+````````````````````````````````
+
+Multiple definitions, loose:
+
+```````````````````````````````` example
+apple
+
+: red fruit
+
+: computer company
+
+orange
+
+: orange fruit
+: telecom company
+.
+
+- apple
+-
+
red fruit
+
+-
+
computer company
+
+- orange
+-
+
orange fruit
+
+-
+
telecom company
+
+
+````````````````````````````````
+
+Lazy line continuations:
+
+```````````````````````````````` example
+apple
+
+: red fruit
+
+: computer
+company
+
+orange
+
+: orange
+fruit
+: telecom company
+.
+
+- apple
+-
+
red fruit
+
+-
+
computer
+company
+
+- orange
+-
+
orange
+fruit
+
+-
+
telecom company
+
+
+````````````````````````````````
+
+
+
+`~` may be used as a marker instead of `:`:
+
+```````````````````````````````` example
+apple
+ ~ red fruit
+
+orange
+ ~ orange fruit
+.
+
+- apple
+- red fruit
+- orange
+- orange fruit
+
+````````````````````````````````
+
+Definition terms may span multiple lines:
+
+```````````````````````````````` example
+a
+b\
+c
+
+: foo
+.
+
+- a
+b
+c
+-
+
foo
+
+
+````````````````````````````````
+
+Definition list with preceding paragraph
+():
+
+```````````````````````````````` example
+Foo
+
+bar
+: baz
+
+bim
+: bor
+.
+Foo
+
+- bar
+- baz
+- bim
+- bor
+
+````````````````````````````````