@@ -357,6 +357,41 @@ static bufsize_t scan_to_closing_backticks(subject *subj,
357357 return 0 ;
358358}
359359
360+
361+ // Try to process a dollar inline formula span that began with a
362+ // dollar (already parsed). Return 0 if you don't find matching closing
363+ // dollar, otherwise return the position in the subject
364+ // after the closing dollar.
365+ static bufsize_t scan_to_closing_dollar (subject * subj ) {
366+ bufsize_t startpos = subj -> pos ;
367+
368+ // read non dollar
369+ unsigned char c ;
370+ size_t slash_cnt = 0 ;
371+ // Directly skip the escaped dollar.
372+ while ((c = peek_char (subj )) && (c != '$' || slash_cnt % 2 == 1 )) {
373+ if (c == '\\' ) {
374+ ++ slash_cnt ;
375+ } else {
376+ slash_cnt = 0 ;
377+ }
378+ if (c == '\r' || c == '\n' ) {
379+ // Line break is not allowed.
380+ break ;
381+ }
382+ advance (subj );
383+ }
384+ if (!is_eof (subj ) && c == '$' ) {
385+ advance (subj );
386+ return (subj -> pos );
387+ } else {
388+ // Rewind it.
389+ subj -> pos = startpos ;
390+ return 0 ;
391+ }
392+ }
393+
394+
360395// Destructively modify string, converting newlines to
361396// spaces, then removing a single leading + trailing space,
362397// unless the code span consists entirely of space characters.
@@ -412,8 +447,9 @@ static cmark_node *handle_backticks(subject *subj, int options) {
412447 endpos - startpos - openticks .len );
413448 S_normalize_code (& buf );
414449
415- cmark_node * node = make_literal (subj , CMARK_NODE_CODE , startpos ,
416- endpos - openticks .len - 1 );
450+ // VNoteX: let's fix it to include the ticks.
451+ cmark_node * node = make_literal (subj , CMARK_NODE_CODE , startpos - openticks .len ,
452+ endpos - 1 );
417453 node -> len = buf .size ;
418454 node -> data = cmark_strbuf_detach (& buf );
419455 adjust_subj_node_newlines (subj , node , endpos - startpos , openticks .len , options );
@@ -422,6 +458,70 @@ static cmark_node *handle_backticks(subject *subj, int options) {
422458}
423459
424460
461+ // Parse dollar inline formula section or raw dollar, return an inline.
462+ // Assumes that the subject has a dollar at the current position.
463+ static cmark_node * handle_dollar (subject * subj ) {
464+ bufsize_t initpos = subj -> pos ;
465+ // Skip the open dollar.
466+ advance (subj );
467+ bufsize_t startpos = subj -> pos ;
468+
469+ // Pre check.
470+ if (subj -> pos > 1 ) {
471+ unsigned char before_char = peek_at (subj , subj -> pos - 2 );
472+ if (before_char == '$' ||
473+ (before_char >= '0' && before_char <= '9' ) ||
474+ before_char == '\\' ) {
475+ // Not a legal open dollar.
476+ return make_str (subj , initpos , initpos , cmark_chunk_literal ("$" ));
477+ }
478+ }
479+
480+ bufsize_t endpos = scan_to_closing_dollar (subj );
481+ if (endpos == 0 ) {
482+ subj -> pos = startpos ;
483+ return make_str (subj , initpos , initpos , cmark_chunk_literal ("$" ));
484+ }
485+
486+ // Post check.
487+ {
488+ // $$ is invalid.
489+ if (endpos - startpos == 1 ) {
490+ return make_str (subj , initpos , startpos , cmark_chunk_literal ("$$" ));
491+ }
492+
493+ // No space before the closing dollar.
494+ unsigned char before_char = peek_at (subj , endpos - 2 );
495+ if (endpos - startpos == 1 || before_char == ' ' || before_char == '\t' ) {
496+ // Not a legal closing dollar.
497+ subj -> pos = startpos ;
498+ return make_str (subj , initpos , initpos , cmark_chunk_literal ("$" ));
499+ }
500+
501+ // No digit after the closing dollar.
502+ if (endpos < subj -> input .len ) {
503+ unsigned char after_char = peek_at (subj , endpos );
504+ if (after_char >= '0' && after_char <= '9' ) {
505+ // Not a legal closing dollar.
506+ subj -> pos = startpos ;
507+ return make_str (subj , initpos , initpos , cmark_chunk_literal ("$" ));
508+ }
509+ }
510+ }
511+
512+ cmark_strbuf buf = CMARK_BUF_INIT (subj -> mem );
513+
514+ cmark_strbuf_set (& buf , subj -> input .data + startpos ,
515+ endpos - startpos - 1 );
516+ cmark_strbuf_unescape_char (& buf , '$' );
517+
518+ cmark_node * node = make_literal (subj , CMARK_NODE_FORMULA_INLINE , startpos , endpos - 2 );
519+ node -> len = buf .size ;
520+ node -> data = cmark_strbuf_detach (& buf );
521+ return node ;
522+ }
523+
524+
425525// Scan ***, **, or * and return number scanned, or 0.
426526// Advances position.
427527static int scan_delims (subject * subj , unsigned char c , bool * can_open ,
@@ -1330,10 +1430,10 @@ static cmark_node *handle_newline(subject *subj) {
13301430
13311431static bufsize_t subject_find_special_char (subject * subj , int options ) {
13321432 // "\r\n\\`&_*[]<!"
1333- // Add '~', '='.
1433+ // Add '~', '=', '$' .
13341434 static const int8_t SPECIAL_CHARS [256 ] = {
13351435 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
1336- 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 ,
1436+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 ,
13371437 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
13381438 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 0 , 1 ,
13391439 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
@@ -1391,6 +1491,9 @@ static int parse_inline(subject *subj, cmark_node *parent, int options) {
13911491 case '`' :
13921492 new_inl = handle_backticks (subj , options );
13931493 break ;
1494+ case '$' :
1495+ new_inl = handle_dollar (subj );
1496+ break ;
13941497 case '\\' :
13951498 new_inl = handle_backslash (subj );
13961499 break ;
0 commit comments