diff --git a/CHANGES.md b/CHANGES.md index 5b89e158..6d62d770 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ - [pull #529] Add `breaks` extra with ability to hard break on backslashes (issue #525) - [pull #532] Fix #493 persisting when `code-friendly` extra enabled - [pull #535] Update `_slugify` to use utf-8 encoding (issue #534) +- [pull #536] Maintain order of appearance in footnotes ## python-markdown2 2.4.10 diff --git a/lib/markdown2.py b/lib/markdown2.py index 34d8d609..48c2b281 100755 --- a/lib/markdown2.py +++ b/lib/markdown2.py @@ -115,7 +115,7 @@ import logging import re import sys -from collections import defaultdict +from collections import defaultdict, OrderedDict from hashlib import sha256 from random import randint, random @@ -280,7 +280,9 @@ def reset(self): def _setup_extras(self): if "footnotes" in self.extras: - self.footnotes = {} + # order of insertion matters for footnotes. Use ordered dict for Python < 3.7 + # https://docs.python.org/3/whatsnew/3.7.html#summary-release-highlights + self.footnotes = OrderedDict() self.footnote_ids = [] if "header-ids" in self.extras: self._count_from_header_id = defaultdict(int) @@ -2508,6 +2510,10 @@ def _add_footnotes(self, text): if not self.footnote_return_symbol: self.footnote_return_symbol = "↩" + # self.footnotes is generated in _strip_footnote_definitions, which runs re.sub on the whole + # text. This means that the dict keys are inserted in order of appearance. Use the dict to + # sort footnote ids by that same order + self.footnote_ids.sort(key=lambda a: list(self.footnotes.keys()).index(a)) for i, id in enumerate(self.footnote_ids): if i != 0: footer.append('') diff --git a/test/tm-cases/footnotes_order_of_appearance.html b/test/tm-cases/footnotes_order_of_appearance.html new file mode 100644 index 00000000..fb983d3e --- /dev/null +++ b/test/tm-cases/footnotes_order_of_appearance.html @@ -0,0 +1,34 @@ +
Lorem ipsum dolor sit amet. Aliqua cillum, eu velit.3 Velit deserunt adipiscing adipiscing ullamco exercitation.
+ + + +Lorem ipsum dolor sit amet. Adipiscing4 adipiscing ullamco, exercitation sint. Exercitation sint, fugiat exercitation voluptate amet.
+ + diff --git a/test/tm-cases/footnotes_order_of_appearance.opts b/test/tm-cases/footnotes_order_of_appearance.opts new file mode 100644 index 00000000..9dfee9e2 --- /dev/null +++ b/test/tm-cases/footnotes_order_of_appearance.opts @@ -0,0 +1 @@ +{"extras": ["footnotes"]} diff --git a/test/tm-cases/footnotes_order_of_appearance.text b/test/tm-cases/footnotes_order_of_appearance.text new file mode 100644 index 00000000..87df462e --- /dev/null +++ b/test/tm-cases/footnotes_order_of_appearance.text @@ -0,0 +1,15 @@ +--- +title: testing the footnotes bug +--- +Lorem ipsum dolor sit amet. Aliqua cillum, eu velit.[^note1] Velit deserunt adipiscing adipiscing ullamco exercitation. + +- this is a list item +- this is a list item[^note2] +- this is a list item[^note3] + +Lorem ipsum dolor sit amet. Adipiscing[^note4] adipiscing ullamco, exercitation sint. Exercitation sint, fugiat exercitation voluptate amet. + +[^note1]: this should be the first note +[^note2]: this should be the second note +[^note3]: this should be the third note +[^note4]: this should be the fourth note