Fossil

Check-in [28e6a9cd]
Login

Check-in [28e6a9cd]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Handle misreferences: a reference to undefined footnote.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | markdown-footnotes
Files: files | file ages | folders
SHA3-256: 28e6a9cd1355bb58d8644842e3906cbb2b6be171848d495f427b1bb9b103870b
User & Date: george 2022-02-04 23:07:54
Context
2022-02-06
22:53
Handle misreferences more thoroughly. Implement support of footnotes-within-footnotes with (hopefully) proper crosslinking (that's where it's getting tricky). ... (check-in: 1787f6df user: george tags: markdown-footnotes)
2022-02-04
23:07
Handle misreferences: a reference to undefined footnote. ... (check-in: 28e6a9cd user: george tags: markdown-footnotes)
19:47
Minor code refactoring. ... (check-in: 2636e224 user: george tags: markdown-footnotes)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/default.css.

1678
1679
1680
1681
1682
1683
1684




1685
1686
1687
1688
1689
1690
1691
  font-weight: bold;
}
div.markdown > ol.footnotes > li > .footnote-backrefs > a:target {
  background: gold;
}
div.markdown sup > a.noteref:target {
  background: gold;




}
div.markdown span.notescope:hover,
div.markdown span.notescope:target {
  border-bottom: 2px solid gold;
}
div.markdown span.notescope:hover  > sup > a.noteref,
div.markdown span.notescope:target > sup > a.noteref {







>
>
>
>







1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
  font-weight: bold;
}
div.markdown > ol.footnotes > li > .footnote-backrefs > a:target {
  background: gold;
}
div.markdown sup > a.noteref:target {
  background: gold;
}
div.markdown sup.misref {
  color: red;
  font-size: 90%;
}
div.markdown span.notescope:hover,
div.markdown span.notescope:target {
  border-bottom: 2px solid gold;
}
div.markdown span.notescope:hover  > sup > a.noteref,
div.markdown span.notescope:target > sup > a.noteref {

Changes to src/markdown.c.

172
173
174
175
176
177
178
179


180
181
182
183
184
185
186
  int iDepth;                    /* Depth of recursion */
  int nBlobCache;                /* Number of entries in aBlobCache */
  struct Blob *aBlobCache[20];   /* Cache of Blobs available for reuse */

  struct {
    Blob all;    /* array of footnotes */
    int nLbled;  /* number of labeled footnotes found during the first pass */
    int nMarks;  /* count distinct indices found in the second pass */


  } notes;
};

/* html_tag -- structure for quick HTML tag search (inspired from discount) */
struct html_tag {
  const char *text;
  int size;







|
>
>







172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  int iDepth;                    /* Depth of recursion */
  int nBlobCache;                /* Number of entries in aBlobCache */
  struct Blob *aBlobCache[20];   /* Cache of Blobs available for reuse */

  struct {
    Blob all;    /* array of footnotes */
    int nLbled;  /* number of labeled footnotes found during the first pass */
    int nMarks;  /* counts distinct indices found during the second pass */
    struct footnote missing; /* a dummy footnote, its negative index
                                counts missing refs */
  } notes;
};

/* html_tag -- structure for quick HTML tag search (inspired from discount) */
struct html_tag {
  const char *text;
  int size;
206
207
208
209
210
211
212

213
214
215
216
217
218
219


/***************************
 * STATIC HELPER FUNCTIONS *
 ***************************/

/* build_ref_id -- collapse whitespace from input text to make it a ref id */

static int build_ref_id(struct Blob *id, const char *data, size_t size){
  size_t beg, i;
  char *id_data;

  /* skip leading whitespace */
  while( size>0 && (data[0]==' ' || data[0]=='\t' || data[0]=='\n') ){
    data++;







>







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222


/***************************
 * STATIC HELPER FUNCTIONS *
 ***************************/

/* build_ref_id -- collapse whitespace from input text to make it a ref id */
/* FIXME: does this function handle non-Unix newlines? */
static int build_ref_id(struct Blob *id, const char *data, size_t size){
  size_t beg, i;
  char *id_data;

  /* skip leading whitespace */
  while( size>0 && (data[0]==' ' || data[0]=='\t' || data[0]=='\n') ){
    data++;
1219
1220
1221
1222
1223
1224
1225
1226



1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238



1239
1240
1241
1242
1243
1244
1245
        id_data++;
        id_size--;
      }
    }

    if( bFootnote ){
      fn = get_footnote(rndr, id_data, id_size);
      if( !fn ) goto char_link_cleanup;



    }else if( get_link_ref(rndr, link, title, id_data, id_size)<0 ){
      goto char_link_cleanup;
    }

    i = id_end+1;

  /* shortcut reference style link or free-standing footnote refernece */
  }else{
    if(!is_img && size>3 && data[1]=='^'){
      /* free-standing footnote reference */
      fn = get_footnote(rndr, data+2, txt_e-2);
      if( !fn ) goto char_link_cleanup;



      release_work_buffer(rndr, content);
      content = 0; 
    }else if( get_link_ref(rndr, link, title, data+1, txt_e-1)<0 ){
      goto char_link_cleanup;
    }

    /* rewinding a closing square bracket */







|
>
>
>











|
>
>
>







1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
        id_data++;
        id_size--;
      }
    }

    if( bFootnote ){
      fn = get_footnote(rndr, id_data, id_size);
      if( !fn ) {
        rndr->notes.missing.index--;
        fn = &rndr->notes.missing;
      }
    }else if( get_link_ref(rndr, link, title, id_data, id_size)<0 ){
      goto char_link_cleanup;
    }

    i = id_end+1;

  /* shortcut reference style link or free-standing footnote refernece */
  }else{
    if(!is_img && size>3 && data[1]=='^'){
      /* free-standing footnote reference */
      fn = get_footnote(rndr, data+2, txt_e-2);
      if( !fn ) {
        rndr->notes.missing.index--;
        fn = &rndr->notes.missing;
      }
      release_work_buffer(rndr, content);
      content = 0; 
    }else if( get_link_ref(rndr, link, title, data+1, txt_e-1)<0 ){
      goto char_link_cleanup;
    }

    /* rewinding a closing square bracket */
2455
2456
2457
2458
2459
2460
2461





2462
2463
2464
2465
2466
2467
2468
  if( !rndrer ) return;
  rndr.make = *rndrer;
  rndr.nBlobCache = 0;
  rndr.iDepth = 0;
  rndr.refs  = empty_blob;
  rndr.notes.all = empty_blob;
  rndr.notes.nMarks = 0;





  for(i=0; i<256; i++) rndr.active_char[i] = 0;
  if( (rndr.make.emphasis
    || rndr.make.double_emphasis
    || rndr.make.triple_emphasis)
   && rndr.make.emph_chars
  ){
    for(i=0; rndr.make.emph_chars[i]; i++){







>
>
>
>
>







2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
  if( !rndrer ) return;
  rndr.make = *rndrer;
  rndr.nBlobCache = 0;
  rndr.iDepth = 0;
  rndr.refs  = empty_blob;
  rndr.notes.all = empty_blob;
  rndr.notes.nMarks = 0;
  rndr.notes.missing.id    = empty_blob;
  rndr.notes.missing.text  = empty_blob;
  rndr.notes.missing.index = 0;
  rndr.notes.missing.nUsed = 0;

  for(i=0; i<256; i++) rndr.active_char[i] = 0;
  if( (rndr.make.emphasis
    || rndr.make.double_emphasis
    || rndr.make.triple_emphasis)
   && rndr.make.emph_chars
  ){
    for(i=0; rndr.make.emph_chars[i]; i++){

Changes to src/markdown_html.c.

326
327
328
329
330
331
332



333
334
335
336
337
338

339
340
341
342
343
344
345
346
347
348
349
350













351
352
353
354
355
356
357
  BLOB_APPEND_LITERAL(ob, "  </tr>\n");
}

static int html_footnote_ref(
  struct Blob *ob, const struct Blob *span, int index, int locus, void *opaque
){
  const struct MarkdownToHtml *ctx = (struct MarkdownToHtml*)opaque;



  const bitfield64_t l = to_base26(locus-1,0);
  char pos[32];

  /* expect BUGs if the following yields compiler warnings */
  memset(pos,0,32);
  sprintf(pos, "%s-%i-%s", ctx->unique.c, index, l.c);

  if(span && blob_size(span)) {
    BLOB_APPEND_LITERAL(ob,"<span class='notescope' id='noteref");
    blob_appendf(ob,"%s'>",pos);
    BLOB_APPEND_BLOB(ob, span);
    blob_trim(ob);
    BLOB_APPEND_LITERAL(ob,"<sup><a class='noteref' href='#footnote");
    blob_appendf(ob,"%s'>%i</a></sup></span>", pos, index);
  }else{
    blob_trim(ob);
    BLOB_APPEND_LITERAL(ob,"<sup><a class='noteref' href='#footnote");
    blob_appendf(ob,"%s' id='noteref%s'>%i</a></sup>",
                    pos,            pos,   index);













  }
  return 1;
}

/* Render a single item of the footnotes list.
 * Each backref gets a unique id to enable dynamic styling. */
static void html_footnote_item(







>
>
>
|
|
<
<
|
|
>
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>







326
327
328
329
330
331
332
333
334
335
336
337


338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
  BLOB_APPEND_LITERAL(ob, "  </tr>\n");
}

static int html_footnote_ref(
  struct Blob *ob, const struct Blob *span, int index, int locus, void *opaque
){
  const struct MarkdownToHtml *ctx = (struct MarkdownToHtml*)opaque;
  /* expect BUGs if the following yields compiler warnings */

  if( index>0 && locus>0 ){
    const bitfield64_t l = to_base26(locus-1,0);
    char pos[32];


    memset(pos,0,32);
    sprintf(pos, "%s-%i-%s", ctx->unique.c, index, l.c);

    if(span && blob_size(span)) {
      BLOB_APPEND_LITERAL(ob,"<span class='notescope' id='noteref");
      blob_appendf(ob,"%s'>",pos);
      BLOB_APPEND_BLOB(ob, span);
      blob_trim(ob);
      BLOB_APPEND_LITERAL(ob,"<sup><a class='noteref' href='#footnote");
      blob_appendf(ob,"%s'>%i</a></sup></span>", pos, index);
    }else{
      blob_trim(ob);
      BLOB_APPEND_LITERAL(ob,"<sup><a class='noteref' href='#footnote");
      blob_appendf(ob,"%s' id='noteref%s'>%i</a></sup>",
                      pos,            pos,   index);
    }
  }else if(span && blob_size(span)) {
    BLOB_APPEND_LITERAL(ob, "<span class='notescope' id='misref");
    blob_appendf(ob, "%s-%i'>", ctx->unique.c, -index);
    BLOB_APPEND_BLOB(ob, span);
    blob_trim(ob);
    BLOB_APPEND_LITERAL(ob,
          "<sup class='misref'>misreference</sup></span>");
  }else{
    blob_trim(ob);
    BLOB_APPEND_LITERAL(ob, "<sup class='misref' id='misref");
    blob_appendf(ob, "%s-%i", ctx->unique.c, -index);
    BLOB_APPEND_LITERAL(ob, "'>misreference</sup>");
  }
  return 1;
}

/* Render a single item of the footnotes list.
 * Each backref gets a unique id to enable dynamic styling. */
static void html_footnote_item(

Changes to test/markdown-test3.md.

1
2
3
4
5
6


7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

42

43
44
45
46
47
48
49




Markdown Footnotes Test Document
================================

This document should help with testing of footnotes support that
is introduced by the ["`markdown-footnotes`"][branch] branch.[^1]



Developers are invited to add test cases here[^here].
It is suggested that the more simple is a test case the earlier it should
appear in this document.[^ if glitch occurs	]

A footnote's label should be case insensitive[^ case INSENSITIVE ],
but may not contain newlines.[^broken

label]

A labeled footnote may be [referenced several times][^many-refs].

A footnote's text should support Markdown [markup][^].

Another reference[^many-refs] to the preveously used footnote.

Inline footnotes are supported.(^These may be usefull for adding
<s>small</s> comments.)






## Footnotes

[branch]: /timeline?t=markdown-footnotes

[^ 1]:  Footnotes is a Fossil' extention of
        Markdown. Your other tools may have limited support for these.

[^here]: [](/finfo/test/markdown-test3.md)

[^if glitch occurs]:
        So that simple cases are processed even if
        a glitch happens for more tricky cases.

[^	CASE	 insensitive  	]: And also tolerate whitespaces.


^[broken label]: This text should not render within a list of footnotes.



[^many-refs]:
   Each letter on the left is a back-reference to the place of use.
   Highlighted back-reference indicates a place from which navigation occurred.

[^markup]:   E.g. *emphasis*, and [so on](/md_rules).







|
|
>
>






|
>











>
>
>




|




|







>
|
>







>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

Markdown Footnotes Test Document
================================

**This document** should help with testing of footnotes support that
is introduced by the ["`markdown-footnotes`"][branch] branch.
It **might look pretty misformatted unless rendered by the proper Fossil
executable that incorporates the abovementioned branch.**[^1]

Developers are invited to add test cases here[^here].
It is suggested that the more simple is a test case the earlier it should
appear in this document.[^ if glitch occurs	]

A footnote's label should be case insensitive[^ case INSENSITIVE ],
it is whitespace-savvy and can even contain newlines.[^ a
multiline
label]

A labeled footnote may be [referenced several times][^many-refs].

A footnote's text should support Markdown [markup][^].

Another reference[^many-refs] to the preveously used footnote.

Inline footnotes are supported.(^These may be usefull for adding
<s>small</s> comments.)

If [undefined label is used][^] then red "`misreference`" is emited instead of
a numeric marker.[^ see it yourself ]
This can be overridden by the skin though.


## Footnotes

[branch]: /timeline?r=markdown-footnotes&nowiki

[^ 1]:  Footnotes is a Fossil' extention of
        Markdown. Your other tools may have limited support for these.

[^here]: [History of test/markdown-test3.md](/finfo/test/markdown-test3.md)

[^if glitch occurs]:
        So that simple cases are processed even if
        a glitch happens for more tricky cases.

[^	CASE	 insensitive  	]: And also tolerate whitespaces.

[^ a multiline label ]: But at a footnote's definition it should still
    be written within square brackets
             on a single line.


[^many-refs]:
   Each letter on the left is a back-reference to the place of use.
   Highlighted back-reference indicates a place from which navigation occurred.

[^markup]:   E.g. *emphasis*, and [so on](/md_rules).

[^undefined label is used]: For example due to a typo.