From 7e9be8dee323389fb90e73852be194cb7121ccc4 Mon Sep 17 00:00:00 2001 From: Krishan Mistry Date: Tue, 29 Apr 2025 11:41:53 +0100 Subject: [PATCH] Warn on duplicate footnote definition and ignore subsequent definitions --- src/utils/mod.rs | 22 +++++++++++++++---- tests/testsuite/markdown.rs | 20 +++++++++++++---- .../footnotes/expected/footnotes.html | 3 --- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index fc8584ee..0ca0482f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -235,10 +235,10 @@ pub fn render_markdown_with_path( // `count` is the number of references to this footnote (used for multiple // linkbacks, and checking for unused footnotes). let mut footnote_numbers = HashMap::new(); - // This is a list of (name, Vec) + // This is a map of name -> Vec // `name` is the name of the footnote. // The events list is the list of events needed to build the footnote definition. - let mut footnote_defs = Vec::new(); + let mut footnote_defs = HashMap::new(); // The following are used when currently processing a footnote definition. // @@ -268,7 +268,16 @@ pub fn render_markdown_with_path( Event::End(TagEnd::FootnoteDefinition) => { let def_events = std::mem::take(&mut in_footnote); let name = std::mem::take(&mut in_footnote_name); - footnote_defs.push((name, def_events)); + + if footnote_defs.contains_key(&name) { + log::warn!( + "footnote `{name}` in {} defined multiple times - \ + not updating to new definition", + path.map_or_else(|| Cow::from(""), |p| p.to_string_lossy()) + ); + } else { + footnote_defs.insert(name, def_events); + } None } Event::FootnoteReference(name) => { @@ -304,7 +313,12 @@ pub fn render_markdown_with_path( html::push_html(&mut body, events); if !footnote_defs.is_empty() { - add_footnote_defs(&mut body, path, footnote_defs, &footnote_numbers); + add_footnote_defs( + &mut body, + path, + footnote_defs.into_iter().collect(), + &footnote_numbers, + ); } body diff --git a/tests/testsuite/markdown.rs b/tests/testsuite/markdown.rs index 537a8e06..c4bfbd07 100644 --- a/tests/testsuite/markdown.rs +++ b/tests/testsuite/markdown.rs @@ -17,10 +17,22 @@ fn custom_header_attributes() { // Test for a variety of footnote renderings. #[test] fn footnotes() { - BookTest::from_dir("markdown/footnotes").check_main_file( - "book/footnotes.html", - file!["markdown/footnotes/expected/footnotes.html"], - ); + BookTest::from_dir("markdown/footnotes") + .run("build", |cmd| { + cmd.expect_stderr(str![[r#" +[TIMESTAMP] [INFO] (mdbook::book): Book building has started +[TIMESTAMP] [INFO] (mdbook::book): Running the html backend +[TIMESTAMP] [WARN] (mdbook::utils): footnote `multiple-definitions` in defined multiple times - not updating to new definition +[TIMESTAMP] [WARN] (mdbook::utils): footnote `unused` in `` is defined but not referenced +[TIMESTAMP] [WARN] (mdbook::utils): footnote `multiple-definitions` in footnotes.md defined multiple times - not updating to new definition +[TIMESTAMP] [WARN] (mdbook::utils): footnote `unused` in `footnotes.md` is defined but not referenced + +"#]]); + }) + .check_main_file( + "book/footnotes.html", + file!["markdown/footnotes/expected/footnotes.html"], + ); } // Basic table test. diff --git a/tests/testsuite/markdown/footnotes/expected/footnotes.html b/tests/testsuite/markdown/footnotes/expected/footnotes.html index 28c3d94e..8904cb06 100644 --- a/tests/testsuite/markdown/footnotes/expected/footnotes.html +++ b/tests/testsuite/markdown/footnotes/expected/footnotes.html @@ -40,9 +40,6 @@ With a reference inside.

This is the first definition of the footnote with tag multiple-definitions ↩2

-
  • -

    This is the second definition of the footnote with tag multiple-definitions ↩2

    -
  • Footnote between duplicates.