Index: src/doc.c ================================================================== --- src/doc.c +++ src/doc.c @@ -489,14 +489,14 @@ " WHERE objid=%d AND type='ci'", vid)); if( fossil_strcmp(zMime, "application/x-fossil-wiki")==0 ){ Blob title, tail; if( wiki_find_title(&filebody, &title, &tail) ){ style_header(blob_str(&title)); - wiki_convert(&tail, 0, 0); + wiki_convert(&tail, 0, WIKI_BUTTONS); }else{ style_header("Documentation"); - wiki_convert(&filebody, 0, 0); + wiki_convert(&filebody, 0, WIKI_BUTTONS); } style_footer(); }else if( fossil_strcmp(zMime, "text/plain")==0 ){ style_header("Documentation"); @ <blockquote><pre> Index: src/wikiformat.c ================================================================== --- src/wikiformat.c +++ src/wikiformat.c @@ -27,10 +27,11 @@ */ #define WIKI_NOFOLLOW 0x001 #define WIKI_HTML 0x002 #define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */ #define WIKI_NOBLOCK 0x008 /* No block markup of any kind */ +#define WIKI_BUTTONS 0x010 /* Allow sub-menu buttons */ #endif /* ** These are the only markup attributes allowed. @@ -378,19 +379,19 @@ #define TOKEN_INDENT 9 /* " " */ #define TOKEN_RAW 10 /* Output exactly (used when wiki-use-html==1) */ #define TOKEN_TEXT 11 /* None of the above */ /* -** State flags +** State flags. Save the lower 16 bits for the WIKI_* flags. */ -#define AT_NEWLINE 0x001 /* At start of a line */ -#define AT_PARAGRAPH 0x002 /* At start of a paragraph */ -#define ALLOW_WIKI 0x004 /* Allow wiki markup */ -#define FONT_MARKUP_ONLY 0x008 /* Only allow MUTYPE_FONT markup */ -#define INLINE_MARKUP_ONLY 0x010 /* Allow only "inline" markup */ -#define IN_LIST 0x020 /* Within wiki <ul> or <ol> */ -#define WIKI_USE_HTML 0x040 /* wiki-use-html option = on */ +#define AT_NEWLINE 0x0010000 /* At start of a line */ +#define AT_PARAGRAPH 0x0020000 /* At start of a paragraph */ +#define ALLOW_WIKI 0x0040000 /* Allow wiki markup */ +#define FONT_MARKUP_ONLY 0x0080000 /* Only allow MUTYPE_FONT markup */ +#define INLINE_MARKUP_ONLY 0x0100000 /* Allow only "inline" markup */ +#define IN_LIST 0x0200000 /* Within wiki <ul> or <ol> */ +#define WIKI_USE_HTML 0x0400000 /* wiki-use-html option = on */ /* ** Current state of the rendering engine */ typedef struct Renderer Renderer; @@ -825,22 +826,72 @@ z[n] = p->aAttr[i].cTerm; } } /* -** Return the ID attribute for markup. Return NULL if there is no +** Return the value of attribute attrId. Return NULL if there is no ** ID attribute. */ -static const char *markupId(ParsedMarkup *p){ +static const char *attributeValue(ParsedMarkup *p, int attrId){ int i; for(i=0; i<p->nAttr; i++){ - if( p->aAttr[i].iACode==ATTR_ID ){ + if( p->aAttr[i].iACode==attrId ){ return p->aAttr[i].zValue; } } return 0; } + +/* +** Return the ID attribute for markup. Return NULL if there is no +** ID attribute. +*/ +static const char *markupId(ParsedMarkup *p){ + return attributeValue(p, ATTR_ID); +} + +/* +** Check markup pMarkup to see if it is a hyperlink with class "button" +** that is follows by simple text and an </a> only. Example: +** +** <a class="button" href="../index.wiki">Index</a> +** +** If the markup matches this pattern, and if the WIKI_BUTTONS flag was +** passed to wiki_convert(), then transform this link into a submenu +** button, skip the text, and set *pN equal to the total length of the +** text through the end of </a> and return true. If the markup does +** not match or if WIKI_BUTTONS is not set, then make no changes to *pN +** and return false. +*/ +static int isButtonHyperlink( + Renderer *p, /* Renderer state */ + ParsedMarkup *pMarkup, /* Potential button markup */ + const char *z, /* Complete text of Wiki */ + int *pN /* Characters of z[] consumed */ +){ + const char *zClass; + const char *zHref; + char *zTag; + int i, j; + if( (p->state & WIKI_BUTTONS)==0 ) return 0; + zClass = attributeValue(pMarkup, ATTR_CLASS); + if( zClass==0 ) return 0; + if( fossil_strcmp(zClass, "button")!=0 ) return 0; + zHref = attributeValue(pMarkup, ATTR_HREF); + if( zHref==0 ) return 0; + i = *pN; + while( z[i] && z[i]!='<' ){ i++; } + if( fossil_strnicmp(&z[i], "</a>",4)!=0 ) return 0; + for(j=*pN; fossil_isspace(z[j]); j++){} + zTag = mprintf("%.*s", i-j, &z[j]); + j = (int)strlen(zTag); + while( j>0 && fossil_isspace(zTag[j-1]) ){ j--; } + if( j==0 ) return 0; + style_submenu_element(zTag, zTag, "%s", zHref); + *pN = i+4; + return 1; +} /* ** Pop a single element off of the stack. As the element is popped, ** output its end tag if it is not a </div> tag. */ @@ -1453,14 +1504,16 @@ pushStack(p, markup.iCode); renderMarkup(p->pOut, &markup); } }else if( markup.iType==MUTYPE_HYPERLINK ){ - popStackToTag(p, markup.iCode); - startAutoParagraph(p); - renderMarkup(p->pOut, &markup); - pushStack(p, markup.iCode); + if( !isButtonHyperlink(p, &markup, z, &n) ){ + popStackToTag(p, markup.iCode); + startAutoParagraph(p); + renderMarkup(p->pOut, &markup); + pushStack(p, markup.iCode); + } }else { if( markup.iType==MUTYPE_FONT ){ startAutoParagraph(p); }else if( markup.iType==MUTYPE_BLOCK || markup.iType==MUTYPE_LIST ){ @@ -1508,11 +1561,11 @@ void wiki_convert(Blob *pIn, Blob *pOut, int flags){ char *z; Renderer renderer; memset(&renderer, 0, sizeof(renderer)); - renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH; + renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags; if( flags & WIKI_NOBLOCK ){ renderer.state |= INLINE_MARKUP_ONLY; } if( flags & WIKI_INLINE ){ renderer.wantAutoParagraph = 0; @@ -1538,17 +1591,25 @@ free(renderer.aStack); } /* ** COMMAND: test-wiki-render +** +** %fossil test-wiki-render FILE [OPTIONS] +** +** Options: +** --buttons Set the WIKI_BUTTONS flag */ void test_wiki_render(void){ Blob in, out; + int flags = 0; + if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS; + verify_all_options(); if( g.argc!=3 ) usage("FILE"); blob_zero(&out); blob_read_from_file(&in, g.argv[2]); - wiki_convert(&in, &out, 0); + wiki_convert(&in, &out, flags); blob_write_to_file(&out, "-"); } /* ** Search for a <title>...</title> at the beginning of a wiki page. Index: www/changes.wiki ================================================================== --- www/changes.wiki +++ www/changes.wiki @@ -62,10 +62,13 @@ * Add another built-in skin: "Enhanced Default". Other minor tweaks to the existing skins. * Add the "urllist" webpage, showing a list of URLs by which a server instance of Fossil has been accessed. Requires "Administrator" privileges. A link is on the "Setup" main page. + * Enable dynamic loading of the Tcl runtime for installations that want + to use Tcl as part of their configuration. This reduces the size of + the Fossil binary and allows any version of Tcl 8.4 or later to be used. * Merge the latest SQLite changes from upstream. * Lots of minor bug fixes. <h2>Changes For Version 1.23 (2012-08-08)</h2> * The default checkout database name is now ".fslckout" instead of