@@ -47,13 +47,13 @@ pub(crate) fn process_autolinks<'a>(
47
47
}
48
48
}
49
49
b'w' => {
50
- post_org = www_match ( arena, contents, i) ;
50
+ post_org = www_match ( arena, contents, i, relaxed_autolinks ) ;
51
51
if post_org. is_some ( ) {
52
52
break ;
53
53
}
54
54
}
55
55
b'@' => {
56
- post_org = email_match ( arena, contents, i) ;
56
+ post_org = email_match ( arena, contents, i, relaxed_autolinks ) ;
57
57
if post_org. is_some ( ) {
58
58
break ;
59
59
}
@@ -85,6 +85,7 @@ fn www_match<'a>(
85
85
arena : & ' a Arena < AstNode < ' a > > ,
86
86
contents : & [ u8 ] ,
87
87
i : usize ,
88
+ relaxed_autolinks : bool ,
88
89
) -> Option < ( & ' a AstNode < ' a > , usize , usize ) > {
89
90
static WWW_DELIMS : Lazy < [ bool ; 256 ] > = Lazy :: new ( || {
90
91
let mut sc = [ false ; 256 ] ;
@@ -111,7 +112,7 @@ fn www_match<'a>(
111
112
link_end += 1 ;
112
113
}
113
114
114
- link_end = autolink_delim ( & contents[ i..] , link_end) ;
115
+ link_end = autolink_delim ( & contents[ i..] , link_end, relaxed_autolinks ) ;
115
116
116
117
let mut url = "http://" . to_string ( ) ;
117
118
url. push_str ( str:: from_utf8 ( & contents[ i..link_end + i] ) . unwrap ( ) ) ;
@@ -170,12 +171,10 @@ fn is_valid_hostchar(ch: char) -> bool {
170
171
!ch. is_whitespace ( ) && !ch. is_punctuation ( )
171
172
}
172
173
173
- fn autolink_delim ( data : & [ u8 ] , mut link_end : usize ) -> usize {
174
+ fn autolink_delim ( data : & [ u8 ] , mut link_end : usize , relaxed_autolinks : bool ) -> usize {
174
175
static LINK_END_ASSORTMENT : Lazy < [ bool ; 256 ] > = Lazy :: new ( || {
175
176
let mut sc = [ false ; 256 ] ;
176
- for c in & [
177
- b'?' , b'!' , b'.' , b',' , b':' , b'*' , b'_' , b'~' , b'\'' , b'"' , b'[' , b']' ,
178
- ] {
177
+ for c in & [ b'?' , b'!' , b'.' , b',' , b':' , b'*' , b'_' , b'~' , b'\'' , b'"' ] {
179
178
sc[ * c as usize ] = true ;
180
179
}
181
180
sc
@@ -191,7 +190,22 @@ fn autolink_delim(data: &[u8], mut link_end: usize) -> usize {
191
190
while link_end > 0 {
192
191
let cclose = data[ link_end - 1 ] ;
193
192
194
- let copen = if cclose == b')' { Some ( b'(' ) } else { None } ;
193
+ // Allow any number of matching parentheses (as recognised in copen/cclose)
194
+ // at the end of the URL. If there is a greater number of closing
195
+ // parentheses than opening ones, we remove one character from the end of
196
+ // the link.
197
+ let mut copen = if cclose == b')' { Some ( b'(' ) } else { None } ;
198
+
199
+ if relaxed_autolinks && copen. is_none ( ) {
200
+ // allow balancing of `[]` and `{}` just like `()`
201
+ copen = if cclose == b']' {
202
+ Some ( b'[' )
203
+ } else if cclose == b'}' {
204
+ Some ( b'{' )
205
+ } else {
206
+ None
207
+ } ;
208
+ }
195
209
196
210
if LINK_END_ASSORTMENT [ cclose as usize ] {
197
211
link_end -= 1 ;
@@ -266,7 +280,7 @@ fn url_match<'a>(
266
280
link_end += 1 ;
267
281
}
268
282
269
- link_end = autolink_delim ( & contents[ i..] , link_end) ;
283
+ link_end = autolink_delim ( & contents[ i..] , link_end, relaxed_autolinks ) ;
270
284
271
285
let url = str:: from_utf8 ( & contents[ i - rewind..i + link_end] )
272
286
. unwrap ( )
@@ -292,6 +306,7 @@ fn email_match<'a>(
292
306
arena : & ' a Arena < AstNode < ' a > > ,
293
307
contents : & [ u8 ] ,
294
308
i : usize ,
309
+ relaxed_autolinks : bool ,
295
310
) -> Option < ( & ' a AstNode < ' a > , usize , usize ) > {
296
311
static EMAIL_OK_SET : Lazy < [ bool ; 256 ] > = Lazy :: new ( || {
297
312
let mut sc = [ false ; 256 ] ;
@@ -365,7 +380,7 @@ fn email_match<'a>(
365
380
return None ;
366
381
}
367
382
368
- link_end = autolink_delim ( & contents[ i..] , link_end) ;
383
+ link_end = autolink_delim ( & contents[ i..] , link_end, relaxed_autolinks ) ;
369
384
if link_end == 0 {
370
385
return None ;
371
386
}
0 commit comments