Fossil SCM
Further refine the fenced code block rendering in markdown to try to comply with the CommonMark spec.
Commit
81caad6ce6bc412c80b0d1221ca500caad39af5da205dc679025e6233a447b26
Parent
2077ffe660ec2bc…
1 file changed
+36
-4
+36
-4
| --- src/markdown_html.c | ||
| +++ src/markdown_html.c | ||
| @@ -325,20 +325,52 @@ | ||
| 325 | 325 | } |
| 326 | 326 | BLOB_APPEND_LITERAL(ob, "</a>"); |
| 327 | 327 | return 1; |
| 328 | 328 | } |
| 329 | 329 | |
| 330 | +/* Invoked for `...` blocks where there are nSep grave accents in a | |
| 331 | +** row that serve as the delimiter. According to CommonMark: | |
| 332 | +** | |
| 333 | +** * https://spec.commonmark.org/0.29/#fenced-code-blocks | |
| 334 | +** * https://spec.commonmark.org/0.29/#code-spans | |
| 335 | +** | |
| 336 | +** If nSep is 1 or 2, then this is a code-span which is inline. | |
| 337 | +** If nSep is 3 or more, then this is a fenced code block | |
| 338 | +*/ | |
| 330 | 339 | static int html_code_span( |
| 331 | - struct Blob *ob, | |
| 340 | + struct Blob *ob, /* Write the output here */ | |
| 332 | 341 | struct Blob *text, /* The stuff in between the code span marks */ |
| 333 | 342 | int nSep, /* Number of grave accents marks as delimiters */ |
| 334 | 343 | void *opaque |
| 335 | 344 | ){ |
| 336 | - if( text ){ | |
| 337 | - blob_append(ob, nSep>=3 ? "<pre>" : "<code>", -1); | |
| 345 | + if( text==0 ){ | |
| 346 | + /* no-op */ | |
| 347 | + }else if( nSep<=2 ){ | |
| 348 | + /* One or two graves: an in-line code span */ | |
| 349 | + BLOB_APPEND_LITERAL(ob, "<code>"); | |
| 338 | 350 | html_escape(ob, blob_buffer(text), blob_size(text)); |
| 339 | - blob_append(ob, nSep>=3 ? "</pre>" : "</code>", -1); | |
| 351 | + BLOB_APPEND_LITERAL(ob, "</code>"); | |
| 352 | + }else{ | |
| 353 | + /* Three or more graves: a fenced code block */ | |
| 354 | + int n = blob_size(text); | |
| 355 | + const char *z = blob_buffer(text); | |
| 356 | + int i; | |
| 357 | + for(i=0; i<n && z[i]!='\n'; i++){} | |
| 358 | + if( i>=n ){ | |
| 359 | + blob_appendf(ob, "<pre><code>%.*s</code></pre>", n, z); | |
| 360 | + }else{ | |
| 361 | + int k, j; | |
| 362 | + i++; | |
| 363 | + for(k=0; k<i && fossil_isspace(z[k]); k++){} | |
| 364 | + if( k==i ){ | |
| 365 | + blob_appendf(ob, "<pre><code>%.*s</code></pre>", n-i, z+i); | |
| 366 | + }else{ | |
| 367 | + for(j=k+1; j<i && !fossil_isspace(z[j]); j++){} | |
| 368 | + blob_appendf(ob, "<pre><code class='language-%#h'>%.*s</code></pre>", | |
| 369 | + j-k, z+k, n-i, z+i); | |
| 370 | + } | |
| 371 | + } | |
| 340 | 372 | } |
| 341 | 373 | return 1; |
| 342 | 374 | } |
| 343 | 375 | |
| 344 | 376 | static int html_double_emphasis( |
| 345 | 377 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -325,20 +325,52 @@ | |
| 325 | } |
| 326 | BLOB_APPEND_LITERAL(ob, "</a>"); |
| 327 | return 1; |
| 328 | } |
| 329 | |
| 330 | static int html_code_span( |
| 331 | struct Blob *ob, |
| 332 | struct Blob *text, /* The stuff in between the code span marks */ |
| 333 | int nSep, /* Number of grave accents marks as delimiters */ |
| 334 | void *opaque |
| 335 | ){ |
| 336 | if( text ){ |
| 337 | blob_append(ob, nSep>=3 ? "<pre>" : "<code>", -1); |
| 338 | html_escape(ob, blob_buffer(text), blob_size(text)); |
| 339 | blob_append(ob, nSep>=3 ? "</pre>" : "</code>", -1); |
| 340 | } |
| 341 | return 1; |
| 342 | } |
| 343 | |
| 344 | static int html_double_emphasis( |
| 345 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -325,20 +325,52 @@ | |
| 325 | } |
| 326 | BLOB_APPEND_LITERAL(ob, "</a>"); |
| 327 | return 1; |
| 328 | } |
| 329 | |
| 330 | /* Invoked for `...` blocks where there are nSep grave accents in a |
| 331 | ** row that serve as the delimiter. According to CommonMark: |
| 332 | ** |
| 333 | ** * https://spec.commonmark.org/0.29/#fenced-code-blocks |
| 334 | ** * https://spec.commonmark.org/0.29/#code-spans |
| 335 | ** |
| 336 | ** If nSep is 1 or 2, then this is a code-span which is inline. |
| 337 | ** If nSep is 3 or more, then this is a fenced code block |
| 338 | */ |
| 339 | static int html_code_span( |
| 340 | struct Blob *ob, /* Write the output here */ |
| 341 | struct Blob *text, /* The stuff in between the code span marks */ |
| 342 | int nSep, /* Number of grave accents marks as delimiters */ |
| 343 | void *opaque |
| 344 | ){ |
| 345 | if( text==0 ){ |
| 346 | /* no-op */ |
| 347 | }else if( nSep<=2 ){ |
| 348 | /* One or two graves: an in-line code span */ |
| 349 | BLOB_APPEND_LITERAL(ob, "<code>"); |
| 350 | html_escape(ob, blob_buffer(text), blob_size(text)); |
| 351 | BLOB_APPEND_LITERAL(ob, "</code>"); |
| 352 | }else{ |
| 353 | /* Three or more graves: a fenced code block */ |
| 354 | int n = blob_size(text); |
| 355 | const char *z = blob_buffer(text); |
| 356 | int i; |
| 357 | for(i=0; i<n && z[i]!='\n'; i++){} |
| 358 | if( i>=n ){ |
| 359 | blob_appendf(ob, "<pre><code>%.*s</code></pre>", n, z); |
| 360 | }else{ |
| 361 | int k, j; |
| 362 | i++; |
| 363 | for(k=0; k<i && fossil_isspace(z[k]); k++){} |
| 364 | if( k==i ){ |
| 365 | blob_appendf(ob, "<pre><code>%.*s</code></pre>", n-i, z+i); |
| 366 | }else{ |
| 367 | for(j=k+1; j<i && !fossil_isspace(z[j]); j++){} |
| 368 | blob_appendf(ob, "<pre><code class='language-%#h'>%.*s</code></pre>", |
| 369 | j-k, z+k, n-i, z+i); |
| 370 | } |
| 371 | } |
| 372 | } |
| 373 | return 1; |
| 374 | } |
| 375 | |
| 376 | static int html_double_emphasis( |
| 377 |