@@ -17,6 +17,7 @@ pub enum Token<'input> {
17
17
Subject ( String ) ,
18
18
Scissored ( & ' input str ) ,
19
19
Trailer ( & ' input str ) ,
20
+ BlockQuote ( & ' input str ) ,
20
21
VerticalSpace ,
21
22
}
22
23
@@ -83,7 +84,13 @@ pub fn parse(input: &str, comment_char: char) -> Vec<Token> {
83
84
toks. push ( Token :: Trailer ( line) ) ;
84
85
} else if let Some ( y) = match toks. last_mut ( ) {
85
86
Some ( & mut Token :: Footnote ( _, ref mut b) ) => extend_prose_buffer_with_line ( b, line) ,
86
- Some ( & mut Token :: Paragraph ( ref mut b) ) => extend_prose_buffer_with_line ( b, line) ,
87
+ Some ( & mut Token :: Paragraph ( ref mut b) ) => {
88
+ if is_line_block_quote ( line) {
89
+ Some ( Token :: BlockQuote ( line) )
90
+ } else {
91
+ extend_prose_buffer_with_line ( b, line)
92
+ }
93
+ }
87
94
Some ( & mut Token :: ListItem ( _, _, ref mut b) ) => {
88
95
if list_item. is_match ( line) {
89
96
Some ( list_item_from_line ( & list_item, line) )
@@ -96,6 +103,8 @@ pub fn parse(input: &str, comment_char: char) -> Vec<Token> {
96
103
Some ( list_item_from_line ( & list_item, line) )
97
104
} else if is_line_indented ( line) {
98
105
Some ( Token :: Literal ( line) )
106
+ } else if is_line_block_quote ( line) {
107
+ Some ( Token :: BlockQuote ( line) )
99
108
} else {
100
109
px = false ;
101
110
Some ( Token :: Paragraph ( line. trim ( ) . to_owned ( ) ) )
@@ -209,6 +218,10 @@ fn is_line_footnote(line: &str) -> bool {
209
218
false
210
219
}
211
220
221
+ fn is_line_block_quote ( line : & str ) -> bool {
222
+ line. starts_with ( '>' )
223
+ }
224
+
212
225
#[ cfg( test) ]
213
226
mod tests {
214
227
use super :: Token :: * ;
@@ -513,6 +526,113 @@ some other paragraph
513
526
) ;
514
527
}
515
528
529
+ #[ test]
530
+ fn parses_block_quote_verbatim ( ) {
531
+ assert_eq ! (
532
+ parse(
533
+ "
534
+ some subject
535
+
536
+ some paragraph
537
+
538
+ > some block quote
539
+
540
+ some other paragraph
541
+ "
542
+ ) ,
543
+ [
544
+ VerticalSpace ,
545
+ Subject ( "some subject" . to_owned( ) ) ,
546
+ VerticalSpace ,
547
+ Paragraph ( "some paragraph" . to_owned( ) ) ,
548
+ VerticalSpace ,
549
+ BlockQuote ( "> some block quote" ) ,
550
+ VerticalSpace ,
551
+ Paragraph ( "some other paragraph" . to_owned( ) ) ,
552
+ ] ,
553
+ ) ;
554
+ }
555
+
556
+ #[ test]
557
+ fn parses_nested_block_quotes_verbatim ( ) {
558
+ assert_eq ! (
559
+ parse(
560
+ "
561
+ some subject
562
+
563
+ some paragraph
564
+
565
+ > > some block quote
566
+
567
+ some other paragraph
568
+ "
569
+ ) ,
570
+ [
571
+ VerticalSpace ,
572
+ Subject ( "some subject" . to_owned( ) ) ,
573
+ VerticalSpace ,
574
+ Paragraph ( "some paragraph" . to_owned( ) ) ,
575
+ VerticalSpace ,
576
+ BlockQuote ( "> > some block quote" ) ,
577
+ VerticalSpace ,
578
+ Paragraph ( "some other paragraph" . to_owned( ) ) ,
579
+ ] ,
580
+ ) ;
581
+ }
582
+
583
+ #[ test]
584
+ fn parses_nested_block_quotes_ignoring_quote_marker_spacing_and_quote_levels ( ) {
585
+ assert_eq ! (
586
+ parse(
587
+ "
588
+ some subject
589
+
590
+ some paragraph
591
+
592
+ >>>> >>> >> some block quote
593
+
594
+ some other paragraph
595
+ "
596
+ ) ,
597
+ [
598
+ VerticalSpace ,
599
+ Subject ( "some subject" . to_owned( ) ) ,
600
+ VerticalSpace ,
601
+ Paragraph ( "some paragraph" . to_owned( ) ) ,
602
+ VerticalSpace ,
603
+ BlockQuote ( ">>>> >>> >> some block quote" ) ,
604
+ VerticalSpace ,
605
+ Paragraph ( "some other paragraph" . to_owned( ) ) ,
606
+ ] ,
607
+ ) ;
608
+ }
609
+
610
+ #[ test]
611
+ fn parses_block_quote_with_immediately_preceding_paragraph_as_attribution_leaving_no_vertical_space (
612
+ ) {
613
+ assert_eq ! (
614
+ parse(
615
+ "
616
+ some subject
617
+
618
+ some attribution paragraph
619
+ > some block quote
620
+
621
+ some other paragraph
622
+ "
623
+ ) ,
624
+ [
625
+ VerticalSpace ,
626
+ Subject ( "some subject" . to_owned( ) ) ,
627
+ VerticalSpace ,
628
+ Paragraph ( "some attribution paragraph" . to_owned( ) ) ,
629
+ BlockQuote ( "> some block quote" ) ,
630
+ VerticalSpace ,
631
+ Paragraph ( "some other paragraph" . to_owned( ) ) ,
632
+ ] ,
633
+ ) ;
634
+ }
635
+
516
636
#[ test]
517
637
fn parses_trailers ( ) {
518
638
// Trailers look like HTTP or email headers but are not formally
0 commit comments