Fossil SCM

Attempt to add IDs to headers in markdown, the same way that GitHub does. Needs additional testing to confirm that unusual characters in headers are handled reasonably.

drh 2026-01-12 18:55 trunk
Commit 21cbb8c467a1a360490e69292b135e02123cd171183c78bd7fdae58aadf87cae
1 file changed +24 -1
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -216,20 +216,43 @@
216216
struct Blob *text,
217217
int level,
218218
void *opaque
219219
){
220220
struct Blob *title = ((MarkdownToHtml*)opaque)->output_title;
221
+ char *z = 0;
222
+ int i,j;
221223
/* The first header at the beginning of a text is considered as
222224
* a title and not output. */
223225
if( blob_size(ob)<=PROLOG_SIZE && title!=0 && blob_size(title)==0 ){
224226
blob_appendb(title, text);
225227
return;
226228
}
227229
INTER_BLOCK(ob);
228
- blob_appendf(ob, "<h%d>", level);
230
+ z = fossil_strdup(blob_buffer(text));
231
+ if( z==0 ){
232
+ j = 0;
233
+ }else{
234
+ for(i=j=0; z[i]; i++){
235
+ if( fossil_isalnum(z[i]) ){
236
+ z[j++] = fossil_tolower(z[i]);
237
+ }else if( fossil_isspace(z[i]) && j>0 && fossil_isalnum(z[j-1]) ){
238
+ z[j++] = '-';
239
+ }else if( z[i]=='<' ){
240
+ do{ i++; }while( z[i]!=0 && z[i]!='>' );
241
+ }
242
+ }
243
+ if( j>0 && z[j-1]=='-' ) j--;
244
+ z[j] = 0;
245
+ }
246
+ if( j>0 ){
247
+ blob_appendf(ob, "<h%d id=\"%s\">", level, z);
248
+ }else{
249
+ blob_appendf(ob, "<h%d>", level);
250
+ }
229251
blob_appendb(ob, text);
230252
blob_appendf(ob, "</h%d>", level);
253
+ fossil_free(z);
231254
}
232255
233256
static void html_hrule(struct Blob *ob, void *opaque){
234257
INTER_BLOCK(ob);
235258
blob_append_literal(ob, "<hr>\n");
236259
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -216,20 +216,43 @@
216 struct Blob *text,
217 int level,
218 void *opaque
219 ){
220 struct Blob *title = ((MarkdownToHtml*)opaque)->output_title;
 
 
221 /* The first header at the beginning of a text is considered as
222 * a title and not output. */
223 if( blob_size(ob)<=PROLOG_SIZE && title!=0 && blob_size(title)==0 ){
224 blob_appendb(title, text);
225 return;
226 }
227 INTER_BLOCK(ob);
228 blob_appendf(ob, "<h%d>", level);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229 blob_appendb(ob, text);
230 blob_appendf(ob, "</h%d>", level);
 
231 }
232
233 static void html_hrule(struct Blob *ob, void *opaque){
234 INTER_BLOCK(ob);
235 blob_append_literal(ob, "<hr>\n");
236
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -216,20 +216,43 @@
216 struct Blob *text,
217 int level,
218 void *opaque
219 ){
220 struct Blob *title = ((MarkdownToHtml*)opaque)->output_title;
221 char *z = 0;
222 int i,j;
223 /* The first header at the beginning of a text is considered as
224 * a title and not output. */
225 if( blob_size(ob)<=PROLOG_SIZE && title!=0 && blob_size(title)==0 ){
226 blob_appendb(title, text);
227 return;
228 }
229 INTER_BLOCK(ob);
230 z = fossil_strdup(blob_buffer(text));
231 if( z==0 ){
232 j = 0;
233 }else{
234 for(i=j=0; z[i]; i++){
235 if( fossil_isalnum(z[i]) ){
236 z[j++] = fossil_tolower(z[i]);
237 }else if( fossil_isspace(z[i]) && j>0 && fossil_isalnum(z[j-1]) ){
238 z[j++] = '-';
239 }else if( z[i]=='<' ){
240 do{ i++; }while( z[i]!=0 && z[i]!='>' );
241 }
242 }
243 if( j>0 && z[j-1]=='-' ) j--;
244 z[j] = 0;
245 }
246 if( j>0 ){
247 blob_appendf(ob, "<h%d id=\"%s\">", level, z);
248 }else{
249 blob_appendf(ob, "<h%d>", level);
250 }
251 blob_appendb(ob, text);
252 blob_appendf(ob, "</h%d>", level);
253 fossil_free(z);
254 }
255
256 static void html_hrule(struct Blob *ob, void *opaque){
257 INTER_BLOCK(ob);
258 blob_append_literal(ob, "<hr>\n");
259

Keyboard Shortcuts

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