Skip to content

Commit

Permalink
Clean up some more gratuitous differences in footnote parsing
Browse files Browse the repository at this point in the history
* This reverses the choice to diverge from GitHub on the
  issue of back-to-back `[shortcut links][^and footnotes]`,
  since other implementations of this feature also do it.
* This stops pulldown-cmark from trying to parse `[^collapsed][]`
  footnote references. Those aren't a thing.

Fixes #772
  • Loading branch information
notriddle committed Nov 3, 2023
1 parent cc77468 commit 8d3923e
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 14 deletions.
13 changes: 7 additions & 6 deletions specs/footnotes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -394,12 +394,13 @@ Songs that simply loop are a popular way to annoy people. [^examples3]
Test case for the relationship between link references and footnotes.
<https://gist.github.com/notriddle/5625a3c1cb70b3067a01d7465f9d10f1>

In this case, pulldown-cmark treats all four `[cmark-gfm]` uses as links.
GitHub, however, writes
GitHub writes
`My [cmark-gfm]<sup class="footnote-reference"><a href="#examples">1</a></sup>.`
in the first paragraph. This seems like a bug, and would require some gymnastics for
pulldown-cmark to copy it, but this test case is kept here to keep track of the decision to
diverge from GFM's behavior.
in the first paragraph. This seems like a bug, but [markdown-it] and [commonmark-hs]
both do it, too, so it's probably not worth it to be different here.

[markdown-it]: https://markdown-it.github.io/#md3=%7B%22source%22%3A%22%5B%5Efoo%5D%5B%5D%5Cn%5Cn%5B%5Efoo%5D%5Bbaz%5D%5Cn%5Cn%5Bbaz%5D%5B%5Efoo%5D%5Cn%5Cn%5B%5Efoo%5D%3A%20bar%5Cn%5Cn%5Bbaz%5D%3A%20https%3A%2F%2Frust-lang.org%22%2C%22defaults%22%3A%7B%22html%22%3Afalse%2C%22xhtmlOut%22%3Afalse%2C%22breaks%22%3Afalse%2C%22langPrefix%22%3A%22language-%22%2C%22linkify%22%3Atrue%2C%22typographer%22%3Atrue%2C%22_highlight%22%3Atrue%2C%22_strict%22%3Afalse%2C%22_view%22%3A%22html%22%7D%7D
[commonmark-hs]: https://pandoc.org/try/?params=%7B%22text%22%3A%22%5B%5Efoo%5D%5B%5D%5Cn%5Cn%5B%5Efoo%5D%5Bbaz%5D%5Cn%5Cn%5Bbaz%5D%5B%5Efoo%5D%5Cn%5Cn%5B%5Efoo%5D%3A+bar%5Cn%5Cn%5Bbaz%5D%3A+https%3A%2F%2Frust-lang.org%22%2C%22to%22%3A%22html5%22%2C%22from%22%3A%22commonmark_x%22%2C%22standalone%22%3Afalse%2C%22embed-resources%22%3Afalse%2C%22table-of-contents%22%3Afalse%2C%22number-sections%22%3Afalse%2C%22citeproc%22%3Afalse%2C%22html-math-method%22%3A%22plain%22%2C%22wrap%22%3A%22auto%22%2C%22highlight-style%22%3Anull%2C%22files%22%3A%7B%7D%2C%22template%22%3Anull%7D

```````````````````````````````` example
My [cmark-gfm][^c].
Expand All @@ -422,7 +423,7 @@ My [otherlink[^c]].

[otherlink[^c]]: https://github.com/github/cmark-gfm/blob/1e230827a584ebc9938c3eadc5059c55ef3c9abf/test/extensions.txt#L702
.
<p>My <a href="https://github.com/github/cmark-gfm/blob/1e230827a584ebc9938c3eadc5059c55ef3c9abf/test/extensions.txt#L702">cmark-gfm</a><sup class="footnote-reference"><a href="#c">1</a></sup>.</p>
<p>My [cmark-gfm]<sup class="footnote-reference"><a href="#c">1</a></sup>.</p>
<p>My <a href="https://github.com/github/cmark-gfm/blob/1e230827a584ebc9938c3eadc5059c55ef3c9abf/test/extensions.txt#L702">cmark-gfm</a><sup class="footnote-reference"><a href="#c">1</a></sup>.</p>
<p>My <a href="https://github.com/github/cmark-gfm/blob/1e230827a584ebc9938c3eadc5059c55ef3c9abf/test/extensions.txt#L702">cmark-gfm</a><sup class="footnote-reference"><a href="#c">1</a></sup>.</p>
<p>My <a href="https://github.com/github/cmark-gfm/blob/1e230827a584ebc9938c3eadc5059c55ef3c9abf/test/extensions.txt#L702">cmark-gfm</a> <sup class="footnote-reference"><a href="#c">1</a></sup>.</p>
Expand Down
21 changes: 21 additions & 0 deletions specs/regression.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1668,3 +1668,24 @@ Second try]: https://rust-lang.org
<h2>[First try</h2>
<p>Second try]: https://rust-lang.org</p>
````````````````````````````````

ISSUE 772

```````````````````````````````` example
[^foo][]

[^foo][baz]

[baz][^foo]

[^foo]: bar

[baz]: https://rust-lang.org
.
<p><sup class="footnote-reference"><a href="#foo">1</a></sup>[]</p>
<p><a href="https://rust-lang.org">^foo</a></p>
<p>[baz]<sup class="footnote-reference"><a href="#foo">1</a></sup></p>
<div class="footnote-definition" id="foo"><sup class="footnote-definition-label">1</sup>
<p>bar</p>
</div>
````````````````````````````````
21 changes: 14 additions & 7 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ impl<'input, F: BrokenLinkCallback<'input>> Parser<'input, F> {
}
(next, LinkType::Shortcut)
}
RefScan::UnexpectedFootnote => continue,
};

// FIXME: references and labels are mixed in the naming of variables
Expand All @@ -458,6 +459,7 @@ impl<'input, F: BrokenLinkCallback<'input>> Parser<'input, F> {
.map(|(ix, label)| (label, label_start + ix))
.filter(|(_, end)| *end == label_end)
}
RefScan::UnexpectedFootnote => continue,
};

let id = match &label {
Expand All @@ -479,13 +481,16 @@ impl<'input, F: BrokenLinkCallback<'input>> Parser<'input, F> {
if !self.options.has_gfm_footnotes()
|| self.allocs.footdefs.contains(&self.allocs.cows[footref.0])
{
self.tree[tos.node].next = node_after_link;
// use `next` instead of `node_after_link` because
// node_after_link is calculated for a [collapsed][] link,
// which footnotes don't support.
self.tree[tos.node].next = next;
self.tree[tos.node].child = None;
self.tree[tos.node].item.body =
ItemBody::FootnoteReference(footref);
self.tree[tos.node].item.end = end;
prev = Some(tos.node);
cur = node_after_link;
cur = next;
self.link_stack.clear();
continue;
}
Expand Down Expand Up @@ -1169,6 +1174,7 @@ enum RefScan<'a> {
LinkLabel(CowStr<'a>, usize),
// contains next node index
Collapsed(Option<TreeIndex>),
UnexpectedFootnote,
Failed,
}

Expand Down Expand Up @@ -1238,12 +1244,13 @@ fn scan_reference<'a, 'b>(
// TODO: this unwrap is sus and should be looked at closer
let closing_node = tree[cur_ix].next.unwrap();
RefScan::Collapsed(tree[closing_node].next)
} else if let Some((ix, ReferenceLabel::Link(label))) =
scan_link_label(tree, &text[start..], allow_footnote_refs, gfm_footnotes)
{
RefScan::LinkLabel(label, start + ix)
} else {
RefScan::Failed
let label = scan_link_label(tree, &text[start..], allow_footnote_refs, gfm_footnotes);
match label {
Some((ix, ReferenceLabel::Link(label))) => RefScan::LinkLabel(label, start + ix),
Some((_ix, ReferenceLabel::Footnote(_label))) => RefScan::UnexpectedFootnote,
None => RefScan::Failed,
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/suite/footnotes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ My [otherlink[^c]].
[otherlink[^c]]: https://github.com/github/cmark-gfm/blob/1e230827a584ebc9938c3eadc5059c55ef3c9abf/test/extensions.txt#L702
"##;
let expected = r##"<p>My <a href="https://github.com/github/cmark-gfm/blob/1e230827a584ebc9938c3eadc5059c55ef3c9abf/test/extensions.txt#L702">cmark-gfm</a><sup class="footnote-reference"><a href="#c">1</a></sup>.</p>
let expected = r##"<p>My [cmark-gfm]<sup class="footnote-reference"><a href="#c">1</a></sup>.</p>
<p>My <a href="https://github.com/github/cmark-gfm/blob/1e230827a584ebc9938c3eadc5059c55ef3c9abf/test/extensions.txt#L702">cmark-gfm</a><sup class="footnote-reference"><a href="#c">1</a></sup>.</p>
<p>My <a href="https://github.com/github/cmark-gfm/blob/1e230827a584ebc9938c3eadc5059c55ef3c9abf/test/extensions.txt#L702">cmark-gfm</a><sup class="footnote-reference"><a href="#c">1</a></sup>.</p>
<p>My <a href="https://github.com/github/cmark-gfm/blob/1e230827a584ebc9938c3eadc5059c55ef3c9abf/test/extensions.txt#L702">cmark-gfm</a> <sup class="footnote-reference"><a href="#c">1</a></sup>.</p>
Expand Down
23 changes: 23 additions & 0 deletions tests/suite/regression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1955,3 +1955,26 @@ Second try]: https://rust-lang.org

test_markdown_html(original, expected, false, false, false);
}

#[test]
fn regression_test_124() {
let original = r##"[^foo][]
[^foo][baz]
[baz][^foo]
[^foo]: bar
[baz]: https://rust-lang.org
"##;
let expected = r##"<p><sup class="footnote-reference"><a href="#foo">1</a></sup>[]</p>
<p><a href="https://rust-lang.org">^foo</a></p>
<p>[baz]<sup class="footnote-reference"><a href="#foo">1</a></sup></p>
<div class="footnote-definition" id="foo"><sup class="footnote-definition-label">1</sup>
<p>bar</p>
</div>
"##;

test_markdown_html(original, expected, false, false, false);
}

0 comments on commit 8d3923e

Please sign in to comment.