@@ -10,18 +10,30 @@ use super::SpannedEvent;
1010/// references.
1111pub ( super ) struct Footnotes < ' a , I > {
1212 inner : I ,
13- footnotes : FxIndexMap < String , ( Vec < Event < ' a > > , u16 ) > ,
13+ footnotes : FxIndexMap < String , FootnoteDef < ' a > > ,
14+ }
15+
16+ /// The definition of a single footnote.
17+ struct FootnoteDef < ' a > {
18+ content : Vec < Event < ' a > > ,
19+ /// The number that appears in the footnote reference and list.
20+ id : u16 ,
1421}
1522
1623impl < ' a , I > Footnotes < ' a , I > {
1724 pub ( super ) fn new ( iter : I ) -> Self {
1825 Footnotes { inner : iter, footnotes : FxIndexMap :: default ( ) }
1926 }
2027
21- fn get_entry ( & mut self , key : & str ) -> & mut ( Vec < Event < ' a > > , u16 ) {
28+ fn get_entry ( & mut self , key : & str ) -> ( & mut Vec < Event < ' a > > , u16 ) {
2229 let new_id = self . footnotes . len ( ) + 1 ;
2330 let key = key. to_owned ( ) ;
24- self . footnotes . entry ( key) . or_insert ( ( Vec :: new ( ) , new_id as u16 ) )
31+ let FootnoteDef { content, id } = self
32+ . footnotes
33+ . entry ( key)
34+ . or_insert ( FootnoteDef { content : Vec :: new ( ) , id : new_id as u16 } ) ;
35+ // Don't allow changing the ID of existing entrys, but allow changing the contents.
36+ ( content, * id)
2537 }
2638}
2739
@@ -32,46 +44,28 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
3244 loop {
3345 match self . inner . next ( ) {
3446 Some ( ( Event :: FootnoteReference ( ref reference) , range) ) => {
35- let entry = self . get_entry ( reference) ;
36- let reference = format ! (
37- "<sup id= \" fnref{0} \" ><a href= \" #fn{0} \" >{0}</a></sup>" ,
38- ( * entry ) . 1
39- ) ;
47+ // When we see a reference (to a footnote we may not know) the definition of,
48+ // reserve a number for it, and emit a link to that number.
49+ let ( _ , id ) = self . get_entry ( reference ) ;
50+ let reference =
51+ format ! ( "<sup id= \" fnref{0} \" ><a href= \" #fn{0} \" >{0}</a></sup>" , id ) ;
4052 return Some ( ( Event :: Html ( reference. into ( ) ) , range) ) ;
4153 }
4254 Some ( ( Event :: Start ( Tag :: FootnoteDefinition ( def) ) , _) ) => {
43- let mut content = Vec :: new ( ) ;
44- for ( event, _) in & mut self . inner {
45- if let Event :: End ( TagEnd :: FootnoteDefinition ) = event {
46- break ;
47- }
48- content. push ( event) ;
49- }
50- let entry = self . get_entry ( & def) ;
51- ( * entry) . 0 = content;
55+ // When we see a footnote definition, collect the assocated content, and store
56+ // that for rendering later.
57+ let content = collect_footnote_def ( & mut self . inner ) ;
58+ let ( entry_content, _) = self . get_entry ( & def) ;
59+ * entry_content = content;
5260 }
5361 Some ( e) => return Some ( e) ,
5462 None => {
5563 if !self . footnotes . is_empty ( ) {
56- let mut v: Vec < _ > = self . footnotes . drain ( ..) . map ( |( _, x) | x) . collect ( ) ;
57- v. sort_by ( |a, b| a. 1 . cmp ( & b. 1 ) ) ;
58- let mut ret = String :: from ( "<div class=\" footnotes\" ><hr><ol>" ) ;
59- for ( mut content, id) in v {
60- write ! ( ret, "<li id=\" fn{id}\" >" ) . unwrap ( ) ;
61- let mut is_paragraph = false ;
62- if let Some ( & Event :: End ( TagEnd :: Paragraph ) ) = content. last ( ) {
63- content. pop ( ) ;
64- is_paragraph = true ;
65- }
66- html:: push_html ( & mut ret, content. into_iter ( ) ) ;
67- write ! ( ret, " <a href=\" #fnref{id}\" >↩</a>" ) . unwrap ( ) ;
68- if is_paragraph {
69- ret. push_str ( "</p>" ) ;
70- }
71- ret. push_str ( "</li>" ) ;
72- }
73- ret. push_str ( "</ol></div>" ) ;
74- return Some ( ( Event :: Html ( ret. into ( ) ) , 0 ..0 ) ) ;
64+ // After all the markdown is emmited, emit an <hr> then all the footnotes
65+ // in a list.
66+ let defs: Vec < _ > = self . footnotes . drain ( ..) . map ( |( _, x) | x) . collect ( ) ;
67+ let defs_html = render_footnotes_defs ( defs) ;
68+ return Some ( ( Event :: Html ( defs_html. into ( ) ) , 0 ..0 ) ) ;
7569 } else {
7670 return None ;
7771 }
@@ -80,3 +74,40 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
8074 }
8175 }
8276}
77+
78+ fn collect_footnote_def < ' a > ( events : impl Iterator < Item = SpannedEvent < ' a > > ) -> Vec < Event < ' a > > {
79+ let mut content = Vec :: new ( ) ;
80+ for ( event, _) in events {
81+ if let Event :: End ( TagEnd :: FootnoteDefinition ) = event {
82+ break ;
83+ }
84+ content. push ( event) ;
85+ }
86+ content
87+ }
88+
89+ fn render_footnotes_defs ( mut footnotes : Vec < FootnoteDef < ' _ > > ) -> String {
90+ let mut ret = String :: from ( "<div class=\" footnotes\" ><hr><ol>" ) ;
91+
92+ // Footnotes must listed in order of id, so the numbers the
93+ // browser generated for <li> are right.
94+ footnotes. sort_by_key ( |x| x. id ) ;
95+
96+ for FootnoteDef { mut content, id } in footnotes {
97+ write ! ( ret, "<li id=\" fn{id}\" >" ) . unwrap ( ) ;
98+ let mut is_paragraph = false ;
99+ if let Some ( & Event :: End ( TagEnd :: Paragraph ) ) = content. last ( ) {
100+ content. pop ( ) ;
101+ is_paragraph = true ;
102+ }
103+ html:: push_html ( & mut ret, content. into_iter ( ) ) ;
104+ write ! ( ret, " <a href=\" #fnref{id}\" >↩</a>" ) . unwrap ( ) ;
105+ if is_paragraph {
106+ ret. push_str ( "</p>" ) ;
107+ }
108+ ret. push_str ( "</li>" ) ;
109+ }
110+ ret. push_str ( "</ol></div>" ) ;
111+
112+ ret
113+ }
0 commit comments