about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/html/markdown.rs54
-rw-r--r--src/test/rustdoc/check-rule-image-footnote.rs13
2 files changed, 42 insertions, 25 deletions
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 6c82dab94bc..e8acabde408 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -27,6 +27,7 @@
 
 use std::ascii::AsciiExt;
 use std::cell::RefCell;
+use std::collections::HashMap;
 use std::default::Default;
 use std::fmt::{self, Write};
 use std::str;
@@ -135,8 +136,8 @@ macro_rules! event_loop_break {
 
 struct ParserWrapper<'a> {
     parser: Parser<'a>,
-    footnotes: Vec<String>,
-    current_footnote_id: u16,
+    // The key is the footnote reference. The value is the footnote definition and the id.
+    footnotes: HashMap<String, (String, u16)>,
 }
 
 impl<'a> ParserWrapper<'a> {
@@ -144,18 +145,18 @@ impl<'a> ParserWrapper<'a> {
         ParserWrapper {
             parser: Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES |
                                        pulldown_cmark::OPTION_ENABLE_FOOTNOTES),
-            footnotes: Vec::new(),
-            current_footnote_id: 1,
+            footnotes: HashMap::new(),
         }
     }
+
     pub fn next(&mut self) -> Option<Event<'a>> {
         self.parser.next()
     }
 
-    pub fn get_next_footnote_id(&mut self) -> u16 {
-        let tmp = self.current_footnote_id;
-        self.current_footnote_id += 1;
-        tmp
+    pub fn get_entry(&mut self, key: &str) -> &mut (String, u16) {
+        let new_id = self.footnotes.keys().count() + 1;
+        let key = key.to_owned();
+        self.footnotes.entry(key).or_insert((String::new(), new_id as u16))
     }
 }
 
@@ -450,10 +451,11 @@ pub fn render(w: &mut fmt::Formatter,
 
     fn footnote(parser: &mut ParserWrapper, buffer: &mut String,
                 toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle,
-                mut definition: String, id: &mut Option<&mut String>) {
-        event_loop_break!(parser, toc_builder, shorter, definition, true, id,
+                id: &mut Option<&mut String>) {
+        let mut content = String::new();
+        event_loop_break!(parser, toc_builder, shorter, content, true, id,
                           Event::End(Tag::FootnoteDefinition(_)));
-        buffer.push_str(&definition);
+        buffer.push_str(&content);
     }
 
     fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
@@ -507,17 +509,24 @@ pub fn render(w: &mut fmt::Formatter,
                 }
                 Event::Start(Tag::FootnoteDefinition(ref def)) => {
                     let mut content = String::new();
-                    footnote(parser, &mut content, toc_builder, shorter, def.as_ref().to_owned(),
-                             id);
-                    let cur_len = parser.footnotes.len() + 1;
-                    parser.footnotes.push(format!("<li id=\"ref{}\">{}<a href=\"#supref{0}\" \
-                                                   rev=\"footnote\">↩</a></li>",
-                                                  cur_len, content));
-                }
-                Event::FootnoteReference(_) => {
+                    let def = def.as_ref();
+                    footnote(parser, &mut content, toc_builder, shorter, id);
+                    let entry = parser.get_entry(def);
+                    let cur_id = (*entry).1;
+                    (*entry).0.push_str(&format!("<li id=\"ref{}\">{}&nbsp;<a href=\"#supref{0}\" \
+                                                  rev=\"footnote\">↩</a></p></li>",
+                                                 cur_id,
+                                                 if content.ends_with("</p>") {
+                                                     &content[..content.len() - 4]
+                                                 } else {
+                                                     &content
+                                                 }));
+                }
+                Event::FootnoteReference(ref reference) => {
+                    let entry = parser.get_entry(reference.as_ref());
                     buffer.push_str(&format!("<sup id=\"supref{0}\"><a href=\"#ref{0}\">{0}</a>\
                                               </sup>",
-                                             parser.get_next_footnote_id()));
+                                             (*entry).1));
                 }
                 Event::Html(h) | Event::InlineHtml(h) => {
                     buffer.push_str(&*h);
@@ -545,7 +554,10 @@ pub fn render(w: &mut fmt::Formatter,
     }
     if !parser.footnotes.is_empty() {
         buffer.push_str(&format!("<div class=\"footnotes\"><hr><ol>{}</ol></div>",
-                                 parser.footnotes.join("")));
+                                 parser.footnotes.values()
+                                                 .map(|&(ref s, _)| s.as_str())
+                                                 .collect::<Vec<_>>()
+                                                 .join("")));
     }
     let mut ret = toc_builder.map_or(Ok(()), |builder| {
         write!(w, "<nav id=\"TOC\">{}</nav>", builder.into_toc())
diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs
index 629e1a64e6f..4d3bea20ba8 100644
--- a/src/test/rustdoc/check-rule-image-footnote.rs
+++ b/src/test/rustdoc/check-rule-image-footnote.rs
@@ -10,11 +10,10 @@
 
 #![crate_name = "foo"]
 
+// ignore-tidy-linelength
+
 // @has foo/fn.f.html
-// @has - '<p>hard break: after hard break</p><hr>'
-// @has - '<img src="https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png" alt="Rust">'
-// @has - '<li id="ref1">'
-// @has - '<sup id="supref1"><a href="#ref1">1</a></sup>'
+// @has - '<p>markdown test</p><p>this is a <a href="https://example.com" title="this is a title">link</a>.</p><p>hard break: after hard break</p><hr><p>a footnote<sup id="supref1"><a href="#ref1">1</a></sup>.</p><p>another footnote<sup id="supref2"><a href="#ref2">2</a></sup>.</p><p><img src="https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png" alt="Rust"></p><div class="footnotes"><hr><ol><li id="ref1"><p>Thing&nbsp;<a href="#supref1" rev="footnote">↩</a></p></li><li id="ref2"><p>Another Thing&nbsp;<a href="#supref2" rev="footnote">↩</a></p></li></ol></div>'
 /// markdown test
 ///
 /// this is a [link].
@@ -28,8 +27,14 @@
 ///
 /// a footnote[^footnote].
 ///
+/// another footnote[^footnotebis].
+///
 /// [^footnote]: Thing
 ///
+///
+/// [^footnotebis]: Another Thing
+///
+///
 /// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png)
 #[deprecated(note = "Struct<T>")]
 pub fn f() {}