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/src/html.rs b/src/html.rs index b759711c..0d633c6b 100644 --- a/src/html.rs +++ b/src/html.rs @@ -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 03b8d5de..2c233981 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -1640,7 +1640,7 @@ impl<'a, 'o> Parser<'a, 'o> {
scanners::description_item_start(&line[self.first_nonspace..]),
&mut matched,
)
- && self.parse_desc_list_details(container)
+ && self.parse_desc_list_details(container, matched)
{
let offset = self.first_nonspace + matched - self.offset;
self.advance_offset(line, offset, false);
@@ -1884,15 +1884,26 @@ impl<'a, 'o> Parser<'a, 'o> {
}
}
- fn parse_desc_list_details(&mut self, node: &mut &'a AstNode<'a>) -> bool {
- let container = node;
-
+ 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 => {
// Happens when the detail line is directly after the term,
// without a blank line between.
- *container = container.parent().unwrap();
+ 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()
}
};
@@ -1918,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.
//
@@ -1941,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(
@@ -1961,11 +1973,15 @@ impl<'a, 'o> Parser<'a, 'o> {
true
} else if node_matches!(last_child, NodeValue::DescriptionItem(..)) {
let parent = last_child.parent().unwrap();
- reopen_ast_nodes(parent);
+ let tight = match last_child.data.borrow().value {
+ NodeValue::DescriptionItem(ref ndi) => ndi.tight,
+ _ => false,
+ };
let metadata = NodeDescriptionItem {
marker_offset: self.indent,
- padding: 2,
+ padding: matched,
+ tight,
};
let item = self.add_child(
diff --git a/src/scanners.re b/src/scanners.re
index ecdcaa8c..f665f854 100644
--- a/src/scanners.re
+++ b/src/scanners.re
@@ -433,10 +433,9 @@ pub fn tasklist(s: &[u8]) -> Option<(usize, u8)> {
pub fn description_item_start(s: &[u8]) -> Option Nested : : foo a\n: `
-tags.
+The list is tight if there is no blank line between
+the term and the first definition, otherwise loose.
```````````````````````````````` example
apple
@@ -24,13 +23,9 @@ orange
.
red fruit orange fruit red fruit orange fruit red fruit computer company orange fruit telecom company red fruit orange fruit Foo baz bor\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",
+ ),
+ no_roundtrip,
+ );
+}
+#[test]
+fn description_lists_edge_cases() {
+ html_opts!(
+ [extension.description_lists],
+ concat!(":"),
+ concat!("\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
index a9ca0fc4..5f689014 100644
--- a/src/tests/fixtures/description_lists.md
+++ b/src/tests/fixtures/description_lists.md
@@ -11,9 +11,8 @@ with `:` (after 0-2 spaces); subsequent lines must
be indented unless they are lazy paragraph
continuations.
-There is no distinction between a "tight" list or a
-"loose" list. Definitions are always wrapped in `\n",
+ "
\n",
+ "
````````````````````````````````
@@ -68,13 +63,9 @@ orange
.
````````````````````````````````
@@ -101,8 +92,6 @@ orange
Multiple blocks in a definition:
-Note that the column
-
```````````````````````````````` example
*apple*
@@ -161,7 +150,6 @@ term
````````````````````````````````
Multiple definitions, tight:
-(always rendered as loose)
```````````````````````````````` example
apple
@@ -174,19 +162,11 @@ orange
.
````````````````````````````````
@@ -271,13 +251,9 @@ orange
.
````````````````````````````````
@@ -315,12 +291,8 @@ bim
````````````````````````````````