Merge pull request #2681 from krishanjmistry/issue-2649-footnotes
Warn on and ignore duplicate footnote definitions
This commit is contained in:
commit
23abd20589
4 changed files with 90 additions and 44 deletions
|
|
@ -235,10 +235,10 @@ pub fn render_markdown_with_path(
|
||||||
// `count` is the number of references to this footnote (used for multiple
|
// `count` is the number of references to this footnote (used for multiple
|
||||||
// linkbacks, and checking for unused footnotes).
|
// linkbacks, and checking for unused footnotes).
|
||||||
let mut footnote_numbers = HashMap::new();
|
let mut footnote_numbers = HashMap::new();
|
||||||
// This is a list of (name, Vec<Event>)
|
// This is a map of name -> Vec<Event>
|
||||||
// `name` is the name of the footnote.
|
// `name` is the name of the footnote.
|
||||||
// The events list is the list of events needed to build the footnote definition.
|
// 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.
|
// The following are used when currently processing a footnote definition.
|
||||||
//
|
//
|
||||||
|
|
@ -268,7 +268,16 @@ pub fn render_markdown_with_path(
|
||||||
Event::End(TagEnd::FootnoteDefinition) => {
|
Event::End(TagEnd::FootnoteDefinition) => {
|
||||||
let def_events = std::mem::take(&mut in_footnote);
|
let def_events = std::mem::take(&mut in_footnote);
|
||||||
let name = std::mem::take(&mut in_footnote_name);
|
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("<unknown>"), |p| p.to_string_lossy())
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
footnote_defs.insert(name, def_events);
|
||||||
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Event::FootnoteReference(name) => {
|
Event::FootnoteReference(name) => {
|
||||||
|
|
@ -304,7 +313,12 @@ pub fn render_markdown_with_path(
|
||||||
html::push_html(&mut body, events);
|
html::push_html(&mut body, events);
|
||||||
|
|
||||||
if !footnote_defs.is_empty() {
|
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
|
body
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
//! Tests for special markdown rendering.
|
//! Tests for special markdown rendering.
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use snapbox::file;
|
||||||
|
|
||||||
// Checks custom header id and classes.
|
// Checks custom header id and classes.
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -17,46 +18,21 @@ fn custom_header_attributes() {
|
||||||
#[test]
|
#[test]
|
||||||
fn footnotes() {
|
fn footnotes() {
|
||||||
BookTest::from_dir("markdown/footnotes")
|
BookTest::from_dir("markdown/footnotes")
|
||||||
.check_main_file("book/footnotes.html", str![[r##"
|
.run("build", |cmd| {
|
||||||
<h1 id="footnote-tests"><a class="header" href="#footnote-tests">Footnote tests</a></h1>
|
cmd.expect_stderr(str![[r#"
|
||||||
<p>Footnote example<sup class="footnote-reference" id="fr-1-1"><a href="#footnote-1">1</a></sup>, or with a word<sup class="footnote-reference" id="fr-word-1"><a href="#footnote-word">2</a></sup>.</p>
|
[TIMESTAMP] [INFO] (mdbook::book): Book building has started
|
||||||
<p>There are multiple references to word<sup class="footnote-reference" id="fr-word-2"><a href="#footnote-word">2</a></sup>.</p>
|
[TIMESTAMP] [INFO] (mdbook::book): Running the html backend
|
||||||
<p>Footnote without a paragraph<sup class="footnote-reference" id="fr-para-1"><a href="#footnote-para">3</a></sup></p>
|
[TIMESTAMP] [WARN] (mdbook::utils): footnote `multiple-definitions` in <unknown> defined multiple times - not updating to new definition
|
||||||
<p>Footnote with multiple paragraphs<sup class="footnote-reference" id="fr-multiple-1"><a href="#footnote-multiple">4</a></sup></p>
|
[TIMESTAMP] [WARN] (mdbook::utils): footnote `unused` in `<unknown>` is defined but not referenced
|
||||||
<p>Footnote name with wacky characters<sup class="footnote-reference" id="fr-"wacky"-1"><a href="#footnote-"wacky"">5</a></sup></p>
|
[TIMESTAMP] [WARN] (mdbook::utils): footnote `multiple-definitions` in footnotes.md defined multiple times - not updating to new definition
|
||||||
<p>Testing when referring to something earlier.<sup class="footnote-reference" id="fr-define-before-use-1"><a href="#footnote-define-before-use">6</a></sup></p>
|
[TIMESTAMP] [WARN] (mdbook::utils): footnote `unused` in `footnotes.md` is defined but not referenced
|
||||||
<hr>
|
|
||||||
<ol class="footnote-definition"><li id="footnote-1">
|
"#]]);
|
||||||
<p>This is a footnote. <a href="#fr-1-1">↩</a> <a href="#fr-1-2">↩2</a></p>
|
})
|
||||||
</li>
|
.check_main_file(
|
||||||
<li id="footnote-word">
|
"book/footnotes.html",
|
||||||
<p>A longer footnote.
|
file!["markdown/footnotes/expected/footnotes.html"],
|
||||||
With multiple lines. <a href="other.html">Link to other</a>.
|
);
|
||||||
With a reference inside.<sup class="footnote-reference" id="fr-1-2"><a href="#footnote-1">1</a></sup> <a href="#fr-word-1">↩</a> <a href="#fr-word-2">↩2</a></p>
|
|
||||||
</li>
|
|
||||||
<li id="footnote-para">
|
|
||||||
<ol>
|
|
||||||
<li>Item one
|
|
||||||
<ol>
|
|
||||||
<li>Sub-item</li>
|
|
||||||
</ol>
|
|
||||||
</li>
|
|
||||||
<li>Item two</li>
|
|
||||||
</ol>
|
|
||||||
<a href="#fr-para-1">↩</a></li>
|
|
||||||
<li id="footnote-multiple">
|
|
||||||
<p>One</p>
|
|
||||||
<p>Two</p>
|
|
||||||
<p>Three <a href="#fr-multiple-1">↩</a></p>
|
|
||||||
</li>
|
|
||||||
<li id="footnote-"wacky"">
|
|
||||||
<p>Testing footnote id with special characters. <a href="#fr-"wacky"-1">↩</a></p>
|
|
||||||
</li>
|
|
||||||
<li id="footnote-define-before-use">
|
|
||||||
<p>This is defined before it is referred to. <a href="#fr-define-before-use-1">↩</a></p>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
"##]]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic table test.
|
// Basic table test.
|
||||||
|
|
|
||||||
46
tests/testsuite/markdown/footnotes/expected/footnotes.html
Normal file
46
tests/testsuite/markdown/footnotes/expected/footnotes.html
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
<h1 id="footnote-tests"><a class="header" href="#footnote-tests">Footnote tests</a></h1>
|
||||||
|
<p>Footnote example<sup class="footnote-reference" id="fr-1-1"><a href="#footnote-1">1</a></sup>, or with a word<sup class="footnote-reference" id="fr-word-1"><a href="#footnote-word">2</a></sup>.</p>
|
||||||
|
<p>There are multiple references to word<sup class="footnote-reference" id="fr-word-2"><a href="#footnote-word">2</a></sup>.</p>
|
||||||
|
<p>Footnote without a paragraph<sup class="footnote-reference" id="fr-para-1"><a href="#footnote-para">3</a></sup></p>
|
||||||
|
<p>Footnote with multiple paragraphs<sup class="footnote-reference" id="fr-multiple-1"><a href="#footnote-multiple">4</a></sup></p>
|
||||||
|
<p>Footnote name with wacky characters<sup class="footnote-reference" id="fr-"wacky"-1"><a href="#footnote-"wacky"">5</a></sup></p>
|
||||||
|
<p>Testing when referring to something earlier.<sup class="footnote-reference" id="fr-define-before-use-1"><a href="#footnote-define-before-use">6</a></sup></p>
|
||||||
|
<p>Footnote that is defined multiple times.<sup class="footnote-reference" id="fr-multiple-definitions-1"><a href="#footnote-multiple-definitions">7</a></sup></p>
|
||||||
|
<p>And another<sup class="footnote-reference" id="fr-in-between-1"><a href="#footnote-in-between">8</a></sup> that references the duplicate again.<sup class="footnote-reference" id="fr-multiple-definitions-2"><a href="#footnote-multiple-definitions">7</a></sup></p>
|
||||||
|
<hr>
|
||||||
|
<ol class="footnote-definition"><li id="footnote-1">
|
||||||
|
<p>This is a footnote. <a href="#fr-1-1">↩</a> <a href="#fr-1-2">↩2</a></p>
|
||||||
|
</li>
|
||||||
|
<li id="footnote-word">
|
||||||
|
<p>A longer footnote.
|
||||||
|
With multiple lines. <a href="other.html">Link to other</a>.
|
||||||
|
With a reference inside.<sup class="footnote-reference" id="fr-1-2"><a href="#footnote-1">1</a></sup> <a href="#fr-word-1">↩</a> <a href="#fr-word-2">↩2</a></p>
|
||||||
|
</li>
|
||||||
|
<li id="footnote-para">
|
||||||
|
<ol>
|
||||||
|
<li>Item one
|
||||||
|
<ol>
|
||||||
|
<li>Sub-item</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
<li>Item two</li>
|
||||||
|
</ol>
|
||||||
|
<a href="#fr-para-1">↩</a></li>
|
||||||
|
<li id="footnote-multiple">
|
||||||
|
<p>One</p>
|
||||||
|
<p>Two</p>
|
||||||
|
<p>Three <a href="#fr-multiple-1">↩</a></p>
|
||||||
|
</li>
|
||||||
|
<li id="footnote-"wacky"">
|
||||||
|
<p>Testing footnote id with special characters. <a href="#fr-"wacky"-1">↩</a></p>
|
||||||
|
</li>
|
||||||
|
<li id="footnote-define-before-use">
|
||||||
|
<p>This is defined before it is referred to. <a href="#fr-define-before-use-1">↩</a></p>
|
||||||
|
</li>
|
||||||
|
<li id="footnote-multiple-definitions">
|
||||||
|
<p>This is the first definition of the footnote with tag multiple-definitions <a href="#fr-multiple-definitions-1">↩</a> <a href="#fr-multiple-definitions-2">↩2</a></p>
|
||||||
|
</li>
|
||||||
|
<li id="footnote-in-between">
|
||||||
|
<p>Footnote between duplicates. <a href="#fr-in-between-1">↩</a></p>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
@ -35,3 +35,13 @@ Footnote name with wacky characters[^"wacky"]
|
||||||
[^"wacky"]: Testing footnote id with special characters.
|
[^"wacky"]: Testing footnote id with special characters.
|
||||||
|
|
||||||
Testing when referring to something earlier.[^define-before-use]
|
Testing when referring to something earlier.[^define-before-use]
|
||||||
|
|
||||||
|
Footnote that is defined multiple times.[^multiple-definitions]
|
||||||
|
|
||||||
|
[^multiple-definitions]: This is the first definition of the footnote with tag multiple-definitions
|
||||||
|
|
||||||
|
And another[^in-between] that references the duplicate again.[^multiple-definitions]
|
||||||
|
|
||||||
|
[^in-between]: Footnote between duplicates.
|
||||||
|
|
||||||
|
[^multiple-definitions]: This is the second definition of the footnote with tag multiple-definitions
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue