Fossil SCM
Implement `...` verbatim sections for the WIKI_MARKDOWN_SPAN option.
Commit
c903885574f6598e4e0433926a319de2dc79769be21cd9b81a87bbfbfebfeed1
Parent
6f9e29924471420…
1 file changed
+59
-5
+59
-5
| --- src/wikiformat.c | ||
| +++ src/wikiformat.c | ||
| @@ -436,13 +436,14 @@ | ||
| 436 | 436 | #define TOKEN_NUM_LI 7 /* " # " */ |
| 437 | 437 | #define TOKEN_ENUM 8 /* " \(?\d+[.)]? " */ |
| 438 | 438 | #define TOKEN_INDENT 9 /* " " */ |
| 439 | 439 | #define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */ |
| 440 | 440 | #define TOKEN_AUTOLINK 11 /* <URL> */ |
| 441 | -#define TOKEN_MDSPAN 12 /* Markdown span characters: * _ ` */ | |
| 442 | -#define TOKEN_BACKSLASH 13 /* A backslash-escape */ | |
| 443 | -#define TOKEN_TEXT 14 /* None of the above */ | |
| 441 | +#define TOKEN_MDSPAN 12 /* Markdown span characters: * ** _ or __ */ | |
| 442 | +#define TOKEN_MDCODE 13 /* Markdown code characters: ` or `` */ | |
| 443 | +#define TOKEN_BACKSLASH 14 /* A backslash-escape */ | |
| 444 | +#define TOKEN_TEXT 15 /* None of the above */ | |
| 444 | 445 | |
| 445 | 446 | static const char *wiki_token_names[] = { "", |
| 446 | 447 | "MARKUP", |
| 447 | 448 | "CHARACTER", |
| 448 | 449 | "LINK", |
| @@ -453,10 +454,11 @@ | ||
| 453 | 454 | "ENUM", |
| 454 | 455 | "INDENT", |
| 455 | 456 | "RAW", |
| 456 | 457 | "AUTOLINK", |
| 457 | 458 | "MDSPAN", |
| 459 | + "MDCODE", | |
| 458 | 460 | "BACKSLASH", |
| 459 | 461 | "TEXT", |
| 460 | 462 | }; |
| 461 | 463 | |
| 462 | 464 | /* |
| @@ -485,10 +487,13 @@ | ||
| 485 | 487 | int inAutoParagraph; /* True if within an automatic paragraph */ |
| 486 | 488 | int pikchrHtmlFlags; /* Flags for pikchr_to_html() */ |
| 487 | 489 | const char *zVerbatimId; /* The id= attribute of <verbatim> */ |
| 488 | 490 | int nStack; /* Number of elements on the stack */ |
| 489 | 491 | int nAlloc; /* Space allocated for aStack */ |
| 492 | + char inCode[2]; /* True if in `...` or ``...`` */ | |
| 493 | + char inEmphS[2]; /* True if in *...* or **...** */ | |
| 494 | + char inEmphU[2]; /* True if in _..._ or __***__ */ | |
| 490 | 495 | struct sStack { |
| 491 | 496 | short iCode; /* Markup code */ |
| 492 | 497 | short allowWiki; /* ALLOW_WIKI if wiki allowed before tag */ |
| 493 | 498 | const char *zId; /* ID attribute or NULL */ |
| 494 | 499 | } *aStack; |
| @@ -773,14 +778,18 @@ | ||
| 773 | 778 | } |
| 774 | 779 | if( z[0]=='[' && (n = linkLength(z))>0 ){ |
| 775 | 780 | *pTokenType = TOKEN_LINK; |
| 776 | 781 | return n; |
| 777 | 782 | } |
| 778 | - if( z[0]=='*' || z[0]=='_' || z[0]=='`' ){ | |
| 783 | + if( z[0]=='*' || z[0]=='_' ){ | |
| 779 | 784 | *pTokenType = TOKEN_MDSPAN; |
| 780 | 785 | return 1 + (z[1]==z[0]); |
| 781 | 786 | } |
| 787 | + if( z[0]=='`' ){ | |
| 788 | + *pTokenType = TOKEN_MDCODE; | |
| 789 | + return 1 + (z[1]==z[0]); | |
| 790 | + } | |
| 782 | 791 | if( z[0]=='\\' ){ |
| 783 | 792 | if( z[1]==0 || fossil_isspace(z[1]) || (z[1]&0x80)!=0 ){ |
| 784 | 793 | *pTokenType = TOKEN_TEXT; |
| 785 | 794 | return 1; |
| 786 | 795 | } |
| @@ -1504,10 +1513,28 @@ | ||
| 1504 | 1513 | */ |
| 1505 | 1514 | static int stackTopType(Renderer *p){ |
| 1506 | 1515 | if( p->nStack<=0 ) return 0; |
| 1507 | 1516 | return aMarkup[p->aStack[p->nStack-1].iCode].iType; |
| 1508 | 1517 | } |
| 1518 | + | |
| 1519 | +/* | |
| 1520 | +** z[] is the first character past the start of a `...` literal | |
| 1521 | +** section of a markdown span. Look ahead in z[] for the ` terminator | |
| 1522 | +** mark. Return the offset into z[] of the terminator. | |
| 1523 | +** Or return zero if there is no terminator. | |
| 1524 | +*/ | |
| 1525 | +static int verbatimLength(Renderer *p, char *z, int sz){ | |
| 1526 | + int i = 0, n; | |
| 1527 | + int tokenType; | |
| 1528 | + while( z[i] ){ | |
| 1529 | + n = nextWikiToken(&z[i], p, &tokenType); | |
| 1530 | + if( tokenType==TOKEN_PARAGRAPH ) break; | |
| 1531 | + if( tokenType==TOKEN_MDCODE && n>=sz ) return i; | |
| 1532 | + i += n; | |
| 1533 | + } | |
| 1534 | + return 0; | |
| 1535 | +} | |
| 1509 | 1536 | |
| 1510 | 1537 | /* |
| 1511 | 1538 | ** Convert the wiki in z[] into html in the renderer p. The |
| 1512 | 1539 | ** renderer has already been initialized. |
| 1513 | 1540 | ** |
| @@ -1709,11 +1736,38 @@ | ||
| 1709 | 1736 | }else{ |
| 1710 | 1737 | blob_append_char(p->pOut, z[1]); |
| 1711 | 1738 | } |
| 1712 | 1739 | break; |
| 1713 | 1740 | } |
| 1714 | - case TOKEN_MDSPAN: | |
| 1741 | + case TOKEN_MDCODE: { | |
| 1742 | + if( (p->state & WIKI_MARKDOWN_SPAN)==0 ){ | |
| 1743 | + blob_append(p->pOut, z, n); | |
| 1744 | + }else{ | |
| 1745 | + int x = verbatimLength(p, z+n, n); | |
| 1746 | + if( x==0 ){ | |
| 1747 | + blob_append(p->pOut, z, n); | |
| 1748 | + }else{ | |
| 1749 | + z[x+n] = 0; | |
| 1750 | + blob_appendf(p->pOut, "<code>%h</code>", z+n); | |
| 1751 | + z[x+n] = '`'; | |
| 1752 | + n += x + n; | |
| 1753 | + } | |
| 1754 | + } | |
| 1755 | + break; | |
| 1756 | + } | |
| 1757 | + case TOKEN_MDSPAN: { | |
| 1758 | +#if 0 | |
| 1759 | + if( (z[n]==0 || isspace(z[n])) | |
| 1760 | + && (z==zOrig || isspace(z[-1])) ){ | |
| 1761 | + /* markdown emphasis markup surrounded by whitespace is ignored */ | |
| 1762 | + blob_append(p->pOut, z, n); | |
| 1763 | + break; | |
| 1764 | + } | |
| 1765 | +#endif | |
| 1766 | + blob_append(p->pOut, z, n); | |
| 1767 | + break; | |
| 1768 | + } | |
| 1715 | 1769 | case TOKEN_TEXT: { |
| 1716 | 1770 | int i; |
| 1717 | 1771 | for(i=0; i<n && fossil_isspace(z[i]); i++){} |
| 1718 | 1772 | if( i<n ) startAutoParagraph(p); |
| 1719 | 1773 | blob_append(p->pOut, z, n); |
| 1720 | 1774 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -436,13 +436,14 @@ | |
| 436 | #define TOKEN_NUM_LI 7 /* " # " */ |
| 437 | #define TOKEN_ENUM 8 /* " \(?\d+[.)]? " */ |
| 438 | #define TOKEN_INDENT 9 /* " " */ |
| 439 | #define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */ |
| 440 | #define TOKEN_AUTOLINK 11 /* <URL> */ |
| 441 | #define TOKEN_MDSPAN 12 /* Markdown span characters: * _ ` */ |
| 442 | #define TOKEN_BACKSLASH 13 /* A backslash-escape */ |
| 443 | #define TOKEN_TEXT 14 /* None of the above */ |
| 444 | |
| 445 | static const char *wiki_token_names[] = { "", |
| 446 | "MARKUP", |
| 447 | "CHARACTER", |
| 448 | "LINK", |
| @@ -453,10 +454,11 @@ | |
| 453 | "ENUM", |
| 454 | "INDENT", |
| 455 | "RAW", |
| 456 | "AUTOLINK", |
| 457 | "MDSPAN", |
| 458 | "BACKSLASH", |
| 459 | "TEXT", |
| 460 | }; |
| 461 | |
| 462 | /* |
| @@ -485,10 +487,13 @@ | |
| 485 | int inAutoParagraph; /* True if within an automatic paragraph */ |
| 486 | int pikchrHtmlFlags; /* Flags for pikchr_to_html() */ |
| 487 | const char *zVerbatimId; /* The id= attribute of <verbatim> */ |
| 488 | int nStack; /* Number of elements on the stack */ |
| 489 | int nAlloc; /* Space allocated for aStack */ |
| 490 | struct sStack { |
| 491 | short iCode; /* Markup code */ |
| 492 | short allowWiki; /* ALLOW_WIKI if wiki allowed before tag */ |
| 493 | const char *zId; /* ID attribute or NULL */ |
| 494 | } *aStack; |
| @@ -773,14 +778,18 @@ | |
| 773 | } |
| 774 | if( z[0]=='[' && (n = linkLength(z))>0 ){ |
| 775 | *pTokenType = TOKEN_LINK; |
| 776 | return n; |
| 777 | } |
| 778 | if( z[0]=='*' || z[0]=='_' || z[0]=='`' ){ |
| 779 | *pTokenType = TOKEN_MDSPAN; |
| 780 | return 1 + (z[1]==z[0]); |
| 781 | } |
| 782 | if( z[0]=='\\' ){ |
| 783 | if( z[1]==0 || fossil_isspace(z[1]) || (z[1]&0x80)!=0 ){ |
| 784 | *pTokenType = TOKEN_TEXT; |
| 785 | return 1; |
| 786 | } |
| @@ -1504,10 +1513,28 @@ | |
| 1504 | */ |
| 1505 | static int stackTopType(Renderer *p){ |
| 1506 | if( p->nStack<=0 ) return 0; |
| 1507 | return aMarkup[p->aStack[p->nStack-1].iCode].iType; |
| 1508 | } |
| 1509 | |
| 1510 | /* |
| 1511 | ** Convert the wiki in z[] into html in the renderer p. The |
| 1512 | ** renderer has already been initialized. |
| 1513 | ** |
| @@ -1709,11 +1736,38 @@ | |
| 1709 | }else{ |
| 1710 | blob_append_char(p->pOut, z[1]); |
| 1711 | } |
| 1712 | break; |
| 1713 | } |
| 1714 | case TOKEN_MDSPAN: |
| 1715 | case TOKEN_TEXT: { |
| 1716 | int i; |
| 1717 | for(i=0; i<n && fossil_isspace(z[i]); i++){} |
| 1718 | if( i<n ) startAutoParagraph(p); |
| 1719 | blob_append(p->pOut, z, n); |
| 1720 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -436,13 +436,14 @@ | |
| 436 | #define TOKEN_NUM_LI 7 /* " # " */ |
| 437 | #define TOKEN_ENUM 8 /* " \(?\d+[.)]? " */ |
| 438 | #define TOKEN_INDENT 9 /* " " */ |
| 439 | #define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */ |
| 440 | #define TOKEN_AUTOLINK 11 /* <URL> */ |
| 441 | #define TOKEN_MDSPAN 12 /* Markdown span characters: * ** _ or __ */ |
| 442 | #define TOKEN_MDCODE 13 /* Markdown code characters: ` or `` */ |
| 443 | #define TOKEN_BACKSLASH 14 /* A backslash-escape */ |
| 444 | #define TOKEN_TEXT 15 /* None of the above */ |
| 445 | |
| 446 | static const char *wiki_token_names[] = { "", |
| 447 | "MARKUP", |
| 448 | "CHARACTER", |
| 449 | "LINK", |
| @@ -453,10 +454,11 @@ | |
| 454 | "ENUM", |
| 455 | "INDENT", |
| 456 | "RAW", |
| 457 | "AUTOLINK", |
| 458 | "MDSPAN", |
| 459 | "MDCODE", |
| 460 | "BACKSLASH", |
| 461 | "TEXT", |
| 462 | }; |
| 463 | |
| 464 | /* |
| @@ -485,10 +487,13 @@ | |
| 487 | int inAutoParagraph; /* True if within an automatic paragraph */ |
| 488 | int pikchrHtmlFlags; /* Flags for pikchr_to_html() */ |
| 489 | const char *zVerbatimId; /* The id= attribute of <verbatim> */ |
| 490 | int nStack; /* Number of elements on the stack */ |
| 491 | int nAlloc; /* Space allocated for aStack */ |
| 492 | char inCode[2]; /* True if in `...` or ``...`` */ |
| 493 | char inEmphS[2]; /* True if in *...* or **...** */ |
| 494 | char inEmphU[2]; /* True if in _..._ or __***__ */ |
| 495 | struct sStack { |
| 496 | short iCode; /* Markup code */ |
| 497 | short allowWiki; /* ALLOW_WIKI if wiki allowed before tag */ |
| 498 | const char *zId; /* ID attribute or NULL */ |
| 499 | } *aStack; |
| @@ -773,14 +778,18 @@ | |
| 778 | } |
| 779 | if( z[0]=='[' && (n = linkLength(z))>0 ){ |
| 780 | *pTokenType = TOKEN_LINK; |
| 781 | return n; |
| 782 | } |
| 783 | if( z[0]=='*' || z[0]=='_' ){ |
| 784 | *pTokenType = TOKEN_MDSPAN; |
| 785 | return 1 + (z[1]==z[0]); |
| 786 | } |
| 787 | if( z[0]=='`' ){ |
| 788 | *pTokenType = TOKEN_MDCODE; |
| 789 | return 1 + (z[1]==z[0]); |
| 790 | } |
| 791 | if( z[0]=='\\' ){ |
| 792 | if( z[1]==0 || fossil_isspace(z[1]) || (z[1]&0x80)!=0 ){ |
| 793 | *pTokenType = TOKEN_TEXT; |
| 794 | return 1; |
| 795 | } |
| @@ -1504,10 +1513,28 @@ | |
| 1513 | */ |
| 1514 | static int stackTopType(Renderer *p){ |
| 1515 | if( p->nStack<=0 ) return 0; |
| 1516 | return aMarkup[p->aStack[p->nStack-1].iCode].iType; |
| 1517 | } |
| 1518 | |
| 1519 | /* |
| 1520 | ** z[] is the first character past the start of a `...` literal |
| 1521 | ** section of a markdown span. Look ahead in z[] for the ` terminator |
| 1522 | ** mark. Return the offset into z[] of the terminator. |
| 1523 | ** Or return zero if there is no terminator. |
| 1524 | */ |
| 1525 | static int verbatimLength(Renderer *p, char *z, int sz){ |
| 1526 | int i = 0, n; |
| 1527 | int tokenType; |
| 1528 | while( z[i] ){ |
| 1529 | n = nextWikiToken(&z[i], p, &tokenType); |
| 1530 | if( tokenType==TOKEN_PARAGRAPH ) break; |
| 1531 | if( tokenType==TOKEN_MDCODE && n>=sz ) return i; |
| 1532 | i += n; |
| 1533 | } |
| 1534 | return 0; |
| 1535 | } |
| 1536 | |
| 1537 | /* |
| 1538 | ** Convert the wiki in z[] into html in the renderer p. The |
| 1539 | ** renderer has already been initialized. |
| 1540 | ** |
| @@ -1709,11 +1736,38 @@ | |
| 1736 | }else{ |
| 1737 | blob_append_char(p->pOut, z[1]); |
| 1738 | } |
| 1739 | break; |
| 1740 | } |
| 1741 | case TOKEN_MDCODE: { |
| 1742 | if( (p->state & WIKI_MARKDOWN_SPAN)==0 ){ |
| 1743 | blob_append(p->pOut, z, n); |
| 1744 | }else{ |
| 1745 | int x = verbatimLength(p, z+n, n); |
| 1746 | if( x==0 ){ |
| 1747 | blob_append(p->pOut, z, n); |
| 1748 | }else{ |
| 1749 | z[x+n] = 0; |
| 1750 | blob_appendf(p->pOut, "<code>%h</code>", z+n); |
| 1751 | z[x+n] = '`'; |
| 1752 | n += x + n; |
| 1753 | } |
| 1754 | } |
| 1755 | break; |
| 1756 | } |
| 1757 | case TOKEN_MDSPAN: { |
| 1758 | #if 0 |
| 1759 | if( (z[n]==0 || isspace(z[n])) |
| 1760 | && (z==zOrig || isspace(z[-1])) ){ |
| 1761 | /* markdown emphasis markup surrounded by whitespace is ignored */ |
| 1762 | blob_append(p->pOut, z, n); |
| 1763 | break; |
| 1764 | } |
| 1765 | #endif |
| 1766 | blob_append(p->pOut, z, n); |
| 1767 | break; |
| 1768 | } |
| 1769 | case TOKEN_TEXT: { |
| 1770 | int i; |
| 1771 | for(i=0; i<n && fossil_isspace(z[i]); i++){} |
| 1772 | if( i<n ) startAutoParagraph(p); |
| 1773 | blob_append(p->pOut, z, n); |
| 1774 |