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;
@@ -115,15 +116,19 @@ macro_rules! event_loop_break {
115
116
match event {
116
117
$( $end_event) |* => break ,
117
118
Event :: Text ( ref s) => {
119
+ debug!( "Text" ) ;
118
120
inner( $id, s) ;
119
121
if $escape {
120
122
$buf. push_str( & format!( "{}" , Escape ( s) ) ) ;
121
123
} else {
122
124
$buf. push_str( s) ;
123
125
}
124
126
}
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
+ }
127
132
}
128
133
x => {
129
134
looper( $parser, & mut $buf, Some ( x) , $toc_builder, $shorter, $id) ;
@@ -133,11 +138,38 @@ macro_rules! event_loop_break {
133
138
} }
134
139
}
135
140
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
+
136
167
pub fn render ( w : & mut fmt:: Formatter ,
137
168
s : & str ,
138
169
print_toc : bool ,
139
170
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" ) ;
141
173
let mut origtext = String :: new ( ) ;
142
174
while let Some ( event) = parser. next ( ) {
143
175
match event {
@@ -215,8 +247,9 @@ pub fn render(w: &mut fmt::Formatter,
215
247
} ) ;
216
248
}
217
249
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" ) ;
220
253
let mut ret = String :: new ( ) ;
221
254
let mut id = String :: new ( ) ;
222
255
event_loop_break ! ( parser, toc_builder, shorter, ret, true , & mut Some ( & mut id) ,
@@ -249,32 +282,53 @@ pub fn render(w: &mut fmt::Formatter,
249
282
ret, lvl = level, id = id, sec = sec) ) ;
250
283
}
251
284
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" ) ;
254
289
let mut content = String :: new ( ) ;
255
290
event_loop_break ! ( parser, toc_builder, shorter, content, false , id, Event :: End ( Tag :: Code ) ) ;
256
291
buffer. push_str ( & format ! ( "<code>{}</code>" ,
257
292
Escape ( & collapse_whitespace( content. trim_right( ) ) ) ) ) ;
258
293
}
259
294
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 > ,
261
311
shorter : MarkdownOutputStyle , url : & str , mut title : String ,
262
312
id : & mut Option < & mut String > ) {
313
+ debug ! ( "Image" ) ;
263
314
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) ) ;
266
317
}
267
318
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" ) ;
270
323
let mut content = String :: new ( ) ;
271
324
event_loop_break ! ( parser, toc_builder, shorter, content, true , id,
272
325
Event :: End ( Tag :: Paragraph ) ) ;
273
326
buffer. push_str ( & format ! ( "<p>{}</p>" , content. trim_right( ) ) ) ;
274
327
}
275
328
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" ) ;
278
332
let mut content = String :: new ( ) ;
279
333
event_loop_break ! ( parser, toc_builder, shorter, content, true , & mut None ,
280
334
Event :: End ( Tag :: TableHead ) |
@@ -284,8 +338,9 @@ pub fn render(w: &mut fmt::Formatter,
284
338
buffer. push_str ( & format ! ( "<td>{}</td>" , content. trim( ) ) ) ;
285
339
}
286
340
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" ) ;
289
344
let mut content = String :: new ( ) ;
290
345
while let Some ( event) = parser. next ( ) {
291
346
match event {
@@ -303,8 +358,9 @@ pub fn render(w: &mut fmt::Formatter,
303
358
buffer. push_str ( & format ! ( "<tr>{}</tr>" , content) ) ;
304
359
}
305
360
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" ) ;
308
364
let mut content = String :: new ( ) ;
309
365
while let Some ( event) = parser. next ( ) {
310
366
match event {
@@ -322,8 +378,9 @@ pub fn render(w: &mut fmt::Formatter,
322
378
}
323
379
}
324
380
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 > ,
326
382
shorter : MarkdownOutputStyle ) {
383
+ debug ! ( "Table" ) ;
327
384
let mut content = String :: new ( ) ;
328
385
let mut rows = String :: new ( ) ;
329
386
while let Some ( event) = parser. next ( ) {
@@ -347,16 +404,18 @@ pub fn render(w: &mut fmt::Formatter,
347
404
} ) ) ;
348
405
}
349
406
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" ) ;
352
410
let mut content = String :: new ( ) ;
353
411
event_loop_break ! ( parser, toc_builder, shorter, content, true , & mut None ,
354
412
Event :: End ( Tag :: BlockQuote ) ) ;
355
413
buffer. push_str ( & format ! ( "<blockquote>{}</blockquote>" , content. trim_right( ) ) ) ;
356
414
}
357
415
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" ) ;
360
419
let mut content = String :: new ( ) ;
361
420
while let Some ( event) = parser. next ( ) {
362
421
match event {
@@ -372,8 +431,9 @@ pub fn render(w: &mut fmt::Formatter,
372
431
buffer. push_str ( & format ! ( "<li>{}</li>" , content) ) ;
373
432
}
374
433
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 > ,
376
435
shorter : MarkdownOutputStyle ) {
436
+ debug ! ( "List" ) ;
377
437
let mut content = String :: new ( ) ;
378
438
while let Some ( event) = parser. next ( ) {
379
439
match event {
@@ -389,23 +449,45 @@ pub fn render(w: &mut fmt::Formatter,
389
449
buffer. push_str ( & format ! ( "<ul>{}</ul>" , content) ) ;
390
450
}
391
451
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" ) ;
394
456
let mut content = String :: new ( ) ;
395
457
event_loop_break ! ( parser, toc_builder, shorter, content, false , id,
396
458
Event :: End ( Tag :: Emphasis ) ) ;
397
459
buffer. push_str ( & format ! ( "<em>{}</em>" , content) ) ;
398
460
}
399
461
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 > ,
401
463
shorter : MarkdownOutputStyle , id : & mut Option < & mut String > ) {
464
+ debug ! ( "Strong" ) ;
402
465
let mut content = String :: new ( ) ;
403
466
event_loop_break ! ( parser, toc_builder, shorter, content, false , id,
404
467
Event :: End ( Tag :: Strong ) ) ;
405
468
buffer. push_str ( & format ! ( "<strong>{}</strong>" , content) ) ;
406
469
}
407
470
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 > > ,
409
491
toc_builder : & mut Option < TocBuilder > , shorter : MarkdownOutputStyle ,
410
492
id : & mut Option < & mut String > ) -> bool {
411
493
if let Some ( event) = next_event {
@@ -423,7 +505,10 @@ pub fn render(w: &mut fmt::Formatter,
423
505
paragraph ( parser, buffer, toc_builder, shorter, id) ;
424
506
}
425
507
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) ;
427
512
}
428
513
Event :: Start ( Tag :: Table ( _) ) => {
429
514
table ( parser, buffer, toc_builder, shorter) ;
@@ -440,7 +525,42 @@ pub fn render(w: &mut fmt::Formatter,
440
525
Event :: Start ( Tag :: Strong ) => {
441
526
strong ( parser, buffer, toc_builder, shorter, id) ;
442
527
}
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
+ }
443
562
Event :: Html ( h) | Event :: InlineHtml ( h) => {
563
+ debug ! ( "Html/InlineHtml" ) ;
444
564
buffer. push_str ( & * h) ;
445
565
}
446
566
_ => { }
@@ -457,13 +577,22 @@ pub fn render(w: &mut fmt::Formatter,
457
577
None
458
578
} ;
459
579
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 ) ;
461
581
loop {
462
582
let next_event = parser. next ( ) ;
463
583
if !looper ( & mut parser, & mut buffer, next_event, & mut toc_builder, shorter, & mut None ) {
464
584
break
465
585
}
466
586
}
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
+ }
467
596
let mut ret = toc_builder. map_or ( Ok ( ( ) ) , |builder| {
468
597
write ! ( w, "<nav id=\" TOC\" >{}</nav>" , builder. into_toc( ) )
469
598
} ) ;
0 commit comments