@@ -150,8 +150,8 @@ static CMARK_INLINE cmark_node *make_autolink(subject *subj,
150150 link -> as .link .url = cmark_clean_autolink (subj -> mem , & url , is_email );
151151 link -> as .link .title = cmark_chunk_literal ("" );
152152 link -> start_line = link -> end_line = subj -> line ;
153- link -> start_column = start_column + 1 ;
154- link -> end_column = end_column + 1 ;
153+ link -> start_column = subj -> column_offset + subj -> block_offset + start_column + 1 ;
154+ link -> end_column = subj -> column_offset + subj -> block_offset + end_column + 1 ;
155155 cmark_node_append_child (link , make_str_with_entities (subj , start_column + 1 , end_column - 1 , & url ));
156156 return link ;
157157}
@@ -325,10 +325,10 @@ static bufsize_t scan_to_closing_backticks(subject *subj,
325325// spaces, then removing a single leading + trailing space,
326326// unless the code span consists entirely of space characters.
327327static void S_normalize_code (cmark_strbuf * s ) {
328- bufsize_t r , w ;
328+ bufsize_t r , w , last_char_after_nl ;
329329 bool contains_nonspace = false;
330330
331- for (r = 0 , w = 0 ; r < s -> size ; ++ r ) {
331+ for (r = 0 , w = 0 , last_char_after_nl = 0 ; r < s -> size ; ++ r ) {
332332 switch (s -> ptr [r ]) {
333333 case '\r' :
334334 if (s -> ptr [r + 1 ] != '\n' ) {
@@ -337,15 +337,46 @@ static void S_normalize_code(cmark_strbuf *s) {
337337 break ;
338338 case '\n' :
339339 s -> ptr [w ++ ] = ' ' ;
340+ last_char_after_nl = w ;
341+ break ;
342+ case ' ' :
343+ s -> ptr [w ++ ] = s -> ptr [r ];
340344 break ;
341345 default :
346+ if (last_char_after_nl ) {
347+ // Remove leading whitespace.
348+ bufsize_t remove_len = r - last_char_after_nl ;
349+
350+ if (remove_len ) {
351+ cmark_strbuf_remove (s , last_char_after_nl , remove_len );
352+ w -= remove_len ;
353+ r -= remove_len ;
354+ }
355+
356+ last_char_after_nl = 0 ;
357+ }
358+
342359 s -> ptr [w ++ ] = s -> ptr [r ];
343360 }
344361 if (s -> ptr [r ] != ' ' ) {
345362 contains_nonspace = true;
346363 }
347364 }
348365
366+ if (last_char_after_nl ) {
367+ // Remove leading whitespace. Only reach here if the closing backquote
368+ // delimiter is on its own line.
369+ bufsize_t remove_len = r - last_char_after_nl ;
370+
371+ if (remove_len ) {
372+ cmark_strbuf_remove (s , last_char_after_nl , remove_len );
373+ w -= remove_len ;
374+ r -= remove_len ;
375+ }
376+
377+ last_char_after_nl = 0 ;
378+ }
379+
349380 // begins and ends with space?
350381 if (contains_nonspace &&
351382 s -> ptr [0 ] == ' ' && s -> ptr [w - 1 ] == ' ' ) {
@@ -361,13 +392,15 @@ static void S_normalize_code(cmark_strbuf *s) {
361392// Parse backtick code section or raw backticks, return an inline.
362393// Assumes that the subject has a backtick at the current position.
363394static cmark_node * handle_backticks (subject * subj , int options ) {
395+ // Save the current source position in case of need to rewind.
396+ bufsize_t subjpos = subj -> pos ;
364397 cmark_chunk openticks = take_while (subj , isbacktick );
365398 bufsize_t startpos = subj -> pos ;
366399 bufsize_t endpos = scan_to_closing_backticks (subj , openticks .len );
367400
368401 if (endpos == 0 ) { // not found
369402 subj -> pos = startpos ; // rewind
370- return make_str (subj , subj -> pos , subj -> pos , openticks );
403+ return make_str (subj , subjpos , subjpos , openticks );
371404 } else {
372405 cmark_strbuf buf = CMARK_BUF_INIT (subj -> mem );
373406
@@ -797,6 +830,10 @@ static cmark_node *handle_backslash(cmark_parser *parser, subject *subj) {
797830 advance (subj );
798831 return make_str (subj , subj -> pos - 2 , subj -> pos - 1 , cmark_chunk_dup (& subj -> input , subj -> pos - 1 , 1 ));
799832 } else if (!is_eof (subj ) && skip_line_end (subj )) {
833+ // Adjust the subject source position state.
834+ ++ subj -> line ;
835+ subj -> column_offset = - subj -> pos ;
836+
800837 return make_linebreak (subj -> mem );
801838 } else {
802839 return make_str (subj , subj -> pos - 1 , subj -> pos - 1 , cmark_chunk_literal ("\\" ));
@@ -1163,7 +1200,8 @@ static cmark_node *handle_close_bracket(cmark_parser *parser, subject *subj) {
11631200 inl = make_simple (subj -> mem , is_image ? CMARK_NODE_IMAGE : CMARK_NODE_LINK );
11641201 inl -> as .link .url = url ;
11651202 inl -> as .link .title = title ;
1166- inl -> start_line = inl -> end_line = subj -> line ;
1203+ inl -> start_line = opener -> inl_text -> start_line ;
1204+ inl -> end_line = subj -> line ;
11671205 inl -> start_column = opener -> inl_text -> start_column ;
11681206 inl -> end_column = subj -> pos + subj -> column_offset + subj -> block_offset ;
11691207 cmark_node_insert_before (opener -> inl_text , inl );
@@ -1304,10 +1342,21 @@ static int parse_inline(cmark_parser *parser, subject *subj, cmark_node *parent,
13041342 cmark_chunk contents ;
13051343 unsigned char c ;
13061344 bufsize_t startpos , endpos ;
1345+ int saved_block_offset = subj -> block_offset ;
1346+
13071347 c = peek_char (subj );
13081348 if (c == 0 ) {
13091349 return 0 ;
13101350 }
1351+
1352+ // If NOT the subject's initial line...
1353+ if (subj -> column_offset != 0 ) {
1354+ // Reset the block offset. The line's leading trivia was not trimmed,
1355+ // so the source position will be computed appropriately without the
1356+ // block offset.
1357+ subj -> block_offset = 0 ;
1358+ }
1359+
13111360 switch (c ) {
13121361 case '\r' :
13131362 case '\n' :
@@ -1370,12 +1419,27 @@ static int parse_inline(cmark_parser *parser, subject *subj, cmark_node *parent,
13701419 cmark_chunk_rtrim (& contents );
13711420 }
13721421
1422+ // If not the initial line (in the subject) AND at the beginning of another line.
1423+ if (subj -> column_offset != 0 && startpos + subj -> column_offset == 0 ) {
1424+ // Trim leading whitespace.
1425+ bufsize_t before_trim = contents .len ;
1426+ cmark_chunk_ltrim (& contents );
1427+
1428+ if (contents .len == 0 )
1429+ break ; // The contents were only whitespaces.
1430+
1431+ // Update the start source position.
1432+ startpos += before_trim - contents .len ;
1433+ }
1434+
13731435 new_inl = make_str (subj , startpos , endpos - 1 , contents );
13741436 }
13751437 if (new_inl != NULL ) {
13761438 cmark_node_append_child (parent , new_inl );
13771439 }
13781440
1441+ subj -> block_offset = saved_block_offset ;
1442+
13791443 return 1 ;
13801444}
13811445
0 commit comments