Fossil SCM
All submenu buttons on embedded documentation pages using markup of the form: <a class="button" href="...">LABEL</a>.
Commit
563b3ccb7b676112740dfe89b87510ac1cac0f28
Parent
2116906fb1b1ae0…
2 files changed
+2
-2
+78
-17
+2
-2
| --- src/doc.c | ||
| +++ src/doc.c | ||
| @@ -489,14 +489,14 @@ | ||
| 489 | 489 | " WHERE objid=%d AND type='ci'", vid)); |
| 490 | 490 | if( fossil_strcmp(zMime, "application/x-fossil-wiki")==0 ){ |
| 491 | 491 | Blob title, tail; |
| 492 | 492 | if( wiki_find_title(&filebody, &title, &tail) ){ |
| 493 | 493 | style_header(blob_str(&title)); |
| 494 | - wiki_convert(&tail, 0, 0); | |
| 494 | + wiki_convert(&tail, 0, WIKI_BUTTONS); | |
| 495 | 495 | }else{ |
| 496 | 496 | style_header("Documentation"); |
| 497 | - wiki_convert(&filebody, 0, 0); | |
| 497 | + wiki_convert(&filebody, 0, WIKI_BUTTONS); | |
| 498 | 498 | } |
| 499 | 499 | style_footer(); |
| 500 | 500 | }else if( fossil_strcmp(zMime, "text/plain")==0 ){ |
| 501 | 501 | style_header("Documentation"); |
| 502 | 502 | @ <blockquote><pre> |
| 503 | 503 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -489,14 +489,14 @@ | |
| 489 | " WHERE objid=%d AND type='ci'", vid)); |
| 490 | if( fossil_strcmp(zMime, "application/x-fossil-wiki")==0 ){ |
| 491 | Blob title, tail; |
| 492 | if( wiki_find_title(&filebody, &title, &tail) ){ |
| 493 | style_header(blob_str(&title)); |
| 494 | wiki_convert(&tail, 0, 0); |
| 495 | }else{ |
| 496 | style_header("Documentation"); |
| 497 | wiki_convert(&filebody, 0, 0); |
| 498 | } |
| 499 | style_footer(); |
| 500 | }else if( fossil_strcmp(zMime, "text/plain")==0 ){ |
| 501 | style_header("Documentation"); |
| 502 | @ <blockquote><pre> |
| 503 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -489,14 +489,14 @@ | |
| 489 | " WHERE objid=%d AND type='ci'", vid)); |
| 490 | if( fossil_strcmp(zMime, "application/x-fossil-wiki")==0 ){ |
| 491 | Blob title, tail; |
| 492 | if( wiki_find_title(&filebody, &title, &tail) ){ |
| 493 | style_header(blob_str(&title)); |
| 494 | wiki_convert(&tail, 0, WIKI_BUTTONS); |
| 495 | }else{ |
| 496 | style_header("Documentation"); |
| 497 | wiki_convert(&filebody, 0, WIKI_BUTTONS); |
| 498 | } |
| 499 | style_footer(); |
| 500 | }else if( fossil_strcmp(zMime, "text/plain")==0 ){ |
| 501 | style_header("Documentation"); |
| 502 | @ <blockquote><pre> |
| 503 |
+78
-17
| --- src/wikiformat.c | ||
| +++ src/wikiformat.c | ||
| @@ -27,10 +27,11 @@ | ||
| 27 | 27 | */ |
| 28 | 28 | #define WIKI_NOFOLLOW 0x001 |
| 29 | 29 | #define WIKI_HTML 0x002 |
| 30 | 30 | #define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */ |
| 31 | 31 | #define WIKI_NOBLOCK 0x008 /* No block markup of any kind */ |
| 32 | +#define WIKI_BUTTONS 0x010 /* Allow sub-menu buttons */ | |
| 32 | 33 | #endif |
| 33 | 34 | |
| 34 | 35 | |
| 35 | 36 | /* |
| 36 | 37 | ** These are the only markup attributes allowed. |
| @@ -378,19 +379,19 @@ | ||
| 378 | 379 | #define TOKEN_INDENT 9 /* " " */ |
| 379 | 380 | #define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */ |
| 380 | 381 | #define TOKEN_TEXT 11 /* None of the above */ |
| 381 | 382 | |
| 382 | 383 | /* |
| 383 | -** State flags | |
| 384 | +** State flags. Save the lower 16 bits for the WIKI_* flags. | |
| 384 | 385 | */ |
| 385 | -#define AT_NEWLINE 0x001 /* At start of a line */ | |
| 386 | -#define AT_PARAGRAPH 0x002 /* At start of a paragraph */ | |
| 387 | -#define ALLOW_WIKI 0x004 /* Allow wiki markup */ | |
| 388 | -#define FONT_MARKUP_ONLY 0x008 /* Only allow MUTYPE_FONT markup */ | |
| 389 | -#define INLINE_MARKUP_ONLY 0x010 /* Allow only "inline" markup */ | |
| 390 | -#define IN_LIST 0x020 /* Within wiki <ul> or <ol> */ | |
| 391 | -#define WIKI_USE_HTML 0x040 /* wiki-use-html option = on */ | |
| 386 | +#define AT_NEWLINE 0x0010000 /* At start of a line */ | |
| 387 | +#define AT_PARAGRAPH 0x0020000 /* At start of a paragraph */ | |
| 388 | +#define ALLOW_WIKI 0x0040000 /* Allow wiki markup */ | |
| 389 | +#define FONT_MARKUP_ONLY 0x0080000 /* Only allow MUTYPE_FONT markup */ | |
| 390 | +#define INLINE_MARKUP_ONLY 0x0100000 /* Allow only "inline" markup */ | |
| 391 | +#define IN_LIST 0x0200000 /* Within wiki <ul> or <ol> */ | |
| 392 | +#define WIKI_USE_HTML 0x0400000 /* wiki-use-html option = on */ | |
| 392 | 393 | |
| 393 | 394 | /* |
| 394 | 395 | ** Current state of the rendering engine |
| 395 | 396 | */ |
| 396 | 397 | typedef struct Renderer Renderer; |
| @@ -825,22 +826,72 @@ | ||
| 825 | 826 | z[n] = p->aAttr[i].cTerm; |
| 826 | 827 | } |
| 827 | 828 | } |
| 828 | 829 | |
| 829 | 830 | /* |
| 830 | -** Return the ID attribute for markup. Return NULL if there is no | |
| 831 | +** Return the value of attribute attrId. Return NULL if there is no | |
| 831 | 832 | ** ID attribute. |
| 832 | 833 | */ |
| 833 | -static const char *markupId(ParsedMarkup *p){ | |
| 834 | +static const char *attributeValue(ParsedMarkup *p, int attrId){ | |
| 834 | 835 | int i; |
| 835 | 836 | for(i=0; i<p->nAttr; i++){ |
| 836 | - if( p->aAttr[i].iACode==ATTR_ID ){ | |
| 837 | + if( p->aAttr[i].iACode==attrId ){ | |
| 837 | 838 | return p->aAttr[i].zValue; |
| 838 | 839 | } |
| 839 | 840 | } |
| 840 | 841 | return 0; |
| 841 | 842 | } |
| 843 | + | |
| 844 | +/* | |
| 845 | +** Return the ID attribute for markup. Return NULL if there is no | |
| 846 | +** ID attribute. | |
| 847 | +*/ | |
| 848 | +static const char *markupId(ParsedMarkup *p){ | |
| 849 | + return attributeValue(p, ATTR_ID); | |
| 850 | +} | |
| 851 | + | |
| 852 | +/* | |
| 853 | +** Check markup pMarkup to see if it is a hyperlink with class "button" | |
| 854 | +** that is follows by simple text and an </a> only. Example: | |
| 855 | +** | |
| 856 | +** <a class="button" href="../index.wiki">Index</a> | |
| 857 | +** | |
| 858 | +** If the markup matches this pattern, and if the WIKI_BUTTONS flag was | |
| 859 | +** passed to wiki_convert(), then transform this link into a submenu | |
| 860 | +** button, skip the text, and set *pN equal to the total length of the | |
| 861 | +** text through the end of </a> and return true. If the markup does | |
| 862 | +** not match or if WIKI_BUTTONS is not set, then make no changes to *pN | |
| 863 | +** and return false. | |
| 864 | +*/ | |
| 865 | +static int isButtonHyperlink( | |
| 866 | + Renderer *p, /* Renderer state */ | |
| 867 | + ParsedMarkup *pMarkup, /* Potential button markup */ | |
| 868 | + const char *z, /* Complete text of Wiki */ | |
| 869 | + int *pN /* Characters of z[] consumed */ | |
| 870 | +){ | |
| 871 | + const char *zClass; | |
| 872 | + const char *zHref; | |
| 873 | + char *zTag; | |
| 874 | + int i, j; | |
| 875 | + if( (p->state & WIKI_BUTTONS)==0 ) return 0; | |
| 876 | + zClass = attributeValue(pMarkup, ATTR_CLASS); | |
| 877 | + if( zClass==0 ) return 0; | |
| 878 | + if( fossil_strcmp(zClass, "button")!=0 ) return 0; | |
| 879 | + zHref = attributeValue(pMarkup, ATTR_HREF); | |
| 880 | + if( zHref==0 ) return 0; | |
| 881 | + i = *pN; | |
| 882 | + while( z[i] && z[i]!='<' ){ i++; } | |
| 883 | + if( fossil_strnicmp(&z[i], "</a>",4)!=0 ) return 0; | |
| 884 | + for(j=*pN; fossil_isspace(z[j]); j++){} | |
| 885 | + zTag = mprintf("%.*s", i-j, &z[j]); | |
| 886 | + j = (int)strlen(zTag); | |
| 887 | + while( j>0 && fossil_isspace(zTag[j-1]) ){ j--; } | |
| 888 | + if( j==0 ) return 0; | |
| 889 | + style_submenu_element(zTag, zTag, "%s", zHref); | |
| 890 | + *pN = i+4; | |
| 891 | + return 1; | |
| 892 | +} | |
| 842 | 893 | |
| 843 | 894 | /* |
| 844 | 895 | ** Pop a single element off of the stack. As the element is popped, |
| 845 | 896 | ** output its end tag if it is not a </div> tag. |
| 846 | 897 | */ |
| @@ -1453,14 +1504,16 @@ | ||
| 1453 | 1504 | pushStack(p, markup.iCode); |
| 1454 | 1505 | renderMarkup(p->pOut, &markup); |
| 1455 | 1506 | } |
| 1456 | 1507 | }else |
| 1457 | 1508 | if( markup.iType==MUTYPE_HYPERLINK ){ |
| 1458 | - popStackToTag(p, markup.iCode); | |
| 1459 | - startAutoParagraph(p); | |
| 1460 | - renderMarkup(p->pOut, &markup); | |
| 1461 | - pushStack(p, markup.iCode); | |
| 1509 | + if( !isButtonHyperlink(p, &markup, z, &n) ){ | |
| 1510 | + popStackToTag(p, markup.iCode); | |
| 1511 | + startAutoParagraph(p); | |
| 1512 | + renderMarkup(p->pOut, &markup); | |
| 1513 | + pushStack(p, markup.iCode); | |
| 1514 | + } | |
| 1462 | 1515 | }else |
| 1463 | 1516 | { |
| 1464 | 1517 | if( markup.iType==MUTYPE_FONT ){ |
| 1465 | 1518 | startAutoParagraph(p); |
| 1466 | 1519 | }else if( markup.iType==MUTYPE_BLOCK || markup.iType==MUTYPE_LIST ){ |
| @@ -1508,11 +1561,11 @@ | ||
| 1508 | 1561 | void wiki_convert(Blob *pIn, Blob *pOut, int flags){ |
| 1509 | 1562 | char *z; |
| 1510 | 1563 | Renderer renderer; |
| 1511 | 1564 | |
| 1512 | 1565 | memset(&renderer, 0, sizeof(renderer)); |
| 1513 | - renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH; | |
| 1566 | + renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags; | |
| 1514 | 1567 | if( flags & WIKI_NOBLOCK ){ |
| 1515 | 1568 | renderer.state |= INLINE_MARKUP_ONLY; |
| 1516 | 1569 | } |
| 1517 | 1570 | if( flags & WIKI_INLINE ){ |
| 1518 | 1571 | renderer.wantAutoParagraph = 0; |
| @@ -1538,17 +1591,25 @@ | ||
| 1538 | 1591 | free(renderer.aStack); |
| 1539 | 1592 | } |
| 1540 | 1593 | |
| 1541 | 1594 | /* |
| 1542 | 1595 | ** COMMAND: test-wiki-render |
| 1596 | +** | |
| 1597 | +** %fossil test-wiki-render FILE [OPTIONS] | |
| 1598 | +** | |
| 1599 | +** Options: | |
| 1600 | +** --buttons Set the WIKI_BUTTONS flag | |
| 1543 | 1601 | */ |
| 1544 | 1602 | void test_wiki_render(void){ |
| 1545 | 1603 | Blob in, out; |
| 1604 | + int flags = 0; | |
| 1605 | + if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS; | |
| 1606 | + verify_all_options(); | |
| 1546 | 1607 | if( g.argc!=3 ) usage("FILE"); |
| 1547 | 1608 | blob_zero(&out); |
| 1548 | 1609 | blob_read_from_file(&in, g.argv[2]); |
| 1549 | - wiki_convert(&in, &out, 0); | |
| 1610 | + wiki_convert(&in, &out, flags); | |
| 1550 | 1611 | blob_write_to_file(&out, "-"); |
| 1551 | 1612 | } |
| 1552 | 1613 | |
| 1553 | 1614 | /* |
| 1554 | 1615 | ** Search for a <title>...</title> at the beginning of a wiki page. |
| 1555 | 1616 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -27,10 +27,11 @@ | |
| 27 | */ |
| 28 | #define WIKI_NOFOLLOW 0x001 |
| 29 | #define WIKI_HTML 0x002 |
| 30 | #define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */ |
| 31 | #define WIKI_NOBLOCK 0x008 /* No block markup of any kind */ |
| 32 | #endif |
| 33 | |
| 34 | |
| 35 | /* |
| 36 | ** These are the only markup attributes allowed. |
| @@ -378,19 +379,19 @@ | |
| 378 | #define TOKEN_INDENT 9 /* " " */ |
| 379 | #define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */ |
| 380 | #define TOKEN_TEXT 11 /* None of the above */ |
| 381 | |
| 382 | /* |
| 383 | ** State flags |
| 384 | */ |
| 385 | #define AT_NEWLINE 0x001 /* At start of a line */ |
| 386 | #define AT_PARAGRAPH 0x002 /* At start of a paragraph */ |
| 387 | #define ALLOW_WIKI 0x004 /* Allow wiki markup */ |
| 388 | #define FONT_MARKUP_ONLY 0x008 /* Only allow MUTYPE_FONT markup */ |
| 389 | #define INLINE_MARKUP_ONLY 0x010 /* Allow only "inline" markup */ |
| 390 | #define IN_LIST 0x020 /* Within wiki <ul> or <ol> */ |
| 391 | #define WIKI_USE_HTML 0x040 /* wiki-use-html option = on */ |
| 392 | |
| 393 | /* |
| 394 | ** Current state of the rendering engine |
| 395 | */ |
| 396 | typedef struct Renderer Renderer; |
| @@ -825,22 +826,72 @@ | |
| 825 | z[n] = p->aAttr[i].cTerm; |
| 826 | } |
| 827 | } |
| 828 | |
| 829 | /* |
| 830 | ** Return the ID attribute for markup. Return NULL if there is no |
| 831 | ** ID attribute. |
| 832 | */ |
| 833 | static const char *markupId(ParsedMarkup *p){ |
| 834 | int i; |
| 835 | for(i=0; i<p->nAttr; i++){ |
| 836 | if( p->aAttr[i].iACode==ATTR_ID ){ |
| 837 | return p->aAttr[i].zValue; |
| 838 | } |
| 839 | } |
| 840 | return 0; |
| 841 | } |
| 842 | |
| 843 | /* |
| 844 | ** Pop a single element off of the stack. As the element is popped, |
| 845 | ** output its end tag if it is not a </div> tag. |
| 846 | */ |
| @@ -1453,14 +1504,16 @@ | |
| 1453 | pushStack(p, markup.iCode); |
| 1454 | renderMarkup(p->pOut, &markup); |
| 1455 | } |
| 1456 | }else |
| 1457 | if( markup.iType==MUTYPE_HYPERLINK ){ |
| 1458 | popStackToTag(p, markup.iCode); |
| 1459 | startAutoParagraph(p); |
| 1460 | renderMarkup(p->pOut, &markup); |
| 1461 | pushStack(p, markup.iCode); |
| 1462 | }else |
| 1463 | { |
| 1464 | if( markup.iType==MUTYPE_FONT ){ |
| 1465 | startAutoParagraph(p); |
| 1466 | }else if( markup.iType==MUTYPE_BLOCK || markup.iType==MUTYPE_LIST ){ |
| @@ -1508,11 +1561,11 @@ | |
| 1508 | void wiki_convert(Blob *pIn, Blob *pOut, int flags){ |
| 1509 | char *z; |
| 1510 | Renderer renderer; |
| 1511 | |
| 1512 | memset(&renderer, 0, sizeof(renderer)); |
| 1513 | renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH; |
| 1514 | if( flags & WIKI_NOBLOCK ){ |
| 1515 | renderer.state |= INLINE_MARKUP_ONLY; |
| 1516 | } |
| 1517 | if( flags & WIKI_INLINE ){ |
| 1518 | renderer.wantAutoParagraph = 0; |
| @@ -1538,17 +1591,25 @@ | |
| 1538 | free(renderer.aStack); |
| 1539 | } |
| 1540 | |
| 1541 | /* |
| 1542 | ** COMMAND: test-wiki-render |
| 1543 | */ |
| 1544 | void test_wiki_render(void){ |
| 1545 | Blob in, out; |
| 1546 | if( g.argc!=3 ) usage("FILE"); |
| 1547 | blob_zero(&out); |
| 1548 | blob_read_from_file(&in, g.argv[2]); |
| 1549 | wiki_convert(&in, &out, 0); |
| 1550 | blob_write_to_file(&out, "-"); |
| 1551 | } |
| 1552 | |
| 1553 | /* |
| 1554 | ** Search for a <title>...</title> at the beginning of a wiki page. |
| 1555 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -27,10 +27,11 @@ | |
| 27 | */ |
| 28 | #define WIKI_NOFOLLOW 0x001 |
| 29 | #define WIKI_HTML 0x002 |
| 30 | #define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */ |
| 31 | #define WIKI_NOBLOCK 0x008 /* No block markup of any kind */ |
| 32 | #define WIKI_BUTTONS 0x010 /* Allow sub-menu buttons */ |
| 33 | #endif |
| 34 | |
| 35 | |
| 36 | /* |
| 37 | ** These are the only markup attributes allowed. |
| @@ -378,19 +379,19 @@ | |
| 379 | #define TOKEN_INDENT 9 /* " " */ |
| 380 | #define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */ |
| 381 | #define TOKEN_TEXT 11 /* None of the above */ |
| 382 | |
| 383 | /* |
| 384 | ** State flags. Save the lower 16 bits for the WIKI_* flags. |
| 385 | */ |
| 386 | #define AT_NEWLINE 0x0010000 /* At start of a line */ |
| 387 | #define AT_PARAGRAPH 0x0020000 /* At start of a paragraph */ |
| 388 | #define ALLOW_WIKI 0x0040000 /* Allow wiki markup */ |
| 389 | #define FONT_MARKUP_ONLY 0x0080000 /* Only allow MUTYPE_FONT markup */ |
| 390 | #define INLINE_MARKUP_ONLY 0x0100000 /* Allow only "inline" markup */ |
| 391 | #define IN_LIST 0x0200000 /* Within wiki <ul> or <ol> */ |
| 392 | #define WIKI_USE_HTML 0x0400000 /* wiki-use-html option = on */ |
| 393 | |
| 394 | /* |
| 395 | ** Current state of the rendering engine |
| 396 | */ |
| 397 | typedef struct Renderer Renderer; |
| @@ -825,22 +826,72 @@ | |
| 826 | z[n] = p->aAttr[i].cTerm; |
| 827 | } |
| 828 | } |
| 829 | |
| 830 | /* |
| 831 | ** Return the value of attribute attrId. Return NULL if there is no |
| 832 | ** ID attribute. |
| 833 | */ |
| 834 | static const char *attributeValue(ParsedMarkup *p, int attrId){ |
| 835 | int i; |
| 836 | for(i=0; i<p->nAttr; i++){ |
| 837 | if( p->aAttr[i].iACode==attrId ){ |
| 838 | return p->aAttr[i].zValue; |
| 839 | } |
| 840 | } |
| 841 | return 0; |
| 842 | } |
| 843 | |
| 844 | /* |
| 845 | ** Return the ID attribute for markup. Return NULL if there is no |
| 846 | ** ID attribute. |
| 847 | */ |
| 848 | static const char *markupId(ParsedMarkup *p){ |
| 849 | return attributeValue(p, ATTR_ID); |
| 850 | } |
| 851 | |
| 852 | /* |
| 853 | ** Check markup pMarkup to see if it is a hyperlink with class "button" |
| 854 | ** that is follows by simple text and an </a> only. Example: |
| 855 | ** |
| 856 | ** <a class="button" href="../index.wiki">Index</a> |
| 857 | ** |
| 858 | ** If the markup matches this pattern, and if the WIKI_BUTTONS flag was |
| 859 | ** passed to wiki_convert(), then transform this link into a submenu |
| 860 | ** button, skip the text, and set *pN equal to the total length of the |
| 861 | ** text through the end of </a> and return true. If the markup does |
| 862 | ** not match or if WIKI_BUTTONS is not set, then make no changes to *pN |
| 863 | ** and return false. |
| 864 | */ |
| 865 | static int isButtonHyperlink( |
| 866 | Renderer *p, /* Renderer state */ |
| 867 | ParsedMarkup *pMarkup, /* Potential button markup */ |
| 868 | const char *z, /* Complete text of Wiki */ |
| 869 | int *pN /* Characters of z[] consumed */ |
| 870 | ){ |
| 871 | const char *zClass; |
| 872 | const char *zHref; |
| 873 | char *zTag; |
| 874 | int i, j; |
| 875 | if( (p->state & WIKI_BUTTONS)==0 ) return 0; |
| 876 | zClass = attributeValue(pMarkup, ATTR_CLASS); |
| 877 | if( zClass==0 ) return 0; |
| 878 | if( fossil_strcmp(zClass, "button")!=0 ) return 0; |
| 879 | zHref = attributeValue(pMarkup, ATTR_HREF); |
| 880 | if( zHref==0 ) return 0; |
| 881 | i = *pN; |
| 882 | while( z[i] && z[i]!='<' ){ i++; } |
| 883 | if( fossil_strnicmp(&z[i], "</a>",4)!=0 ) return 0; |
| 884 | for(j=*pN; fossil_isspace(z[j]); j++){} |
| 885 | zTag = mprintf("%.*s", i-j, &z[j]); |
| 886 | j = (int)strlen(zTag); |
| 887 | while( j>0 && fossil_isspace(zTag[j-1]) ){ j--; } |
| 888 | if( j==0 ) return 0; |
| 889 | style_submenu_element(zTag, zTag, "%s", zHref); |
| 890 | *pN = i+4; |
| 891 | return 1; |
| 892 | } |
| 893 | |
| 894 | /* |
| 895 | ** Pop a single element off of the stack. As the element is popped, |
| 896 | ** output its end tag if it is not a </div> tag. |
| 897 | */ |
| @@ -1453,14 +1504,16 @@ | |
| 1504 | pushStack(p, markup.iCode); |
| 1505 | renderMarkup(p->pOut, &markup); |
| 1506 | } |
| 1507 | }else |
| 1508 | if( markup.iType==MUTYPE_HYPERLINK ){ |
| 1509 | if( !isButtonHyperlink(p, &markup, z, &n) ){ |
| 1510 | popStackToTag(p, markup.iCode); |
| 1511 | startAutoParagraph(p); |
| 1512 | renderMarkup(p->pOut, &markup); |
| 1513 | pushStack(p, markup.iCode); |
| 1514 | } |
| 1515 | }else |
| 1516 | { |
| 1517 | if( markup.iType==MUTYPE_FONT ){ |
| 1518 | startAutoParagraph(p); |
| 1519 | }else if( markup.iType==MUTYPE_BLOCK || markup.iType==MUTYPE_LIST ){ |
| @@ -1508,11 +1561,11 @@ | |
| 1561 | void wiki_convert(Blob *pIn, Blob *pOut, int flags){ |
| 1562 | char *z; |
| 1563 | Renderer renderer; |
| 1564 | |
| 1565 | memset(&renderer, 0, sizeof(renderer)); |
| 1566 | renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags; |
| 1567 | if( flags & WIKI_NOBLOCK ){ |
| 1568 | renderer.state |= INLINE_MARKUP_ONLY; |
| 1569 | } |
| 1570 | if( flags & WIKI_INLINE ){ |
| 1571 | renderer.wantAutoParagraph = 0; |
| @@ -1538,17 +1591,25 @@ | |
| 1591 | free(renderer.aStack); |
| 1592 | } |
| 1593 | |
| 1594 | /* |
| 1595 | ** COMMAND: test-wiki-render |
| 1596 | ** |
| 1597 | ** %fossil test-wiki-render FILE [OPTIONS] |
| 1598 | ** |
| 1599 | ** Options: |
| 1600 | ** --buttons Set the WIKI_BUTTONS flag |
| 1601 | */ |
| 1602 | void test_wiki_render(void){ |
| 1603 | Blob in, out; |
| 1604 | int flags = 0; |
| 1605 | if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS; |
| 1606 | verify_all_options(); |
| 1607 | if( g.argc!=3 ) usage("FILE"); |
| 1608 | blob_zero(&out); |
| 1609 | blob_read_from_file(&in, g.argv[2]); |
| 1610 | wiki_convert(&in, &out, flags); |
| 1611 | blob_write_to_file(&out, "-"); |
| 1612 | } |
| 1613 | |
| 1614 | /* |
| 1615 | ** Search for a <title>...</title> at the beginning of a wiki page. |
| 1616 |