2727
2828use std:: ascii:: AsciiExt ;
2929use std:: cell:: RefCell ;
30+ use std:: collections:: HashMap ;
3031use std:: default:: Default ;
3132use std:: fmt:: { self , Write } ;
3233use std:: str;
@@ -115,15 +116,19 @@ macro_rules! event_loop_break {
115116 match event {
116117 $( $end_event) |* => break ,
117118 Event :: Text ( ref s) => {
119+ debug!( "Text" ) ;
118120 inner( $id, s) ;
119121 if $escape {
120122 $buf. push_str( & format!( "{}" , Escape ( s) ) ) ;
121123 } else {
122124 $buf. push_str( s) ;
123125 }
124126 }
125- Event :: SoftBreak | Event :: HardBreak if !$buf. is_empty( ) => {
126- $buf. push( ' ' ) ;
127+ Event :: SoftBreak => {
128+ debug!( "SoftBreak" ) ;
129+ if !$buf. is_empty( ) {
130+ $buf. push( ' ' ) ;
131+ }
127132 }
128133 x => {
129134 looper( $parser, & mut $buf, Some ( x) , $toc_builder, $shorter, $id) ;
@@ -133,11 +138,38 @@ macro_rules! event_loop_break {
133138 } }
134139}
135140
141+ struct ParserWrapper < ' a > {
142+ parser : Parser < ' a > ,
143+ // The key is the footnote reference. The value is the footnote definition and the id.
144+ footnotes : HashMap < String , ( String , u16 ) > ,
145+ }
146+
147+ impl < ' a > ParserWrapper < ' a > {
148+ pub fn new ( s : & ' a str ) -> ParserWrapper < ' a > {
149+ ParserWrapper {
150+ parser : Parser :: new_ext ( s, pulldown_cmark:: OPTION_ENABLE_TABLES |
151+ pulldown_cmark:: OPTION_ENABLE_FOOTNOTES ) ,
152+ footnotes : HashMap :: new ( ) ,
153+ }
154+ }
155+
156+ pub fn next ( & mut self ) -> Option < Event < ' a > > {
157+ self . parser . next ( )
158+ }
159+
160+ pub fn get_entry ( & mut self , key : & str ) -> & mut ( String , u16 ) {
161+ let new_id = self . footnotes . keys ( ) . count ( ) + 1 ;
162+ let key = key. to_owned ( ) ;
163+ self . footnotes . entry ( key) . or_insert ( ( String :: new ( ) , new_id as u16 ) )
164+ }
165+ }
166+
136167pub fn render ( w : & mut fmt:: Formatter ,
137168 s : & str ,
138169 print_toc : bool ,
139170 shorter : MarkdownOutputStyle ) -> fmt:: Result {
140- fn code_block ( parser : & mut Parser , buffer : & mut String , lang : & str ) {
171+ fn code_block ( parser : & mut ParserWrapper , buffer : & mut String , lang : & str ) {
172+ debug ! ( "CodeBlock" ) ;
141173 let mut origtext = String :: new ( ) ;
142174 while let Some ( event) = parser. next ( ) {
143175 match event {
@@ -215,8 +247,9 @@ pub fn render(w: &mut fmt::Formatter,
215247 } ) ;
216248 }
217249
218- fn heading ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
219- shorter : MarkdownOutputStyle , level : i32 ) {
250+ fn heading ( parser : & mut ParserWrapper , buffer : & mut String ,
251+ toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle , level : i32 ) {
252+ debug ! ( "Heading" ) ;
220253 let mut ret = String :: new ( ) ;
221254 let mut id = String :: new ( ) ;
222255 event_loop_break ! ( parser, toc_builder, shorter, ret, true , & mut Some ( & mut id) ,
@@ -249,32 +282,53 @@ pub fn render(w: &mut fmt::Formatter,
249282 ret, lvl = level, id = id, sec = sec) ) ;
250283 }
251284
252- fn inline_code ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
253- shorter : MarkdownOutputStyle , id : & mut Option < & mut String > ) {
285+ fn inline_code ( parser : & mut ParserWrapper , buffer : & mut String ,
286+ toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle ,
287+ id : & mut Option < & mut String > ) {
288+ debug ! ( "InlineCode" ) ;
254289 let mut content = String :: new ( ) ;
255290 event_loop_break ! ( parser, toc_builder, shorter, content, false , id, Event :: End ( Tag :: Code ) ) ;
256291 buffer. push_str ( & format ! ( "<code>{}</code>" ,
257292 Escape ( & collapse_whitespace( content. trim_right( ) ) ) ) ) ;
258293 }
259294
260- fn link ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
295+ fn link ( parser : & mut ParserWrapper , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
296+ shorter : MarkdownOutputStyle , url : & str , title : & str ,
297+ id : & mut Option < & mut String > ) {
298+ debug ! ( "Link" ) ;
299+ let mut content = String :: new ( ) ;
300+ event_loop_break ! ( parser, toc_builder, shorter, content, true , id,
301+ Event :: End ( Tag :: Link ( _, _) ) ) ;
302+ if title. is_empty ( ) {
303+ buffer. push_str ( & format ! ( "<a href=\" {}\" >{}</a>" , url, content) ) ;
304+ } else {
305+ buffer. push_str ( & format ! ( "<a href=\" {}\" title=\" {}\" >{}</a>" ,
306+ url, Escape ( title) , content) ) ;
307+ }
308+ }
309+
310+ fn image ( parser : & mut ParserWrapper , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
261311 shorter : MarkdownOutputStyle , url : & str , mut title : String ,
262312 id : & mut Option < & mut String > ) {
313+ debug ! ( "Image" ) ;
263314 event_loop_break ! ( parser, toc_builder, shorter, title, true , id,
264- Event :: End ( Tag :: Link ( _, _) ) ) ;
265- buffer. push_str ( & format ! ( "<a href =\" {}\" >{}</a >" , url, title) ) ;
315+ Event :: End ( Tag :: Image ( _, _) ) ) ;
316+ buffer. push_str ( & format ! ( "<img src =\" {}\" alt= \" {} \" >" , url, title) ) ;
266317 }
267318
268- fn paragraph ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
269- shorter : MarkdownOutputStyle , id : & mut Option < & mut String > ) {
319+ fn paragraph ( parser : & mut ParserWrapper , buffer : & mut String ,
320+ toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle ,
321+ id : & mut Option < & mut String > ) {
322+ debug ! ( "Paragraph" ) ;
270323 let mut content = String :: new ( ) ;
271324 event_loop_break ! ( parser, toc_builder, shorter, content, true , id,
272325 Event :: End ( Tag :: Paragraph ) ) ;
273326 buffer. push_str ( & format ! ( "<p>{}</p>" , content. trim_right( ) ) ) ;
274327 }
275328
276- fn table_cell ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
277- shorter : MarkdownOutputStyle ) {
329+ fn table_cell ( parser : & mut ParserWrapper , buffer : & mut String ,
330+ toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle ) {
331+ debug ! ( "TableCell" ) ;
278332 let mut content = String :: new ( ) ;
279333 event_loop_break ! ( parser, toc_builder, shorter, content, true , & mut None ,
280334 Event :: End ( Tag :: TableHead ) |
@@ -284,8 +338,9 @@ pub fn render(w: &mut fmt::Formatter,
284338 buffer. push_str ( & format ! ( "<td>{}</td>" , content. trim( ) ) ) ;
285339 }
286340
287- fn table_row ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
288- shorter : MarkdownOutputStyle ) {
341+ fn table_row ( parser : & mut ParserWrapper , buffer : & mut String ,
342+ toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle ) {
343+ debug ! ( "TableRow" ) ;
289344 let mut content = String :: new ( ) ;
290345 while let Some ( event) = parser. next ( ) {
291346 match event {
@@ -303,8 +358,9 @@ pub fn render(w: &mut fmt::Formatter,
303358 buffer. push_str ( & format ! ( "<tr>{}</tr>" , content) ) ;
304359 }
305360
306- fn table_head ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
307- shorter : MarkdownOutputStyle ) {
361+ fn table_head ( parser : & mut ParserWrapper , buffer : & mut String ,
362+ toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle ) {
363+ debug ! ( "TableHead" ) ;
308364 let mut content = String :: new ( ) ;
309365 while let Some ( event) = parser. next ( ) {
310366 match event {
@@ -322,8 +378,9 @@ pub fn render(w: &mut fmt::Formatter,
322378 }
323379 }
324380
325- fn table ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
381+ fn table ( parser : & mut ParserWrapper , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
326382 shorter : MarkdownOutputStyle ) {
383+ debug ! ( "Table" ) ;
327384 let mut content = String :: new ( ) ;
328385 let mut rows = String :: new ( ) ;
329386 while let Some ( event) = parser. next ( ) {
@@ -347,16 +404,18 @@ pub fn render(w: &mut fmt::Formatter,
347404 } ) ) ;
348405 }
349406
350- fn blockquote ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
351- shorter : MarkdownOutputStyle ) {
407+ fn blockquote ( parser : & mut ParserWrapper , buffer : & mut String ,
408+ toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle ) {
409+ debug ! ( "BlockQuote" ) ;
352410 let mut content = String :: new ( ) ;
353411 event_loop_break ! ( parser, toc_builder, shorter, content, true , & mut None ,
354412 Event :: End ( Tag :: BlockQuote ) ) ;
355413 buffer. push_str ( & format ! ( "<blockquote>{}</blockquote>" , content. trim_right( ) ) ) ;
356414 }
357415
358- fn list_item ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
359- shorter : MarkdownOutputStyle ) {
416+ fn list_item ( parser : & mut ParserWrapper , buffer : & mut String ,
417+ toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle ) {
418+ debug ! ( "ListItem" ) ;
360419 let mut content = String :: new ( ) ;
361420 while let Some ( event) = parser. next ( ) {
362421 match event {
@@ -372,8 +431,9 @@ pub fn render(w: &mut fmt::Formatter,
372431 buffer. push_str ( & format ! ( "<li>{}</li>" , content) ) ;
373432 }
374433
375- fn list ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
434+ fn list ( parser : & mut ParserWrapper , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
376435 shorter : MarkdownOutputStyle ) {
436+ debug ! ( "List" ) ;
377437 let mut content = String :: new ( ) ;
378438 while let Some ( event) = parser. next ( ) {
379439 match event {
@@ -389,23 +449,45 @@ pub fn render(w: &mut fmt::Formatter,
389449 buffer. push_str ( & format ! ( "<ul>{}</ul>" , content) ) ;
390450 }
391451
392- fn emphasis ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
393- shorter : MarkdownOutputStyle , id : & mut Option < & mut String > ) {
452+ fn emphasis ( parser : & mut ParserWrapper , buffer : & mut String ,
453+ toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle ,
454+ id : & mut Option < & mut String > ) {
455+ debug ! ( "Emphasis" ) ;
394456 let mut content = String :: new ( ) ;
395457 event_loop_break ! ( parser, toc_builder, shorter, content, false , id,
396458 Event :: End ( Tag :: Emphasis ) ) ;
397459 buffer. push_str ( & format ! ( "<em>{}</em>" , content) ) ;
398460 }
399461
400- fn strong ( parser : & mut Parser , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
462+ fn strong ( parser : & mut ParserWrapper , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
401463 shorter : MarkdownOutputStyle , id : & mut Option < & mut String > ) {
464+ debug ! ( "Strong" ) ;
402465 let mut content = String :: new ( ) ;
403466 event_loop_break ! ( parser, toc_builder, shorter, content, false , id,
404467 Event :: End ( Tag :: Strong ) ) ;
405468 buffer. push_str ( & format ! ( "<strong>{}</strong>" , content) ) ;
406469 }
407470
408- fn looper < ' a > ( parser : & ' a mut Parser , buffer : & mut String , next_event : Option < Event < ' a > > ,
471+ fn footnote ( parser : & mut ParserWrapper , buffer : & mut String ,
472+ toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle ,
473+ id : & mut Option < & mut String > ) {
474+ debug ! ( "FootnoteDefinition" ) ;
475+ let mut content = String :: new ( ) ;
476+ event_loop_break ! ( parser, toc_builder, shorter, content, true , id,
477+ Event :: End ( Tag :: FootnoteDefinition ( _) ) ) ;
478+ buffer. push_str ( & content) ;
479+ }
480+
481+ fn rule ( parser : & mut ParserWrapper , buffer : & mut String , toc_builder : & mut Option < TocBuilder > ,
482+ shorter : MarkdownOutputStyle , id : & mut Option < & mut String > ) {
483+ debug ! ( "Rule" ) ;
484+ let mut content = String :: new ( ) ;
485+ event_loop_break ! ( parser, toc_builder, shorter, content, true , id,
486+ Event :: End ( Tag :: Rule ) ) ;
487+ buffer. push_str ( "<hr>" ) ;
488+ }
489+
490+ fn looper < ' a > ( parser : & ' a mut ParserWrapper , buffer : & mut String , next_event : Option < Event < ' a > > ,
409491 toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle ,
410492 id : & mut Option < & mut String > ) -> bool {
411493 if let Some ( event) = next_event {
@@ -423,7 +505,10 @@ pub fn render(w: &mut fmt::Formatter,
423505 paragraph ( parser, buffer, toc_builder, shorter, id) ;
424506 }
425507 Event :: Start ( Tag :: Link ( ref url, ref t) ) => {
426- link ( parser, buffer, toc_builder, shorter, url, t. as_ref ( ) . to_owned ( ) , id) ;
508+ link ( parser, buffer, toc_builder, shorter, url, t. as_ref ( ) , id) ;
509+ }
510+ Event :: Start ( Tag :: Image ( ref url, ref t) ) => {
511+ image ( parser, buffer, toc_builder, shorter, url, t. as_ref ( ) . to_owned ( ) , id) ;
427512 }
428513 Event :: Start ( Tag :: Table ( _) ) => {
429514 table ( parser, buffer, toc_builder, shorter) ;
@@ -440,7 +525,42 @@ pub fn render(w: &mut fmt::Formatter,
440525 Event :: Start ( Tag :: Strong ) => {
441526 strong ( parser, buffer, toc_builder, shorter, id) ;
442527 }
528+ Event :: Start ( Tag :: Rule ) => {
529+ rule ( parser, buffer, toc_builder, shorter, id) ;
530+ }
531+ Event :: Start ( Tag :: FootnoteDefinition ( ref def) ) => {
532+ debug ! ( "FootnoteDefinition" ) ;
533+ let mut content = String :: new ( ) ;
534+ let def = def. as_ref ( ) ;
535+ footnote ( parser, & mut content, toc_builder, shorter, id) ;
536+ let entry = parser. get_entry ( def) ;
537+ let cur_id = ( * entry) . 1 ;
538+ ( * entry) . 0 . push_str ( & format ! ( "<li id=\" ref{}\" >{} <a href=\" #supref{0}\" \
539+ rev=\" footnote\" >↩</a></p></li>",
540+ cur_id,
541+ if content. ends_with( "</p>" ) {
542+ & content[ ..content. len( ) - 4 ]
543+ } else {
544+ & content
545+ } ) ) ;
546+ }
547+ Event :: FootnoteReference ( ref reference) => {
548+ debug ! ( "FootnoteReference" ) ;
549+ let entry = parser. get_entry ( reference. as_ref ( ) ) ;
550+ buffer. push_str ( & format ! ( "<sup id=\" supref{0}\" ><a href=\" #ref{0}\" >{0}</a>\
551+ </sup>",
552+ ( * entry) . 1 ) ) ;
553+ }
554+ Event :: HardBreak => {
555+ debug ! ( "HardBreak" ) ;
556+ if shorter. is_fancy ( ) {
557+ buffer. push_str ( "<br>" ) ;
558+ } else if !buffer. is_empty ( ) {
559+ buffer. push ( ' ' ) ;
560+ }
561+ }
443562 Event :: Html ( h) | Event :: InlineHtml ( h) => {
563+ debug ! ( "Html/InlineHtml" ) ;
444564 buffer. push_str ( & * h) ;
445565 }
446566 _ => { }
@@ -457,13 +577,22 @@ pub fn render(w: &mut fmt::Formatter,
457577 None
458578 } ;
459579 let mut buffer = String :: new ( ) ;
460- let mut parser = Parser :: new_ext ( s , pulldown_cmark :: OPTION_ENABLE_TABLES ) ;
580+ let mut parser = ParserWrapper :: new ( s ) ;
461581 loop {
462582 let next_event = parser. next ( ) ;
463583 if !looper ( & mut parser, & mut buffer, next_event, & mut toc_builder, shorter, & mut None ) {
464584 break
465585 }
466586 }
587+ if !parser. footnotes . is_empty ( ) {
588+ let mut v: Vec < _ > = parser. footnotes . values ( ) . collect ( ) ;
589+ v. sort_by ( |a, b| a. 1 . cmp ( & b. 1 ) ) ;
590+ buffer. push_str ( & format ! ( "<div class=\" footnotes\" ><hr><ol>{}</ol></div>" ,
591+ v. iter( )
592+ . map( |s| s. 0 . as_str( ) )
593+ . collect:: <Vec <_>>( )
594+ . join( "" ) ) ) ;
595+ }
467596 let mut ret = toc_builder. map_or ( Ok ( ( ) ) , |builder| {
468597 write ! ( w, "<nav id=\" TOC\" >{}</nav>" , builder. into_toc( ) )
469598 } ) ;
0 commit comments