Fossil SCM
Get Markdown italic and bold working in wiki.
Commit
079615cb7a412aa9f001216345686853a050be6419a83335a8f5e30ab2c7d967
Parent
4be82a52a558b11…
1 file changed
+49
-11
+49
-11
| --- src/wikiformat.c | ||
| +++ src/wikiformat.c | ||
| @@ -438,11 +438,11 @@ | ||
| 438 | 438 | #define TOKEN_NUM_LI 7 /* " # " */ |
| 439 | 439 | #define TOKEN_ENUM 8 /* " \(?\d+[.)]? " */ |
| 440 | 440 | #define TOKEN_INDENT 9 /* " " */ |
| 441 | 441 | #define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */ |
| 442 | 442 | #define TOKEN_AUTOLINK 11 /* <URL> */ |
| 443 | -#define TOKEN_MDSPAN 12 /* Markdown span characters: * ** _ or __ */ | |
| 443 | +#define TOKEN_MDFONT 12 /* Markdown font: *, **, _, __ */ | |
| 444 | 444 | #define TOKEN_MDCODE 13 /* Markdown code characters: ` or `` */ |
| 445 | 445 | #define TOKEN_BACKSLASH 14 /* A backslash-escape */ |
| 446 | 446 | #define TOKEN_TEXT 15 /* None of the above */ |
| 447 | 447 | |
| 448 | 448 | static const char *wiki_token_names[] = { "", |
| @@ -455,11 +455,11 @@ | ||
| 455 | 455 | "NUM_LI", |
| 456 | 456 | "ENUM", |
| 457 | 457 | "INDENT", |
| 458 | 458 | "RAW", |
| 459 | 459 | "AUTOLINK", |
| 460 | - "MDSPAN", | |
| 460 | + "MDFONT", | |
| 461 | 461 | "MDCODE", |
| 462 | 462 | "BACKSLASH", |
| 463 | 463 | "TEXT", |
| 464 | 464 | }; |
| 465 | 465 | |
| @@ -489,11 +489,10 @@ | ||
| 489 | 489 | int inAutoParagraph; /* True if within an automatic paragraph */ |
| 490 | 490 | int pikchrHtmlFlags; /* Flags for pikchr_to_html() */ |
| 491 | 491 | const char *zVerbatimId; /* The id= attribute of <verbatim> */ |
| 492 | 492 | int nStack; /* Number of elements on the stack */ |
| 493 | 493 | int nAlloc; /* Space allocated for aStack */ |
| 494 | - char inCode[2]; /* True if in `...` or ``...`` */ | |
| 495 | 494 | char inEmphS[2]; /* True if in *...* or **...** */ |
| 496 | 495 | char inEmphU[2]; /* True if in _..._ or __***__ */ |
| 497 | 496 | struct sStack { |
| 498 | 497 | short iCode; /* Markup code */ |
| 499 | 498 | short allowWiki; /* ALLOW_WIKI if wiki allowed before tag */ |
| @@ -781,11 +780,11 @@ | ||
| 781 | 780 | if( z[0]=='[' && (n = linkLength(z))>0 ){ |
| 782 | 781 | *pTokenType = TOKEN_LINK; |
| 783 | 782 | return n; |
| 784 | 783 | } |
| 785 | 784 | if( z[0]=='*' || z[0]=='_' ){ |
| 786 | - *pTokenType = TOKEN_MDSPAN; | |
| 785 | + *pTokenType = TOKEN_MDFONT; | |
| 787 | 786 | return 1 + (z[1]==z[0]); |
| 788 | 787 | } |
| 789 | 788 | if( z[0]=='`' ){ |
| 790 | 789 | *pTokenType = TOKEN_MDCODE; |
| 791 | 790 | return 1 + (z[1]==z[0]); |
| @@ -1533,10 +1532,35 @@ | ||
| 1533 | 1532 | if( tokenType==TOKEN_MDCODE && n>=sz ) return i; |
| 1534 | 1533 | i += n; |
| 1535 | 1534 | } |
| 1536 | 1535 | return 0; |
| 1537 | 1536 | } |
| 1537 | + | |
| 1538 | +/* | |
| 1539 | +** z[] begins with a TOKEN_MDFONT. Look ahead to see if there | |
| 1540 | +** is a corresponding closing pair. | |
| 1541 | +*/ | |
| 1542 | +static int has_mdfont_pair(Renderer *p, char *z, int sz){ | |
| 1543 | + int i = sz; | |
| 1544 | + int tokenType; | |
| 1545 | + int inCode = 0; | |
| 1546 | + while( z[i] ){ | |
| 1547 | + int n = nextWikiToken(&z[i], p, &tokenType); | |
| 1548 | + if( tokenType==TOKEN_PARAGRAPH ) break; | |
| 1549 | + if( tokenType==TOKEN_MDCODE ) inCode = !inCode; | |
| 1550 | + if( tokenType==TOKEN_MDFONT | |
| 1551 | + && n==sz | |
| 1552 | + && z[i]==z[0] | |
| 1553 | + && !inCode | |
| 1554 | + && (!fossil_isspace(z[i+n]) || !fossil_isspace(z[i-1])) | |
| 1555 | + ){ | |
| 1556 | + return 1; | |
| 1557 | + } | |
| 1558 | + i += n; | |
| 1559 | + } | |
| 1560 | + return 0; | |
| 1561 | +} | |
| 1538 | 1562 | |
| 1539 | 1563 | /* |
| 1540 | 1564 | ** Convert the wiki in z[] into html in the renderer p. The |
| 1541 | 1565 | ** renderer has already been initialized. |
| 1542 | 1566 | ** |
| @@ -1756,20 +1780,34 @@ | ||
| 1756 | 1780 | n += x + n; |
| 1757 | 1781 | } |
| 1758 | 1782 | } |
| 1759 | 1783 | break; |
| 1760 | 1784 | } |
| 1761 | - case TOKEN_MDSPAN: { | |
| 1762 | -#if 0 | |
| 1763 | - if( (z[n]==0 || isspace(z[n])) | |
| 1764 | - && (z==zOrig || isspace(z[-1])) ){ | |
| 1765 | - /* markdown emphasis markup surrounded by whitespace is ignored */ | |
| 1785 | + case TOKEN_MDFONT: { | |
| 1786 | + char *inEmph; | |
| 1787 | + if( (p->state & WIKI_MARKDOWN_FONT)==0 ){ | |
| 1788 | + blob_append(p->pOut, z, n); | |
| 1789 | + break; | |
| 1790 | + } | |
| 1791 | + if( fossil_isspace(z[n]) | |
| 1792 | + && (z==zOrig || fossil_isspace(z[-1])) | |
| 1793 | + ){ | |
| 1794 | + blob_append(p->pOut, z, n); | |
| 1795 | + break; | |
| 1796 | + } | |
| 1797 | + inEmph = z[0]=='*' ? p->inEmphS : p->inEmphU; | |
| 1798 | + if( inEmph[n] ){ | |
| 1799 | + blob_append(p->pOut, n==1 ? "</i>" : "</b>", 4); | |
| 1800 | + inEmph[n] = 0; | |
| 1801 | + break; | |
| 1802 | + } | |
| 1803 | + if( !has_mdfont_pair(p, z, n) ){ | |
| 1766 | 1804 | blob_append(p->pOut, z, n); |
| 1767 | 1805 | break; |
| 1768 | 1806 | } |
| 1769 | -#endif | |
| 1770 | - blob_append(p->pOut, z, n); | |
| 1807 | + blob_append(p->pOut, n==1 ? "<i>" : "<b>", 3); | |
| 1808 | + inEmph[n] = 1; | |
| 1771 | 1809 | break; |
| 1772 | 1810 | } |
| 1773 | 1811 | case TOKEN_TEXT: { |
| 1774 | 1812 | int i; |
| 1775 | 1813 | for(i=0; i<n && fossil_isspace(z[i]); i++){} |
| 1776 | 1814 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -438,11 +438,11 @@ | |
| 438 | #define TOKEN_NUM_LI 7 /* " # " */ |
| 439 | #define TOKEN_ENUM 8 /* " \(?\d+[.)]? " */ |
| 440 | #define TOKEN_INDENT 9 /* " " */ |
| 441 | #define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */ |
| 442 | #define TOKEN_AUTOLINK 11 /* <URL> */ |
| 443 | #define TOKEN_MDSPAN 12 /* Markdown span characters: * ** _ or __ */ |
| 444 | #define TOKEN_MDCODE 13 /* Markdown code characters: ` or `` */ |
| 445 | #define TOKEN_BACKSLASH 14 /* A backslash-escape */ |
| 446 | #define TOKEN_TEXT 15 /* None of the above */ |
| 447 | |
| 448 | static const char *wiki_token_names[] = { "", |
| @@ -455,11 +455,11 @@ | |
| 455 | "NUM_LI", |
| 456 | "ENUM", |
| 457 | "INDENT", |
| 458 | "RAW", |
| 459 | "AUTOLINK", |
| 460 | "MDSPAN", |
| 461 | "MDCODE", |
| 462 | "BACKSLASH", |
| 463 | "TEXT", |
| 464 | }; |
| 465 | |
| @@ -489,11 +489,10 @@ | |
| 489 | int inAutoParagraph; /* True if within an automatic paragraph */ |
| 490 | int pikchrHtmlFlags; /* Flags for pikchr_to_html() */ |
| 491 | const char *zVerbatimId; /* The id= attribute of <verbatim> */ |
| 492 | int nStack; /* Number of elements on the stack */ |
| 493 | int nAlloc; /* Space allocated for aStack */ |
| 494 | char inCode[2]; /* True if in `...` or ``...`` */ |
| 495 | char inEmphS[2]; /* True if in *...* or **...** */ |
| 496 | char inEmphU[2]; /* True if in _..._ or __***__ */ |
| 497 | struct sStack { |
| 498 | short iCode; /* Markup code */ |
| 499 | short allowWiki; /* ALLOW_WIKI if wiki allowed before tag */ |
| @@ -781,11 +780,11 @@ | |
| 781 | if( z[0]=='[' && (n = linkLength(z))>0 ){ |
| 782 | *pTokenType = TOKEN_LINK; |
| 783 | return n; |
| 784 | } |
| 785 | if( z[0]=='*' || z[0]=='_' ){ |
| 786 | *pTokenType = TOKEN_MDSPAN; |
| 787 | return 1 + (z[1]==z[0]); |
| 788 | } |
| 789 | if( z[0]=='`' ){ |
| 790 | *pTokenType = TOKEN_MDCODE; |
| 791 | return 1 + (z[1]==z[0]); |
| @@ -1533,10 +1532,35 @@ | |
| 1533 | if( tokenType==TOKEN_MDCODE && n>=sz ) return i; |
| 1534 | i += n; |
| 1535 | } |
| 1536 | return 0; |
| 1537 | } |
| 1538 | |
| 1539 | /* |
| 1540 | ** Convert the wiki in z[] into html in the renderer p. The |
| 1541 | ** renderer has already been initialized. |
| 1542 | ** |
| @@ -1756,20 +1780,34 @@ | |
| 1756 | n += x + n; |
| 1757 | } |
| 1758 | } |
| 1759 | break; |
| 1760 | } |
| 1761 | case TOKEN_MDSPAN: { |
| 1762 | #if 0 |
| 1763 | if( (z[n]==0 || isspace(z[n])) |
| 1764 | && (z==zOrig || isspace(z[-1])) ){ |
| 1765 | /* markdown emphasis markup surrounded by whitespace is ignored */ |
| 1766 | blob_append(p->pOut, z, n); |
| 1767 | break; |
| 1768 | } |
| 1769 | #endif |
| 1770 | blob_append(p->pOut, z, n); |
| 1771 | break; |
| 1772 | } |
| 1773 | case TOKEN_TEXT: { |
| 1774 | int i; |
| 1775 | for(i=0; i<n && fossil_isspace(z[i]); i++){} |
| 1776 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -438,11 +438,11 @@ | |
| 438 | #define TOKEN_NUM_LI 7 /* " # " */ |
| 439 | #define TOKEN_ENUM 8 /* " \(?\d+[.)]? " */ |
| 440 | #define TOKEN_INDENT 9 /* " " */ |
| 441 | #define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */ |
| 442 | #define TOKEN_AUTOLINK 11 /* <URL> */ |
| 443 | #define TOKEN_MDFONT 12 /* Markdown font: *, **, _, __ */ |
| 444 | #define TOKEN_MDCODE 13 /* Markdown code characters: ` or `` */ |
| 445 | #define TOKEN_BACKSLASH 14 /* A backslash-escape */ |
| 446 | #define TOKEN_TEXT 15 /* None of the above */ |
| 447 | |
| 448 | static const char *wiki_token_names[] = { "", |
| @@ -455,11 +455,11 @@ | |
| 455 | "NUM_LI", |
| 456 | "ENUM", |
| 457 | "INDENT", |
| 458 | "RAW", |
| 459 | "AUTOLINK", |
| 460 | "MDFONT", |
| 461 | "MDCODE", |
| 462 | "BACKSLASH", |
| 463 | "TEXT", |
| 464 | }; |
| 465 | |
| @@ -489,11 +489,10 @@ | |
| 489 | int inAutoParagraph; /* True if within an automatic paragraph */ |
| 490 | int pikchrHtmlFlags; /* Flags for pikchr_to_html() */ |
| 491 | const char *zVerbatimId; /* The id= attribute of <verbatim> */ |
| 492 | int nStack; /* Number of elements on the stack */ |
| 493 | int nAlloc; /* Space allocated for aStack */ |
| 494 | char inEmphS[2]; /* True if in *...* or **...** */ |
| 495 | char inEmphU[2]; /* True if in _..._ or __***__ */ |
| 496 | struct sStack { |
| 497 | short iCode; /* Markup code */ |
| 498 | short allowWiki; /* ALLOW_WIKI if wiki allowed before tag */ |
| @@ -781,11 +780,11 @@ | |
| 780 | if( z[0]=='[' && (n = linkLength(z))>0 ){ |
| 781 | *pTokenType = TOKEN_LINK; |
| 782 | return n; |
| 783 | } |
| 784 | if( z[0]=='*' || z[0]=='_' ){ |
| 785 | *pTokenType = TOKEN_MDFONT; |
| 786 | return 1 + (z[1]==z[0]); |
| 787 | } |
| 788 | if( z[0]=='`' ){ |
| 789 | *pTokenType = TOKEN_MDCODE; |
| 790 | return 1 + (z[1]==z[0]); |
| @@ -1533,10 +1532,35 @@ | |
| 1532 | if( tokenType==TOKEN_MDCODE && n>=sz ) return i; |
| 1533 | i += n; |
| 1534 | } |
| 1535 | return 0; |
| 1536 | } |
| 1537 | |
| 1538 | /* |
| 1539 | ** z[] begins with a TOKEN_MDFONT. Look ahead to see if there |
| 1540 | ** is a corresponding closing pair. |
| 1541 | */ |
| 1542 | static int has_mdfont_pair(Renderer *p, char *z, int sz){ |
| 1543 | int i = sz; |
| 1544 | int tokenType; |
| 1545 | int inCode = 0; |
| 1546 | while( z[i] ){ |
| 1547 | int n = nextWikiToken(&z[i], p, &tokenType); |
| 1548 | if( tokenType==TOKEN_PARAGRAPH ) break; |
| 1549 | if( tokenType==TOKEN_MDCODE ) inCode = !inCode; |
| 1550 | if( tokenType==TOKEN_MDFONT |
| 1551 | && n==sz |
| 1552 | && z[i]==z[0] |
| 1553 | && !inCode |
| 1554 | && (!fossil_isspace(z[i+n]) || !fossil_isspace(z[i-1])) |
| 1555 | ){ |
| 1556 | return 1; |
| 1557 | } |
| 1558 | i += n; |
| 1559 | } |
| 1560 | return 0; |
| 1561 | } |
| 1562 | |
| 1563 | /* |
| 1564 | ** Convert the wiki in z[] into html in the renderer p. The |
| 1565 | ** renderer has already been initialized. |
| 1566 | ** |
| @@ -1756,20 +1780,34 @@ | |
| 1780 | n += x + n; |
| 1781 | } |
| 1782 | } |
| 1783 | break; |
| 1784 | } |
| 1785 | case TOKEN_MDFONT: { |
| 1786 | char *inEmph; |
| 1787 | if( (p->state & WIKI_MARKDOWN_FONT)==0 ){ |
| 1788 | blob_append(p->pOut, z, n); |
| 1789 | break; |
| 1790 | } |
| 1791 | if( fossil_isspace(z[n]) |
| 1792 | && (z==zOrig || fossil_isspace(z[-1])) |
| 1793 | ){ |
| 1794 | blob_append(p->pOut, z, n); |
| 1795 | break; |
| 1796 | } |
| 1797 | inEmph = z[0]=='*' ? p->inEmphS : p->inEmphU; |
| 1798 | if( inEmph[n] ){ |
| 1799 | blob_append(p->pOut, n==1 ? "</i>" : "</b>", 4); |
| 1800 | inEmph[n] = 0; |
| 1801 | break; |
| 1802 | } |
| 1803 | if( !has_mdfont_pair(p, z, n) ){ |
| 1804 | blob_append(p->pOut, z, n); |
| 1805 | break; |
| 1806 | } |
| 1807 | blob_append(p->pOut, n==1 ? "<i>" : "<b>", 3); |
| 1808 | inEmph[n] = 1; |
| 1809 | break; |
| 1810 | } |
| 1811 | case TOKEN_TEXT: { |
| 1812 | int i; |
| 1813 | for(i=0; i<n && fossil_isspace(z[i]); i++){} |
| 1814 |