|
27 | 27 |
|
28 | 28 | use std::ascii::AsciiExt; |
29 | 29 | use std::cell::RefCell; |
| 30 | +use std::collections::HashMap; |
30 | 31 | use std::default::Default; |
31 | 32 | use std::fmt::{self, Write}; |
32 | 33 | use std::str; |
@@ -135,27 +136,27 @@ macro_rules! event_loop_break { |
135 | 136 |
|
136 | 137 | struct ParserWrapper<'a> { |
137 | 138 | parser: Parser<'a>, |
138 | | - footnotes: Vec<String>, |
139 | | - current_footnote_id: u16, |
| 139 | + // The key is the footnote reference. The value is the footnote definition and the id. |
| 140 | + footnotes: HashMap<String, (String, u16)>, |
140 | 141 | } |
141 | 142 |
|
142 | 143 | impl<'a> ParserWrapper<'a> { |
143 | 144 | pub fn new(s: &'a str) -> ParserWrapper<'a> { |
144 | 145 | ParserWrapper { |
145 | 146 | parser: Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES | |
146 | 147 | pulldown_cmark::OPTION_ENABLE_FOOTNOTES), |
147 | | - footnotes: Vec::new(), |
148 | | - current_footnote_id: 1, |
| 148 | + footnotes: HashMap::new(), |
149 | 149 | } |
150 | 150 | } |
| 151 | + |
151 | 152 | pub fn next(&mut self) -> Option<Event<'a>> { |
152 | 153 | self.parser.next() |
153 | 154 | } |
154 | 155 |
|
155 | | - pub fn get_next_footnote_id(&mut self) -> u16 { |
156 | | - let tmp = self.current_footnote_id; |
157 | | - self.current_footnote_id += 1; |
158 | | - tmp |
| 156 | + pub fn get_entry(&mut self, key: &str) -> &mut (String, u16) { |
| 157 | + let new_id = self.footnotes.keys().count() + 1; |
| 158 | + let key = key.to_owned(); |
| 159 | + self.footnotes.entry(key).or_insert((String::new(), new_id as u16)) |
159 | 160 | } |
160 | 161 | } |
161 | 162 |
|
@@ -450,10 +451,11 @@ pub fn render(w: &mut fmt::Formatter, |
450 | 451 |
|
451 | 452 | fn footnote(parser: &mut ParserWrapper, buffer: &mut String, |
452 | 453 | toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle, |
453 | | - mut definition: String, id: &mut Option<&mut String>) { |
454 | | - event_loop_break!(parser, toc_builder, shorter, definition, true, id, |
| 454 | + id: &mut Option<&mut String>) { |
| 455 | + let mut content = String::new(); |
| 456 | + event_loop_break!(parser, toc_builder, shorter, content, true, id, |
455 | 457 | Event::End(Tag::FootnoteDefinition(_))); |
456 | | - buffer.push_str(&definition); |
| 458 | + buffer.push_str(&content); |
457 | 459 | } |
458 | 460 |
|
459 | 461 | fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, |
@@ -507,17 +509,24 @@ pub fn render(w: &mut fmt::Formatter, |
507 | 509 | } |
508 | 510 | Event::Start(Tag::FootnoteDefinition(ref def)) => { |
509 | 511 | let mut content = String::new(); |
510 | | - footnote(parser, &mut content, toc_builder, shorter, def.as_ref().to_owned(), |
511 | | - id); |
512 | | - let cur_len = parser.footnotes.len() + 1; |
513 | | - parser.footnotes.push(format!("<li id=\"ref{}\">{}<a href=\"#supref{0}\" \ |
514 | | - rev=\"footnote\">↩</a></li>", |
515 | | - cur_len, content)); |
516 | | - } |
517 | | - Event::FootnoteReference(_) => { |
| 512 | + let def = def.as_ref(); |
| 513 | + footnote(parser, &mut content, toc_builder, shorter, id); |
| 514 | + let entry = parser.get_entry(def); |
| 515 | + let cur_id = (*entry).1; |
| 516 | + (*entry).0.push_str(&format!("<li id=\"ref{}\">{} <a href=\"#supref{0}\" \ |
| 517 | + rev=\"footnote\">↩</a></p></li>", |
| 518 | + cur_id, |
| 519 | + if content.ends_with("</p>") { |
| 520 | + &content[..content.len() - 4] |
| 521 | + } else { |
| 522 | + &content |
| 523 | + })); |
| 524 | + } |
| 525 | + Event::FootnoteReference(ref reference) => { |
| 526 | + let entry = parser.get_entry(reference.as_ref()); |
518 | 527 | buffer.push_str(&format!("<sup id=\"supref{0}\"><a href=\"#ref{0}\">{0}</a>\ |
519 | 528 | </sup>", |
520 | | - parser.get_next_footnote_id())); |
| 529 | + (*entry).1)); |
521 | 530 | } |
522 | 531 | Event::Html(h) | Event::InlineHtml(h) => { |
523 | 532 | buffer.push_str(&*h); |
@@ -545,7 +554,10 @@ pub fn render(w: &mut fmt::Formatter, |
545 | 554 | } |
546 | 555 | if !parser.footnotes.is_empty() { |
547 | 556 | buffer.push_str(&format!("<div class=\"footnotes\"><hr><ol>{}</ol></div>", |
548 | | - parser.footnotes.join(""))); |
| 557 | + parser.footnotes.values() |
| 558 | + .map(|&(ref s, _)| s.as_str()) |
| 559 | + .collect::<Vec<_>>() |
| 560 | + .join(""))); |
549 | 561 | } |
550 | 562 | let mut ret = toc_builder.map_or(Ok(()), |builder| { |
551 | 563 | write!(w, "<nav id=\"TOC\">{}</nav>", builder.into_toc()) |
|
0 commit comments