|
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