@@ -10,15 +10,15 @@ 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"_" ;
13
+ const EMP_U : & [ u8 ] = b"_" ;
14
+ const EMP_A : & [ u8 ] = b"*" ;
14
15
const HDG : & [ u8 ] = b"#" ;
15
16
const LNK_CHARS : & str = "$-_.+!*'()/&?=:%" ;
16
17
const LNK_E : & [ u8 ] = b"]" ;
17
18
const LNK_S : & [ u8 ] = b"[" ;
18
- const STG : & [ u8 ] = b"**" ;
19
+ const STG_U : & [ u8 ] = b"__" ;
20
+ const STG_A : & [ u8 ] = b"**" ;
19
21
const STK : & [ u8 ] = b"~~" ;
20
- const UL1 : & [ u8 ] = b"* " ;
21
- const UL2 : & [ u8 ] = b"- " ;
22
22
23
23
/// Pattern replacements
24
24
const REPLACEMENTS : & [ ( & str , & str ) ] = & [
@@ -100,22 +100,29 @@ fn parse_recursive<'a>(buf: &'a [u8], ctx: Context) -> MdStream<'_> {
100
100
} ;
101
101
102
102
let res: ParseResult < ' _ > = match ( top_blk, prev) {
103
- ( _ , Newline | Whitespace ) if loop_buf. starts_with ( CMT_S ) => {
103
+ _ if loop_buf. starts_with ( CMT_S ) => {
104
104
parse_simple_pat ( loop_buf, CMT_S , CMT_E , Po :: TrimNoEsc , MdTree :: Comment )
105
105
}
106
106
( 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) ,
107
+ _ if loop_buf. starts_with ( CIL ) => parse_codeinline ( loop_buf) ,
108
108
( true , Newline | Whitespace ) if loop_buf. starts_with ( HDG ) => parse_heading ( loop_buf) ,
109
109
( true , Newline ) if loop_buf. starts_with ( BRK ) => {
110
110
Some ( ( MdTree :: HorizontalRule , parse_to_newline ( loop_buf) . 1 ) )
111
111
}
112
- ( _, Newline | Whitespace ) if loop_buf. starts_with ( EMP ) => {
113
- parse_simple_pat ( loop_buf, EMP , EMP , Po :: None , MdTree :: Emphasis )
112
+ ( _, Newline ) if unordered_list_start ( loop_buf) => Some ( parse_unordered_li ( loop_buf) ) ,
113
+ ( _, Newline | Whitespace ) if loop_buf. starts_with ( STG_U ) => {
114
+ parse_simple_pat ( loop_buf, STG_U , STG_U , Po :: None , MdTree :: Strong )
114
115
}
115
- ( _ , Newline | Whitespace ) if loop_buf. starts_with ( STG ) => {
116
- parse_simple_pat ( loop_buf, STG , STG , Po :: None , MdTree :: Strong )
116
+ _ if loop_buf. starts_with ( STG_A ) => {
117
+ parse_simple_pat ( loop_buf, STG_A , STG_A , Po :: None , MdTree :: Strong )
117
118
}
118
- ( _, Newline | Whitespace ) if loop_buf. starts_with ( STK ) => {
119
+ ( _, Newline | Whitespace ) if loop_buf. starts_with ( EMP_U ) => {
120
+ parse_simple_pat ( loop_buf, EMP_U , EMP_U , Po :: None , MdTree :: Emphasis )
121
+ }
122
+ _ if loop_buf. starts_with ( EMP_A ) => {
123
+ parse_simple_pat ( loop_buf, EMP_A , EMP_A , Po :: None , MdTree :: Emphasis )
124
+ }
125
+ _ if loop_buf. starts_with ( STK ) => {
119
126
parse_simple_pat ( loop_buf, STK , STK , Po :: None , MdTree :: Strikethrough )
120
127
}
121
128
( _, Newline | Whitespace ) if loop_buf. starts_with ( ANC_S ) => {
@@ -130,11 +137,8 @@ fn parse_recursive<'a>(buf: &'a [u8], ctx: Context) -> MdStream<'_> {
130
137
_ => None ,
131
138
}
132
139
}
133
- ( _, Newline ) if ( loop_buf. starts_with ( UL1 ) || loop_buf. starts_with ( UL2 ) ) => {
134
- Some ( parse_unordered_li ( loop_buf) )
135
- }
136
140
( _, 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 ) => {
141
+ _ if loop_buf. starts_with ( LNK_S ) => {
138
142
parse_any_link ( loop_buf, top_blk && prev == Prev :: Newline )
139
143
}
140
144
( _, Escape | _) => None ,
@@ -251,7 +255,6 @@ fn parse_heading(buf: &[u8]) -> ParseResult<'_> {
251
255
252
256
/// Bulleted list
253
257
fn parse_unordered_li ( buf : & [ u8 ] ) -> Parsed < ' _ > {
254
- debug_assert ! ( buf. starts_with( b"* " ) || buf. starts_with( b"- " ) ) ;
255
258
let ( txt, rest) = get_indented_section ( & buf[ 2 ..] ) ;
256
259
let ctx = Context { top_block : false , prev : Prev :: Whitespace } ;
257
260
let stream = parse_recursive ( trim_ascii_start ( txt) , ctx) ;
@@ -267,25 +270,28 @@ fn parse_ordered_li(buf: &[u8]) -> Parsed<'_> {
267
270
( MdTree :: OrderedListItem ( num, stream) , rest)
268
271
}
269
272
270
- /// Find first line that isn't empty or doesn't start with whitespace, that will
271
- /// be our contents
272
273
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 ;
274
+ let mut lines = buf. split ( |& byte| byte == b'\n' ) ;
275
+ let mut end = lines. next ( ) . map_or ( 0 , |line| line. len ( ) ) ;
276
+ for line in lines {
277
+ if let Some ( first) = line. first ( ) {
278
+ if unordered_list_start ( line) || !first. is_ascii_whitespace ( ) {
279
+ break ;
280
+ }
283
281
}
282
+ end += line. len ( ) + 1 ;
284
283
}
285
284
286
285
( & buf[ ..end] , & buf[ end..] )
287
286
}
288
287
288
+ fn unordered_list_start ( mut buf : & [ u8 ] ) -> bool {
289
+ while let [ b' ' , rest @ ..] = buf {
290
+ buf = rest;
291
+ }
292
+ matches ! ( buf, [ b'*' | b'-' , b' ' , ..] )
293
+ }
294
+
289
295
/// Verify a valid ordered list start (e.g. `1.`) and parse it. Returns the
290
296
/// parsed number and offset of character after the dot.
291
297
fn ord_list_start ( buf : & [ u8 ] ) -> Option < ( u16 , usize ) > {
0 commit comments