From 4503def965e97736b7326d623ec7986670074e43 Mon Sep 17 00:00:00 2001 From: adarshsm <24850536+adarshsm@users.noreply.github.com> Date: Mon, 19 Oct 2026 11:01:26 +0530 Subject: [PATCH 1/2] List footnotes in the order they are numbered Footnote references are numbered in order of appearance by _do_footnote_marker, but _add_footnotes then sorted the notes by the order of their definitions. When the definitions weren't in reference order, the note numbered 2 in the text could be the first item of the list, and its back-link title said "footnote 1". The sort dates from before _do_footnote_marker numbered references on the final text, when it was needed to undo out-of-order numbering for references inside lists and blockquotes. footnote_ids is now already in numbering order, so drop the sort. Fixes #178 Co-Authored-By: Claude Opus 5.5 --- CHANGES.md | 1 + lib/markdown2.py | 6 ++--- .../footnotes_defined_out_of_order.html | 22 +++++++++++++++++++ .../footnotes_defined_out_of_order.opts | 1 + .../footnotes_defined_out_of_order.text | 7 ++++++ test/tm-cases/repeated_footnote_labels.html | 8 +++---- 6 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 test/tm-cases/footnotes_defined_out_of_order.html create mode 100644 test/tm-cases/footnotes_defined_out_of_order.opts create mode 100644 test/tm-cases/footnotes_defined_out_of_order.text diff --git a/CHANGES.md b/CHANGES.md index 90f815ec..e4b5f8ef 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## python-markdown2 2.5.6 (not yet released) +- Fix `footnotes` extra listing notes in definition order, so a note's position in the list didn't match its number in the text (#178) - [pull #739] Fix `header-ids` extra putting sanitized HTML into header ids in safe mode, which allowed attribute injection (#649) - [pull #732] Fix excessive CPU use in the inline HTML tokenizer on repeated unclosed tag fragments (#707) - [pull #736] Clarify how to enable file variables in the Python API and command-line help (#269, #365). diff --git a/lib/markdown2.py b/lib/markdown2.py index 66d49a69..f052314b 100755 --- a/lib/markdown2.py +++ b/lib/markdown2.py @@ -2272,10 +2272,8 @@ def _add_footnotes(self, text: str) -> str: 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)) + # self.footnote_ids is filled by _do_footnote_marker in the order the references are + # numbered, so listing the notes in that order keeps each note at its number for i, id in enumerate(self.footnote_ids): if i != 0: footer.append('') diff --git a/test/tm-cases/footnotes_defined_out_of_order.html b/test/tm-cases/footnotes_defined_out_of_order.html new file mode 100644 index 00000000..480ee16d --- /dev/null +++ b/test/tm-cases/footnotes_defined_out_of_order.html @@ -0,0 +1,22 @@ +

The first reference1 and the second2.

+ +
+

A quoted reference3.

+
+ +
+
+
    +
  1. +

    Defined third, referenced first. ↩

    +
  2. + +
  3. +

    Defined first, referenced second. ↩

    +
  4. + +
  5. +

    Defined second, referenced third. ↩

    +
  6. +
+
diff --git a/test/tm-cases/footnotes_defined_out_of_order.opts b/test/tm-cases/footnotes_defined_out_of_order.opts new file mode 100644 index 00000000..9dfee9e2 --- /dev/null +++ b/test/tm-cases/footnotes_defined_out_of_order.opts @@ -0,0 +1 @@ +{"extras": ["footnotes"]} diff --git a/test/tm-cases/footnotes_defined_out_of_order.text b/test/tm-cases/footnotes_defined_out_of_order.text new file mode 100644 index 00000000..3fb2bbaf --- /dev/null +++ b/test/tm-cases/footnotes_defined_out_of_order.text @@ -0,0 +1,7 @@ +The first reference[^b] and the second[^a]. + +> A quoted reference[^c]. + +[^a]: Defined first, referenced second. +[^c]: Defined second, referenced third. +[^b]: Defined third, referenced first. diff --git a/test/tm-cases/repeated_footnote_labels.html b/test/tm-cases/repeated_footnote_labels.html index 201708f0..7b99a2f2 100644 --- a/test/tm-cases/repeated_footnote_labels.html +++ b/test/tm-cases/repeated_footnote_labels.html @@ -9,12 +9,12 @@

    -
  1. -

    Second note referencing first1. ↩

    +
  2. +

    First note. ↩

  3. -
  4. -

    First note. ↩

    +
  5. +

    Second note referencing first1. ↩

  6. From e6660784456e401612499e968333b0035da9fefc Mon Sep 17 00:00:00 2001 From: adarshsm <24850536+adarshsm@users.noreply.github.com> Date: Mon, 19 Oct 2026 11:01:51 +0530 Subject: [PATCH 2/2] Add the PR number to the change note Co-Authored-By: Claude Opus 5.5 --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index e4b5f8ef..64bdc16a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,7 @@ ## python-markdown2 2.5.6 (not yet released) -- Fix `footnotes` extra listing notes in definition order, so a note's position in the list didn't match its number in the text (#178) +- [pull #745] Fix `footnotes` extra listing notes in definition order, so a note's position in the list didn't match its number in the text (#178) - [pull #739] Fix `header-ids` extra putting sanitized HTML into header ids in safe mode, which allowed attribute injection (#649) - [pull #732] Fix excessive CPU use in the inline HTML tokenizer on repeated unclosed tag fragments (#707) - [pull #736] Clarify how to enable file variables in the Python API and command-line help (#269, #365).