Repository: raphlinus/pulldown-cmark (rust)

Issue:
[fuzz result] footnote definition not parsed when there's <4 spaces indentation
`foo` and `bar` should both be footnote definitions, but `foo` is getting parsed as a link (and the reference made later isn't working right):

```markdown
 [^foo]: x

[^bar]: x

Test [^foo] / [^bar]  
```

Result:

```html
<div class="footnote-definition" id="bar"><sup class="footnote-definition-label">1</sup>
<p>x</p>
</div>
<p>Test [^foo] / <sup class="footnote-reference"><a href="#bar">1</a></sup></p>
```

<details>

Events from pulldown-cmark:

```rust
" [^|]:\n" -> [
  Start(Paragraph)
    Text(Boxed("[^|]:"))
  End(Paragraph)
]
```

Events from pandoc:

```rust
" [^|]:\n" -> [
]
```


Pull request:
Allow up to three spaces indentation before footnote definition
Fixes #758 

This matches GitHub and commonmark-hs's behavior.

> footnote [^baz]
> footnote [^quux]
>
>     [^quux]: x
>
>    [^baz]: x


Patch:
diff --git a/specs/footnotes.txt b/specs/footnotes.txt
index 5bad835..913c499 100644
--- a/specs/footnotes.txt
+++ b/specs/footnotes.txt
@@ -552,3 +552,23 @@ Test [^] link
 .
 <p>Test <a href="https://rust-lang.org">^</a> link</p>
 ````````````````````````````````
+
+Footnote definitions can be indented up to three spaces.
+At four spaces, it becomes a code block.
+
+```````````````````````````````` example
+footnote [^baz]
+footnote [^quux]
+
+    [^quux]: x
+
+   [^baz]: x
+.
+<p>footnote <sup class="footnote-reference"><a href="#baz">1</a></sup>
+footnote [^quux]</sup></p>
+<pre><code>[^quux]: x
+</code></pre>
+<div class="footnote-definition" id="baz"><sup class="footnote-definition-label">1</sup>
+<p>x</p>
+</div>
+````````````````````````````````
diff --git a/src/firstpass.rs b/src/firstpass.rs
index a638a84..f3e37e3 100644
--- a/src/firstpass.rs
+++ b/src/firstpass.rs
@@ -101,10 +101,18 @@ impl<'a, 'b> FirstPass<'a, 'b> {
             // Footnote definitions of the form
             // [^bar]:
             //     * anything really
-            let container_start = start_ix + line_start.bytes_scanned();
-            if let Some(bytecount) = self.parse_footnote(container_start) {
-                start_ix = container_start + bytecount;
-                line_start = LineStart::new(&bytes[start_ix..]);
+            let save = line_start.clone();
+            let indent = line_start.scan_space_upto(4);
+            if indent < 4 {
+                let container_start = start_ix + line_start.bytes_scanned();
+                if let Some(bytecount) = self.parse_footnote(container_start) {
+                    start_ix = container_start + bytecount;
+                    line_start = LineStart::new(&bytes[start_ix..]);
+                } else {
+                    line_start = save;
+                }
+            } else {
+                line_start = save;
             }
         }
 


Test patch:
diff --git a/tests/suite/footnotes.rs b/tests/suite/footnotes.rs
index 56b135b..fb2d924 100644
--- a/tests/suite/footnotes.rs
+++ b/tests/suite/footnotes.rs
@@ -545,3 +545,24 @@ fn footnotes_test_20() {
 
     test_markdown_html(original, expected, false, false, false);
 }
+
+#[test]
+fn footnotes_test_21() {
+    let original = r##"footnote [^baz]
+footnote [^quux]
+
+    [^quux]: x
+
+   [^baz]: x
+"##;
+    let expected = r##"<p>footnote <sup class="footnote-reference"><a href="#baz">1</a></sup>
+footnote [^quux]</sup></p>
+<pre><code>[^quux]: x
+</code></pre>
+<div class="footnote-definition" id="baz"><sup class="footnote-definition-label">1</sup>
+<p>x</p>
+</div>
+"##;
+
+    test_markdown_html(original, expected, false, false, false);
+}