@@ -10,15 +10,11 @@ const CBK: &[u8] = b"```";
10
10
const CIL : & [ u8 ] = b"`" ;
11
11
const CMT_E : & [ u8 ] = b"-->" ;
12
12
const CMT_S : & [ u8 ] = b"<!--" ;
13
- const EMP : & [ u8 ] = b"_" ;
14
13
const HDG : & [ u8 ] = b"#" ;
15
14
const LNK_CHARS : & str = "$-_.+!*'()/&?=:%" ;
16
15
const LNK_E : & [ u8 ] = b"]" ;
17
16
const LNK_S : & [ u8 ] = b"[" ;
18
- const STG : & [ u8 ] = b"**" ;
19
17
const STK : & [ u8 ] = b"~~" ;
20
- const UL1 : & [ u8 ] = b"* " ;
21
- const UL2 : & [ u8 ] = b"- " ;
22
18
23
19
/// Pattern replacements
24
20
const REPLACEMENTS : & [ ( & str , & str ) ] = & [
@@ -100,25 +96,26 @@ fn parse_recursive<'a>(buf: &'a [u8], ctx: Context) -> MdStream<'_> {
100
96
} ;
101
97
102
98
let res: ParseResult < ' _ > = match ( top_blk, prev) {
103
- ( _ , Newline | Whitespace ) if loop_buf. starts_with ( CMT_S ) => {
99
+ _ if loop_buf. starts_with ( CMT_S ) => {
104
100
parse_simple_pat ( loop_buf, CMT_S , CMT_E , Po :: TrimNoEsc , MdTree :: Comment )
105
101
}
106
102
( true , Newline ) if loop_buf. starts_with ( CBK ) => Some ( parse_codeblock ( loop_buf) ) ,
107
- ( _ , Newline | Whitespace ) if loop_buf. starts_with ( CIL ) => parse_codeinline ( loop_buf) ,
103
+ _ if loop_buf. starts_with ( CIL ) => parse_codeinline ( loop_buf) ,
108
104
( true , Newline | Whitespace ) if loop_buf. starts_with ( HDG ) => parse_heading ( loop_buf) ,
109
105
( true , Newline ) if loop_buf. starts_with ( BRK ) => {
110
106
Some ( ( MdTree :: HorizontalRule , parse_to_newline ( loop_buf) . 1 ) )
111
107
}
112
- ( _, Newline | Whitespace ) if loop_buf. starts_with ( EMP ) => {
113
- parse_simple_pat ( loop_buf, EMP , EMP , Po :: None , MdTree :: Emphasis )
108
+ ( _, Newline ) if unordered_list_start ( loop_buf) => Some ( parse_unordered_li ( loop_buf) ) ,
109
+ _ if let Some ( strong @ ( b"**" | b"__" ) ) = loop_buf. get ( ..2 ) => {
110
+ parse_simple_pat ( loop_buf, strong, strong, Po :: None , MdTree :: Strong )
114
111
}
115
- ( _ , Newline | Whitespace ) if loop_buf. starts_with ( STG ) => {
116
- parse_simple_pat ( loop_buf, STG , STG , Po :: None , MdTree :: Strong )
112
+ _ if let Some ( emph @ ( b"*" | b"_" ) ) = loop_buf. get ( .. 1 ) => {
113
+ parse_simple_pat ( loop_buf, emph , emph , Po :: None , MdTree :: Emphasis )
117
114
}
118
- ( _ , Newline | Whitespace ) if loop_buf. starts_with ( STK ) => {
115
+ _ if loop_buf. starts_with ( STK ) => {
119
116
parse_simple_pat ( loop_buf, STK , STK , Po :: None , MdTree :: Strikethrough )
120
117
}
121
- ( _ , Newline | Whitespace ) if loop_buf. starts_with ( ANC_S ) => {
118
+ _ if loop_buf. starts_with ( ANC_S ) => {
122
119
let tt_fn = |link| MdTree :: Link { disp : link, link } ;
123
120
let ret = parse_simple_pat ( loop_buf, ANC_S , ANC_E , Po :: None , tt_fn) ;
124
121
match ret {
@@ -130,11 +127,8 @@ fn parse_recursive<'a>(buf: &'a [u8], ctx: Context) -> MdStream<'_> {
130
127
_ => None ,
131
128
}
132
129
}
133
- ( _, Newline ) if ( loop_buf. starts_with ( UL1 ) || loop_buf. starts_with ( UL2 ) ) => {
134
- Some ( parse_unordered_li ( loop_buf) )
135
- }
136
130
( _, Newline ) if ord_list_start ( loop_buf) . is_some ( ) => Some ( parse_ordered_li ( loop_buf) ) ,
137
- ( _ , Newline | Whitespace ) if loop_buf. starts_with ( LNK_S ) => {
131
+ _ if loop_buf. starts_with ( LNK_S ) => {
138
132
parse_any_link ( loop_buf, top_blk && prev == Prev :: Newline )
139
133
}
140
134
( _, Escape | _) => None ,
@@ -251,7 +245,6 @@ fn parse_heading(buf: &[u8]) -> ParseResult<'_> {
251
245
252
246
/// Bulleted list
253
247
fn parse_unordered_li ( buf : & [ u8 ] ) -> Parsed < ' _ > {
254
- debug_assert ! ( buf. starts_with( b"* " ) || buf. starts_with( b"- " ) ) ;
255
248
let ( txt, rest) = get_indented_section ( & buf[ 2 ..] ) ;
256
249
let ctx = Context { top_block : false , prev : Prev :: Whitespace } ;
257
250
let stream = parse_recursive ( trim_ascii_start ( txt) , ctx) ;
@@ -267,25 +260,28 @@ fn parse_ordered_li(buf: &[u8]) -> Parsed<'_> {
267
260
( MdTree :: OrderedListItem ( num, stream) , rest)
268
261
}
269
262
270
- /// Find first line that isn't empty or doesn't start with whitespace, that will
271
- /// be our contents
272
263
fn get_indented_section ( buf : & [ u8 ] ) -> ( & [ u8 ] , & [ u8 ] ) {
273
- let mut end = buf. len ( ) ;
274
- for ( idx, window) in buf. windows ( 2 ) . enumerate ( ) {
275
- let & [ ch, next_ch] = window else { unreachable ! ( "always 2 elements" ) } ;
276
- if idx >= buf. len ( ) . saturating_sub ( 2 ) && next_ch == b'\n' {
277
- // End of stream
278
- end = buf. len ( ) . saturating_sub ( 1 ) ;
279
- break ;
280
- } else if ch == b'\n' && ( !next_ch. is_ascii_whitespace ( ) || next_ch == b'\n' ) {
281
- end = idx;
282
- break ;
264
+ let mut lines = buf. split ( |& byte| byte == b'\n' ) ;
265
+ let mut end = lines. next ( ) . map_or ( 0 , |line| line. len ( ) ) ;
266
+ for line in lines {
267
+ if let Some ( first) = line. first ( ) {
268
+ if unordered_list_start ( line) || !first. is_ascii_whitespace ( ) {
269
+ break ;
270
+ }
283
271
}
272
+ end += line. len ( ) + 1 ;
284
273
}
285
274
286
275
( & buf[ ..end] , & buf[ end..] )
287
276
}
288
277
278
+ fn unordered_list_start ( mut buf : & [ u8 ] ) -> bool {
279
+ while let [ b' ' , rest @ ..] = buf {
280
+ buf = rest;
281
+ }
282
+ matches ! ( buf, [ b'*' | b'-' , b' ' , ..] )
283
+ }
284
+
289
285
/// Verify a valid ordered list start (e.g. `1.`) and parse it. Returns the
290
286
/// parsed number and offset of character after the dot.
291
287
fn ord_list_start ( buf : & [ u8 ] ) -> Option < ( u16 , usize ) > {
0 commit comments