Fossil SCM

Get Markdown italic and bold working in wiki.

drh 2025-03-05 21:19 comment-markdown-links
Commit 079615cb7a412aa9f001216345686853a050be6419a83335a8f5e30ab2c7d967
1 file changed +49 -11
+49 -11
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -438,11 +438,11 @@
438438
#define TOKEN_NUM_LI 7 /* " # " */
439439
#define TOKEN_ENUM 8 /* " \(?\d+[.)]? " */
440440
#define TOKEN_INDENT 9 /* " " */
441441
#define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */
442442
#define TOKEN_AUTOLINK 11 /* <URL> */
443
-#define TOKEN_MDSPAN 12 /* Markdown span characters: * ** _ or __ */
443
+#define TOKEN_MDFONT 12 /* Markdown font: *, **, _, __ */
444444
#define TOKEN_MDCODE 13 /* Markdown code characters: ` or `` */
445445
#define TOKEN_BACKSLASH 14 /* A backslash-escape */
446446
#define TOKEN_TEXT 15 /* None of the above */
447447
448448
static const char *wiki_token_names[] = { "",
@@ -455,11 +455,11 @@
455455
"NUM_LI",
456456
"ENUM",
457457
"INDENT",
458458
"RAW",
459459
"AUTOLINK",
460
- "MDSPAN",
460
+ "MDFONT",
461461
"MDCODE",
462462
"BACKSLASH",
463463
"TEXT",
464464
};
465465
@@ -489,11 +489,10 @@
489489
int inAutoParagraph; /* True if within an automatic paragraph */
490490
int pikchrHtmlFlags; /* Flags for pikchr_to_html() */
491491
const char *zVerbatimId; /* The id= attribute of <verbatim> */
492492
int nStack; /* Number of elements on the stack */
493493
int nAlloc; /* Space allocated for aStack */
494
- char inCode[2]; /* True if in `...` or ``...`` */
495494
char inEmphS[2]; /* True if in *...* or **...** */
496495
char inEmphU[2]; /* True if in _..._ or __***__ */
497496
struct sStack {
498497
short iCode; /* Markup code */
499498
short allowWiki; /* ALLOW_WIKI if wiki allowed before tag */
@@ -781,11 +780,11 @@
781780
if( z[0]=='[' && (n = linkLength(z))>0 ){
782781
*pTokenType = TOKEN_LINK;
783782
return n;
784783
}
785784
if( z[0]=='*' || z[0]=='_' ){
786
- *pTokenType = TOKEN_MDSPAN;
785
+ *pTokenType = TOKEN_MDFONT;
787786
return 1 + (z[1]==z[0]);
788787
}
789788
if( z[0]=='`' ){
790789
*pTokenType = TOKEN_MDCODE;
791790
return 1 + (z[1]==z[0]);
@@ -1533,10 +1532,35 @@
15331532
if( tokenType==TOKEN_MDCODE && n>=sz ) return i;
15341533
i += n;
15351534
}
15361535
return 0;
15371536
}
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
+}
15381562
15391563
/*
15401564
** Convert the wiki in z[] into html in the renderer p. The
15411565
** renderer has already been initialized.
15421566
**
@@ -1756,20 +1780,34 @@
17561780
n += x + n;
17571781
}
17581782
}
17591783
break;
17601784
}
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) ){
17661804
blob_append(p->pOut, z, n);
17671805
break;
17681806
}
1769
-#endif
1770
- blob_append(p->pOut, z, n);
1807
+ blob_append(p->pOut, n==1 ? "<i>" : "<b>", 3);
1808
+ inEmph[n] = 1;
17711809
break;
17721810
}
17731811
case TOKEN_TEXT: {
17741812
int i;
17751813
for(i=0; i<n && fossil_isspace(z[i]); i++){}
17761814
--- 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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button