Fossil SCM

Enable automatic paragraph numbering in Markdown using a special HTML comment: "<--markdown paragraph-numbers=on -->"

drh 2020-09-15 18:20 trunk
Commit d9a70a1df92291d74c63590bfd93bacbeae3261032d16b9e1d8503ec54ab77ca
+54
--- src/blob.c
+++ src/blob.c
@@ -652,10 +652,64 @@
652652
blob_extract(pFrom, i-pFrom->iCursor, pTo);
653653
while( i<n && fossil_isspace(aData[i]) ){ i++; }
654654
pFrom->iCursor = i;
655655
return pTo->nUsed;
656656
}
657
+
658
+/*
659
+** Extract a single token of one of the forms:
660
+**
661
+** ="TEXT"
662
+** ='TEXT'
663
+** =TEXT
664
+**
665
+** The leading = is present if and only if skipEq is true.
666
+**
667
+** TEXT is the part that is extracted. There can be whitespace on
668
+** either side of the text. The TEXT ends at the matching delimiter,
669
+** or at whitespace if there is no delimiter.
670
+**
671
+** Return true if an argument is found. Return zero and leave
672
+** the cursor unchanged if there is no argument.
673
+**
674
+** The cursor of pFrom is left pointing at the first character past
675
+** the end of the argument.
676
+**
677
+** pTo will be an ephermeral blob. If pFrom changes, it might alter
678
+** pTo as well.
679
+*/
680
+int blob_argument_token(Blob *pFrom, Blob *pTo, int skipEq){
681
+ char *aData = pFrom->aData;
682
+ int n = pFrom->nUsed;
683
+ int i = pFrom->iCursor;
684
+ int iStart;
685
+ char cDelim;
686
+ while( i<n && fossil_isspace(aData[i]) ){ i++; }
687
+ if( skipEq ){
688
+ if( i>=n || aData[i]!='=' ) return 0;
689
+ i++;
690
+ while( i<n && fossil_isspace(aData[i]) ){ i++; }
691
+ }
692
+ if( i>=n ) return 0;
693
+ cDelim = aData[i];
694
+ if( cDelim=='\'' || cDelim=='"' ){
695
+ if( i>=n-2 ) return 0;
696
+ i++;
697
+ iStart = pFrom->iCursor = i;
698
+ while( i<n && aData[i]!=cDelim ){ i++; }
699
+ if( i>=n ) return 0;
700
+ blob_extract(pFrom, i-iStart, pTo);
701
+ i++;
702
+ }else{
703
+ iStart = pFrom->iCursor = i;
704
+ while( i<n && !fossil_isspace(aData[i]) && aData[i]!='=' ){ i++; }
705
+ blob_extract(pFrom, i-iStart, pTo);
706
+ }
707
+ while( i<n && fossil_isspace(aData[i]) ){ i++; }
708
+ pFrom->iCursor = i;
709
+ return 1;
710
+}
657711
658712
/*
659713
** Extract a single SQL token from pFrom and use it to initialize pTo.
660714
** Return the number of bytes in the token. If no token is found,
661715
** return 0.
662716
--- src/blob.c
+++ src/blob.c
@@ -652,10 +652,64 @@
652 blob_extract(pFrom, i-pFrom->iCursor, pTo);
653 while( i<n && fossil_isspace(aData[i]) ){ i++; }
654 pFrom->iCursor = i;
655 return pTo->nUsed;
656 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
657
658 /*
659 ** Extract a single SQL token from pFrom and use it to initialize pTo.
660 ** Return the number of bytes in the token. If no token is found,
661 ** return 0.
662
--- src/blob.c
+++ src/blob.c
@@ -652,10 +652,64 @@
652 blob_extract(pFrom, i-pFrom->iCursor, pTo);
653 while( i<n && fossil_isspace(aData[i]) ){ i++; }
654 pFrom->iCursor = i;
655 return pTo->nUsed;
656 }
657
658 /*
659 ** Extract a single token of one of the forms:
660 **
661 ** ="TEXT"
662 ** ='TEXT'
663 ** =TEXT
664 **
665 ** The leading = is present if and only if skipEq is true.
666 **
667 ** TEXT is the part that is extracted. There can be whitespace on
668 ** either side of the text. The TEXT ends at the matching delimiter,
669 ** or at whitespace if there is no delimiter.
670 **
671 ** Return true if an argument is found. Return zero and leave
672 ** the cursor unchanged if there is no argument.
673 **
674 ** The cursor of pFrom is left pointing at the first character past
675 ** the end of the argument.
676 **
677 ** pTo will be an ephermeral blob. If pFrom changes, it might alter
678 ** pTo as well.
679 */
680 int blob_argument_token(Blob *pFrom, Blob *pTo, int skipEq){
681 char *aData = pFrom->aData;
682 int n = pFrom->nUsed;
683 int i = pFrom->iCursor;
684 int iStart;
685 char cDelim;
686 while( i<n && fossil_isspace(aData[i]) ){ i++; }
687 if( skipEq ){
688 if( i>=n || aData[i]!='=' ) return 0;
689 i++;
690 while( i<n && fossil_isspace(aData[i]) ){ i++; }
691 }
692 if( i>=n ) return 0;
693 cDelim = aData[i];
694 if( cDelim=='\'' || cDelim=='"' ){
695 if( i>=n-2 ) return 0;
696 i++;
697 iStart = pFrom->iCursor = i;
698 while( i<n && aData[i]!=cDelim ){ i++; }
699 if( i>=n ) return 0;
700 blob_extract(pFrom, i-iStart, pTo);
701 i++;
702 }else{
703 iStart = pFrom->iCursor = i;
704 while( i<n && !fossil_isspace(aData[i]) && aData[i]!='=' ){ i++; }
705 blob_extract(pFrom, i-iStart, pTo);
706 }
707 while( i<n && fossil_isspace(aData[i]) ){ i++; }
708 pFrom->iCursor = i;
709 return 1;
710 }
711
712 /*
713 ** Extract a single SQL token from pFrom and use it to initialize pTo.
714 ** Return the number of bytes in the token. If no token is found,
715 ** return 0.
716
+1 -1
--- src/markdown.c
+++ src/markdown.c
@@ -372,11 +372,11 @@
372372
if( data[0]!='<' ) return 0;
373373
i = (data[1]=='/') ? 2 : 1;
374374
if( (data[i]<'a' || data[i]>'z') && (data[i]<'A' || data[i]>'Z') ){
375375
if( data[1]=='!' && size>=7 && data[2]=='-' && data[3]=='-' ){
376376
for(i=6; i<size && (data[i]!='>'||data[i-1]!='-'|| data[i-2]!='-');i++){}
377
- if( i<size ) return i;
377
+ if( i<size ) return i+1;
378378
}
379379
return 0;
380380
}
381381
382382
/* scheme test */
383383
--- src/markdown.c
+++ src/markdown.c
@@ -372,11 +372,11 @@
372 if( data[0]!='<' ) return 0;
373 i = (data[1]=='/') ? 2 : 1;
374 if( (data[i]<'a' || data[i]>'z') && (data[i]<'A' || data[i]>'Z') ){
375 if( data[1]=='!' && size>=7 && data[2]=='-' && data[3]=='-' ){
376 for(i=6; i<size && (data[i]!='>'||data[i-1]!='-'|| data[i-2]!='-');i++){}
377 if( i<size ) return i;
378 }
379 return 0;
380 }
381
382 /* scheme test */
383
--- src/markdown.c
+++ src/markdown.c
@@ -372,11 +372,11 @@
372 if( data[0]!='<' ) return 0;
373 i = (data[1]=='/') ? 2 : 1;
374 if( (data[i]<'a' || data[i]>'z') && (data[i]<'A' || data[i]>'Z') ){
375 if( data[1]=='!' && size>=7 && data[2]=='-' && data[3]=='-' ){
376 for(i=6; i<size && (data[i]!='>'||data[i-1]!='-'|| data[i-2]!='-');i++){}
377 if( i<size ) return i+1;
378 }
379 return 0;
380 }
381
382 /* scheme test */
383
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -29,17 +29,33 @@
2929
struct Blob *output_title,
3030
struct Blob *output_body);
3131
3232
#endif /* INTERFACE */
3333
34
+/*
35
+** Each heading is recorded as an instance of the following
36
+** structure, in its own separate memory allocation.
37
+*/
38
+typedef struct MarkdownHeading MarkdownHeading;
39
+struct MarkdownHeading {
40
+ MarkdownHeading *pPrev, *pNext; /* List of them all */
41
+ char *zTitle; /* Text as displayed */
42
+ char *zTag; /* Pandoc-style tag */
43
+};
44
+
3445
/*
3546
** An instance of the following structure is passed through the
3647
** "opaque" pointer.
3748
*/
3849
typedef struct MarkdownToHtml MarkdownToHtml;
3950
struct MarkdownToHtml {
40
- Blob *output_title; /* Store the title here */
51
+ Blob *output_title; /* Store the title here */
52
+ MarkdownHeading *pFirst, *pList; /* List of all headings */
53
+ int iToc; /* Where to insert table-of-contents */
54
+ int mxToc; /* Maximum table-of-content level */
55
+ int iHdngNums; /* True to automatically number headings */
56
+ int aNum[6]; /* Most recent number at each level */
4157
};
4258
4359
4460
/* INTER_BLOCK -- skip a line between block level elements */
4561
#define INTER_BLOCK(ob) \
@@ -137,15 +153,64 @@
137153
138154
static void html_epilog(struct Blob *ob, void *opaque){
139155
INTER_BLOCK(ob);
140156
BLOB_APPEND_LITERAL(ob, "</div>\n");
141157
}
158
+
159
+/*
160
+** If text is an HTML control comment, then deal with it and return true.
161
+** Otherwise just return false without making any changes.
162
+**
163
+** We are looking for comments of the following form:
164
+**
165
+** <!--markdown: toc=N -->
166
+** <!--markdown: paragraph-numbers=on -->
167
+** <!--markdown: paragraph-numbers=N -->
168
+**
169
+** In the paragraph-numbers=N form with N>1, N-th level headings are
170
+** numbered like top-levels. N+1-th level headings are like 2nd levels.
171
+** and so forth.
172
+**
173
+** In the toc=N form, a table of contents is generated for all headings
174
+** less than or equal to leve N.
175
+*/
176
+static int html_control_comment(Blob *ob, Blob *text, void *opaque){
177
+ Blob token, arg;
178
+ MarkdownToHtml *pCtx;
179
+ if( blob_size(text)<20 ) return 0;
180
+ if( strncmp(blob_buffer(text),"<!--markdown:",13)!=0 ) return 0;
181
+ pCtx = (MarkdownToHtml*)opaque;
182
+ blob_seek(text, 13, BLOB_SEEK_SET);
183
+ blob_init(&token, 0, 0);
184
+ blob_init(&arg, 0, 0);
185
+ while( blob_argument_token(text, &token, 0) ){
186
+ if( blob_eq_str(&token, "toc", 3) && blob_argument_token(text, &arg, 1) ){
187
+ pCtx->iToc = blob_size(ob);
188
+ pCtx->mxToc = atoi(blob_str(&arg));
189
+ blob_reset(&arg);
190
+ }else
191
+ if( blob_eq_str(&token,"paragraph-numbers",-1)
192
+ && blob_argument_token(text,&arg,1)
193
+ ){
194
+ char *zArg = blob_str(&arg);
195
+ pCtx->iHdngNums = fossil_isdigit(zArg[0]) ? atoi(zArg) : is_truth(zArg);
196
+ blob_reset(&arg);
197
+ }else
198
+ if( !blob_eq_str(&token,"-->",3) ){
199
+ blob_appendf(ob, "<!--markdown: unknown-tag=\"%h\" -->",
200
+ blob_str(&token));
201
+ }
202
+ blob_reset(&token);
203
+ }
204
+ return 1;
205
+}
142206
143207
static void html_blockhtml(struct Blob *ob, struct Blob *text, void *opaque){
144208
char *data = blob_buffer(text);
145209
size_t size = blob_size(text);
146210
Blob *title = ((MarkdownToHtml*)opaque)->output_title;
211
+ if( html_control_comment(ob,text,opaque) ) return;
147212
while( size>0 && fossil_isspace(data[0]) ){ data++; size--; }
148213
while( size>0 && fossil_isspace(data[size-1]) ){ size--; }
149214
/* If the first raw block is an <h1> element, then use it as the title. */
150215
if( blob_size(ob)<=PROLOG_SIZE
151216
&& size>9
@@ -180,19 +245,30 @@
180245
struct Blob *ob,
181246
struct Blob *text,
182247
int level,
183248
void *opaque
184249
){
185
- struct Blob *title = ((MarkdownToHtml*)opaque)->output_title;
250
+ MarkdownToHtml *pCtx = (MarkdownToHtml*)opaque;
251
+ struct Blob *title = pCtx->output_title;
186252
/* The first header at the beginning of a text is considered as
187253
* a title and not output. */
188254
if( blob_size(ob)<=PROLOG_SIZE && title!=0 && blob_size(title)==0 ){
189255
BLOB_APPEND_BLOB(title, text);
190256
return;
191257
}
192258
INTER_BLOCK(ob);
193259
blob_appendf(ob, "<h%d>", level);
260
+ if( pCtx->iHdngNums && level>=pCtx->iHdngNums ){
261
+ int i;
262
+ for(i=pCtx->iHdngNums-1; i<level-1; i++){
263
+ blob_appendf(ob,"%d.",pCtx->aNum[i]);
264
+ }
265
+ blob_appendf(ob,"%d", ++pCtx->aNum[i]);
266
+ if( i==pCtx->iHdngNums-1 ) blob_append(ob, ".0", 2);
267
+ blob_append(ob, " ", 1);
268
+ for(i++; i<6; i++) pCtx->aNum[i] = 0;
269
+ }
194270
BLOB_APPEND_BLOB(ob, text);
195271
blob_appendf(ob, "</h%d>", level);
196272
}
197273
198274
static void html_hrule(struct Blob *ob, void *opaque){
@@ -303,16 +379,18 @@
303379
BLOB_APPEND_LITERAL(ob, " <tr>\n");
304380
BLOB_APPEND_BLOB(ob, cells);
305381
BLOB_APPEND_LITERAL(ob, " </tr>\n");
306382
}
307383
308
-
309
-
310384
/* HTML span tags */
311
-
312385
static int html_raw_html_tag(struct Blob *ob, struct Blob *text, void *opaque){
313
- blob_append(ob, blob_buffer(text), blob_size(text));
386
+ if( html_control_comment(ob,text,opaque) ){
387
+ /* No-op */
388
+ }else{
389
+ /* Everything else is passed through without change */
390
+ blob_append(ob, blob_buffer(text), blob_size(text));
391
+ }
314392
return 1;
315393
}
316394
317395
static int html_autolink(
318396
struct Blob *ob,
@@ -579,12 +657,18 @@
579657
/* misc. parameters */
580658
"*_", /* emph_chars */
581659
0 /* opaque */
582660
};
583661
MarkdownToHtml context;
662
+ MarkdownHeading *pHdng, *pNextHdng;
663
+
584664
memset(&context, 0, sizeof(context));
585665
context.output_title = output_title;
586666
html_renderer.opaque = &context;
587667
if( output_title ) blob_reset(output_title);
588668
blob_reset(output_body);
589669
markdown(output_body, input_markdown, &html_renderer);
670
+ for(pHdng=context.pFirst; pHdng; pHdng=pNextHdng){
671
+ pNextHdng = pHdng->pNext;
672
+ fossil_free(pHdng);
673
+ }
590674
}
591675
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -29,17 +29,33 @@
29 struct Blob *output_title,
30 struct Blob *output_body);
31
32 #endif /* INTERFACE */
33
 
 
 
 
 
 
 
 
 
 
 
34 /*
35 ** An instance of the following structure is passed through the
36 ** "opaque" pointer.
37 */
38 typedef struct MarkdownToHtml MarkdownToHtml;
39 struct MarkdownToHtml {
40 Blob *output_title; /* Store the title here */
 
 
 
 
 
41 };
42
43
44 /* INTER_BLOCK -- skip a line between block level elements */
45 #define INTER_BLOCK(ob) \
@@ -137,15 +153,64 @@
137
138 static void html_epilog(struct Blob *ob, void *opaque){
139 INTER_BLOCK(ob);
140 BLOB_APPEND_LITERAL(ob, "</div>\n");
141 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
143 static void html_blockhtml(struct Blob *ob, struct Blob *text, void *opaque){
144 char *data = blob_buffer(text);
145 size_t size = blob_size(text);
146 Blob *title = ((MarkdownToHtml*)opaque)->output_title;
 
147 while( size>0 && fossil_isspace(data[0]) ){ data++; size--; }
148 while( size>0 && fossil_isspace(data[size-1]) ){ size--; }
149 /* If the first raw block is an <h1> element, then use it as the title. */
150 if( blob_size(ob)<=PROLOG_SIZE
151 && size>9
@@ -180,19 +245,30 @@
180 struct Blob *ob,
181 struct Blob *text,
182 int level,
183 void *opaque
184 ){
185 struct Blob *title = ((MarkdownToHtml*)opaque)->output_title;
 
186 /* The first header at the beginning of a text is considered as
187 * a title and not output. */
188 if( blob_size(ob)<=PROLOG_SIZE && title!=0 && blob_size(title)==0 ){
189 BLOB_APPEND_BLOB(title, text);
190 return;
191 }
192 INTER_BLOCK(ob);
193 blob_appendf(ob, "<h%d>", level);
 
 
 
 
 
 
 
 
 
 
194 BLOB_APPEND_BLOB(ob, text);
195 blob_appendf(ob, "</h%d>", level);
196 }
197
198 static void html_hrule(struct Blob *ob, void *opaque){
@@ -303,16 +379,18 @@
303 BLOB_APPEND_LITERAL(ob, " <tr>\n");
304 BLOB_APPEND_BLOB(ob, cells);
305 BLOB_APPEND_LITERAL(ob, " </tr>\n");
306 }
307
308
309
310 /* HTML span tags */
311
312 static int html_raw_html_tag(struct Blob *ob, struct Blob *text, void *opaque){
313 blob_append(ob, blob_buffer(text), blob_size(text));
 
 
 
 
 
314 return 1;
315 }
316
317 static int html_autolink(
318 struct Blob *ob,
@@ -579,12 +657,18 @@
579 /* misc. parameters */
580 "*_", /* emph_chars */
581 0 /* opaque */
582 };
583 MarkdownToHtml context;
 
 
584 memset(&context, 0, sizeof(context));
585 context.output_title = output_title;
586 html_renderer.opaque = &context;
587 if( output_title ) blob_reset(output_title);
588 blob_reset(output_body);
589 markdown(output_body, input_markdown, &html_renderer);
 
 
 
 
590 }
591
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -29,17 +29,33 @@
29 struct Blob *output_title,
30 struct Blob *output_body);
31
32 #endif /* INTERFACE */
33
34 /*
35 ** Each heading is recorded as an instance of the following
36 ** structure, in its own separate memory allocation.
37 */
38 typedef struct MarkdownHeading MarkdownHeading;
39 struct MarkdownHeading {
40 MarkdownHeading *pPrev, *pNext; /* List of them all */
41 char *zTitle; /* Text as displayed */
42 char *zTag; /* Pandoc-style tag */
43 };
44
45 /*
46 ** An instance of the following structure is passed through the
47 ** "opaque" pointer.
48 */
49 typedef struct MarkdownToHtml MarkdownToHtml;
50 struct MarkdownToHtml {
51 Blob *output_title; /* Store the title here */
52 MarkdownHeading *pFirst, *pList; /* List of all headings */
53 int iToc; /* Where to insert table-of-contents */
54 int mxToc; /* Maximum table-of-content level */
55 int iHdngNums; /* True to automatically number headings */
56 int aNum[6]; /* Most recent number at each level */
57 };
58
59
60 /* INTER_BLOCK -- skip a line between block level elements */
61 #define INTER_BLOCK(ob) \
@@ -137,15 +153,64 @@
153
154 static void html_epilog(struct Blob *ob, void *opaque){
155 INTER_BLOCK(ob);
156 BLOB_APPEND_LITERAL(ob, "</div>\n");
157 }
158
159 /*
160 ** If text is an HTML control comment, then deal with it and return true.
161 ** Otherwise just return false without making any changes.
162 **
163 ** We are looking for comments of the following form:
164 **
165 ** <!--markdown: toc=N -->
166 ** <!--markdown: paragraph-numbers=on -->
167 ** <!--markdown: paragraph-numbers=N -->
168 **
169 ** In the paragraph-numbers=N form with N>1, N-th level headings are
170 ** numbered like top-levels. N+1-th level headings are like 2nd levels.
171 ** and so forth.
172 **
173 ** In the toc=N form, a table of contents is generated for all headings
174 ** less than or equal to leve N.
175 */
176 static int html_control_comment(Blob *ob, Blob *text, void *opaque){
177 Blob token, arg;
178 MarkdownToHtml *pCtx;
179 if( blob_size(text)<20 ) return 0;
180 if( strncmp(blob_buffer(text),"<!--markdown:",13)!=0 ) return 0;
181 pCtx = (MarkdownToHtml*)opaque;
182 blob_seek(text, 13, BLOB_SEEK_SET);
183 blob_init(&token, 0, 0);
184 blob_init(&arg, 0, 0);
185 while( blob_argument_token(text, &token, 0) ){
186 if( blob_eq_str(&token, "toc", 3) && blob_argument_token(text, &arg, 1) ){
187 pCtx->iToc = blob_size(ob);
188 pCtx->mxToc = atoi(blob_str(&arg));
189 blob_reset(&arg);
190 }else
191 if( blob_eq_str(&token,"paragraph-numbers",-1)
192 && blob_argument_token(text,&arg,1)
193 ){
194 char *zArg = blob_str(&arg);
195 pCtx->iHdngNums = fossil_isdigit(zArg[0]) ? atoi(zArg) : is_truth(zArg);
196 blob_reset(&arg);
197 }else
198 if( !blob_eq_str(&token,"-->",3) ){
199 blob_appendf(ob, "<!--markdown: unknown-tag=\"%h\" -->",
200 blob_str(&token));
201 }
202 blob_reset(&token);
203 }
204 return 1;
205 }
206
207 static void html_blockhtml(struct Blob *ob, struct Blob *text, void *opaque){
208 char *data = blob_buffer(text);
209 size_t size = blob_size(text);
210 Blob *title = ((MarkdownToHtml*)opaque)->output_title;
211 if( html_control_comment(ob,text,opaque) ) return;
212 while( size>0 && fossil_isspace(data[0]) ){ data++; size--; }
213 while( size>0 && fossil_isspace(data[size-1]) ){ size--; }
214 /* If the first raw block is an <h1> element, then use it as the title. */
215 if( blob_size(ob)<=PROLOG_SIZE
216 && size>9
@@ -180,19 +245,30 @@
245 struct Blob *ob,
246 struct Blob *text,
247 int level,
248 void *opaque
249 ){
250 MarkdownToHtml *pCtx = (MarkdownToHtml*)opaque;
251 struct Blob *title = pCtx->output_title;
252 /* The first header at the beginning of a text is considered as
253 * a title and not output. */
254 if( blob_size(ob)<=PROLOG_SIZE && title!=0 && blob_size(title)==0 ){
255 BLOB_APPEND_BLOB(title, text);
256 return;
257 }
258 INTER_BLOCK(ob);
259 blob_appendf(ob, "<h%d>", level);
260 if( pCtx->iHdngNums && level>=pCtx->iHdngNums ){
261 int i;
262 for(i=pCtx->iHdngNums-1; i<level-1; i++){
263 blob_appendf(ob,"%d.",pCtx->aNum[i]);
264 }
265 blob_appendf(ob,"%d", ++pCtx->aNum[i]);
266 if( i==pCtx->iHdngNums-1 ) blob_append(ob, ".0", 2);
267 blob_append(ob, " ", 1);
268 for(i++; i<6; i++) pCtx->aNum[i] = 0;
269 }
270 BLOB_APPEND_BLOB(ob, text);
271 blob_appendf(ob, "</h%d>", level);
272 }
273
274 static void html_hrule(struct Blob *ob, void *opaque){
@@ -303,16 +379,18 @@
379 BLOB_APPEND_LITERAL(ob, " <tr>\n");
380 BLOB_APPEND_BLOB(ob, cells);
381 BLOB_APPEND_LITERAL(ob, " </tr>\n");
382 }
383
 
 
384 /* HTML span tags */
 
385 static int html_raw_html_tag(struct Blob *ob, struct Blob *text, void *opaque){
386 if( html_control_comment(ob,text,opaque) ){
387 /* No-op */
388 }else{
389 /* Everything else is passed through without change */
390 blob_append(ob, blob_buffer(text), blob_size(text));
391 }
392 return 1;
393 }
394
395 static int html_autolink(
396 struct Blob *ob,
@@ -579,12 +657,18 @@
657 /* misc. parameters */
658 "*_", /* emph_chars */
659 0 /* opaque */
660 };
661 MarkdownToHtml context;
662 MarkdownHeading *pHdng, *pNextHdng;
663
664 memset(&context, 0, sizeof(context));
665 context.output_title = output_title;
666 html_renderer.opaque = &context;
667 if( output_title ) blob_reset(output_title);
668 blob_reset(output_body);
669 markdown(output_body, input_markdown, &html_renderer);
670 for(pHdng=context.pFirst; pHdng; pHdng=pNextHdng){
671 pNextHdng = pHdng->pNext;
672 fossil_free(pHdng);
673 }
674 }
675

Keyboard Shortcuts

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