Skip to content

Commit 1aabfa3

Browse files
committed
Merge branch 'footnotes-fix-fnref-label-and-backrefs' into all-footnote-fixes
2 parents c464de3 + 8ccdaa7 commit 1aabfa3

File tree

6 files changed

+93
-34
lines changed

6 files changed

+93
-34
lines changed

src/blocks.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,17 @@ static void process_footnotes(cmark_parser *parser) {
484484
if (!footnote->ix)
485485
footnote->ix = ++ix;
486486

487+
// keep track of a) how many times this footnote def has been
488+
// referenced, and b) which reference count this footnote ref is at
489+
// this is used by renderers when generating links and backreferences.
490+
cur->footnote.ix = ++footnote->node->footnote.count;
491+
492+
// store the footnote reference text label in the footnote ref's node's
493+
// `user_data`, so that renderers can use the label when generating
494+
// links and backreferences.
495+
cur->user_data = parser->mem->calloc(1, (sizeof(char) * cur->as.literal.len) + 1);
496+
memmove(cur->user_data, cur->as.literal.data, cur->as.literal.len);
497+
487498
char n[32];
488499
snprintf(n, sizeof(n), "%d", footnote->ix);
489500
cmark_chunk_free(parser->mem, &cur->as.literal);

src/commonmark.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
477477
case CMARK_NODE_FOOTNOTE_REFERENCE:
478478
if (entering) {
479479
LIT("[^");
480-
OUT(cmark_chunk_to_cstr(renderer->mem, &node->as.literal), false, LITERAL);
480+
OUT(node->user_data, false, LITERAL);
481481
LIT("]");
482482
}
483483
break;
@@ -486,9 +486,11 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
486486
if (entering) {
487487
renderer->footnote_ix += 1;
488488
LIT("[^");
489-
char n[32];
490-
snprintf(n, sizeof(n), "%d", renderer->footnote_ix);
491-
OUT(n, false, LITERAL);
489+
490+
char *str = renderer->mem->calloc(1, (sizeof(char) * node->as.literal.len) + 1);
491+
memmove(str, node->as.literal.data, node->as.literal.len);
492+
493+
OUT(str, false, LITERAL);
492494
LIT("]:\n");
493495

494496
cmark_strbuf_puts(renderer->prefix, " ");

src/html.c

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,31 @@ static void filter_html_block(cmark_html_renderer *renderer, uint8_t *data, size
5959
cmark_strbuf_put(html, data, (bufsize_t)len);
6060
}
6161

62-
static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_strbuf *html) {
62+
static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_strbuf *html, cmark_node *node) {
6363
if (renderer->written_footnote_ix >= renderer->footnote_ix)
6464
return false;
6565
renderer->written_footnote_ix = renderer->footnote_ix;
6666

67-
cmark_strbuf_puts(html, "<a href=\"#fnref");
68-
char n[32];
69-
snprintf(n, sizeof(n), "%d", renderer->footnote_ix);
70-
cmark_strbuf_puts(html, n);
67+
cmark_strbuf_puts(html, "<a href=\"#fnref:");
68+
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
7169
cmark_strbuf_puts(html, "\" class=\"footnote-backref\">↩</a>");
7270

71+
if (node->footnote.count > 1)
72+
{
73+
for(int i = 2; i <= node->footnote.count; i++) {
74+
char n[32];
75+
snprintf(n, sizeof(n), "%d", i);
76+
77+
cmark_strbuf_puts(html, " <a href=\"#fnref:");
78+
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
79+
cmark_strbuf_puts(html, ":");
80+
cmark_strbuf_put(html, (const unsigned char *)n, strlen(n));
81+
cmark_strbuf_puts(html, "\" class=\"footnote-backref\">↩<sup class=\"footnote-ref\">");
82+
cmark_strbuf_put(html, (const unsigned char *)n, strlen(n));
83+
cmark_strbuf_puts(html, "</sup></a>");
84+
}
85+
}
86+
7387
return true;
7488
}
7589

@@ -273,7 +287,7 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
273287
} else {
274288
if (parent->type == CMARK_NODE_FOOTNOTE_DEFINITION && node->next == NULL) {
275289
cmark_strbuf_putc(html, ' ');
276-
S_put_footnote_backref(renderer, html);
290+
S_put_footnote_backref(renderer, html, parent);
277291
}
278292
cmark_strbuf_puts(html, "</p>\n");
279293
}
@@ -395,13 +409,12 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
395409
cmark_strbuf_puts(html, "<section class=\"footnotes\">\n<ol>\n");
396410
}
397411
++renderer->footnote_ix;
398-
cmark_strbuf_puts(html, "<li id=\"fn");
399-
char n[32];
400-
snprintf(n, sizeof(n), "%d", renderer->footnote_ix);
401-
cmark_strbuf_puts(html, n);
412+
413+
cmark_strbuf_puts(html, "<li id=\"fn:");
414+
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
402415
cmark_strbuf_puts(html, "\">\n");
403416
} else {
404-
if (S_put_footnote_backref(renderer, html)) {
417+
if (S_put_footnote_backref(renderer, html, node)) {
405418
cmark_strbuf_putc(html, '\n');
406419
}
407420
cmark_strbuf_puts(html, "</li>\n");
@@ -410,10 +423,18 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
410423

411424
case CMARK_NODE_FOOTNOTE_REFERENCE:
412425
if (entering) {
413-
cmark_strbuf_puts(html, "<sup class=\"footnote-ref\"><a href=\"#fn");
414-
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
415-
cmark_strbuf_puts(html, "\" id=\"fnref");
416-
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
426+
cmark_strbuf_puts(html, "<sup class=\"footnote-ref\"><a href=\"#fn:");
427+
cmark_strbuf_puts(html, node->user_data);
428+
cmark_strbuf_puts(html, "\" id=\"fnref:");
429+
cmark_strbuf_puts(html, node->user_data);
430+
431+
if (node->footnote.ix > 1) {
432+
char n[32];
433+
snprintf(n, sizeof(n), "%d", node->footnote.ix);
434+
cmark_strbuf_puts(html, ":");
435+
cmark_strbuf_put(html, (const unsigned char *)n, strlen(n));
436+
}
437+
417438
cmark_strbuf_puts(html, "\">");
418439
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
419440
cmark_strbuf_puts(html, "</a></sup>");

src/node.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ struct cmark_node {
7676

7777
cmark_syntax_extension *extension;
7878

79+
union {
80+
int ix;
81+
int count;
82+
} footnote;
83+
7984
union {
8085
cmark_chunk literal;
8186
cmark_list list;

test/extensions.txt

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -672,31 +672,51 @@ Hi!
672672

673673
[^unused]: This is unused.
674674
.
675-
<p>This is some text!<sup class="footnote-ref"><a href="#fn1" id="fnref1">1</a></sup>. Other text.<sup class="footnote-ref"><a href="#fn2" id="fnref2">2</a></sup>.</p>
676-
<p>Here's a thing<sup class="footnote-ref"><a href="#fn3" id="fnref3">3</a></sup>.</p>
677-
<p>And another thing<sup class="footnote-ref"><a href="#fn4" id="fnref4">4</a></sup>.</p>
675+
<p>This is some text!<sup class="footnote-ref"><a href="#fn:1" id="fnref:1">1</a></sup>. Other text.<sup class="footnote-ref"><a href="#fn:footnote" id="fnref:footnote">2</a></sup>.</p>
676+
<p>Here's a thing<sup class="footnote-ref"><a href="#fn:other-note" id="fnref:other-note">3</a></sup>.</p>
677+
<p>And another thing<sup class="footnote-ref"><a href="#fn:codeblock-note" id="fnref:codeblock-note">4</a></sup>.</p>
678678
<p>This doesn't have a referent[^nope].</p>
679679
<p>Hi!</p>
680680
<section class="footnotes">
681681
<ol>
682-
<li id="fn1">
683-
<p>Some <em>bolded</em> footnote definition. <a href="#fnref1" class="footnote-backref">↩</a></p>
682+
<li id="fn:1">
683+
<p>Some <em>bolded</em> footnote definition. <a href="#fnref:1" class="footnote-backref">↩</a></p>
684684
</li>
685-
<li id="fn2">
685+
<li id="fn:footnote">
686686
<blockquote>
687687
<p>Blockquotes can be in a footnote.</p>
688688
</blockquote>
689689
<pre><code>as well as code blocks
690690
</code></pre>
691-
<p>or, naturally, simple paragraphs. <a href="#fnref2" class="footnote-backref">↩</a></p>
691+
<p>or, naturally, simple paragraphs. <a href="#fnref:footnote" class="footnote-backref">↩</a></p>
692692
</li>
693-
<li id="fn3">
694-
<p>no code block here (spaces are stripped away) <a href="#fnref3" class="footnote-backref">↩</a></p>
693+
<li id="fn:other-note">
694+
<p>no code block here (spaces are stripped away) <a href="#fnref:other-note" class="footnote-backref">↩</a></p>
695695
</li>
696-
<li id="fn4">
696+
<li id="fn:codeblock-note">
697697
<pre><code>this is now a code block (8 spaces indentation)
698698
</code></pre>
699-
<a href="#fnref4" class="footnote-backref">↩</a>
699+
<a href="#fnref:codeblock-note" class="footnote-backref">↩</a>
700+
</li>
701+
</ol>
702+
</section>
703+
````````````````````````````````
704+
705+
## When a footnote is used multiple times, we insert multiple backrefs.
706+
707+
```````````````````````````````` example
708+
This is some text. It has a footnote[^a-footnote].
709+
710+
This footnote is referenced[^a-footnote] multiple times, in lots of different places.[^a-footnote]
711+
712+
[^a-footnote]: This footnote definition should have three backrefs.
713+
.
714+
<p>This is some text. It has a footnote<sup class="footnote-ref"><a href="#fn:a-footnote" id="fnref:a-footnote">1</a></sup>.</p>
715+
<p>This footnote is referenced<sup class="footnote-ref"><a href="#fn:a-footnote" id="fnref:a-footnote:2">1</a></sup> multiple times, in lots of different places.<sup class="footnote-ref"><a href="#fn:a-footnote" id="fnref:a-footnote:3">1</a></sup></p>
716+
<section class="footnotes">
717+
<ol>
718+
<li id="fn:a-footnote">
719+
<p>This footnote definition should have three backrefs. <a href="#fnref:a-footnote" class="footnote-backref">↩</a> <a href="#fnref:a-footnote:2" class="footnote-backref">↩<sup class="footnote-ref">2</sup></a> <a href="#fnref:a-footnote:3" class="footnote-backref">↩<sup class="footnote-ref">3</sup></a></p>
700720
</li>
701721
</ol>
702722
</section>

test/regression.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ A footnote in a paragraph[^1]
175175

176176
[^1]: a footnote
177177
.
178-
<p>A footnote in a paragraph<sup class="footnote-ref"><a href="#fn1" id="fnref1">1</a></sup></p>
178+
<p>A footnote in a paragraph<sup class="footnote-ref"><a href="#fn:1" id="fnref:1">1</a></sup></p>
179179
<table>
180180
<thead>
181181
<tr>
@@ -185,15 +185,15 @@ A footnote in a paragraph[^1]
185185
</thead>
186186
<tbody>
187187
<tr>
188-
<td>foot <sup class="footnote-ref"><a href="#fn1" id="fnref1">1</a></sup></td>
188+
<td>foot <sup class="footnote-ref"><a href="#fn:1" id="fnref:1:2">1</a></sup></td>
189189
<td>note</td>
190190
</tr>
191191
</tbody>
192192
</table>
193193
<section class="footnotes">
194194
<ol>
195-
<li id="fn1">
196-
<p>a footnote <a href="#fnref1" class="footnote-backref">↩</a></p>
195+
<li id="fn:1">
196+
<p>a footnote <a href="#fnref:1" class="footnote-backref">↩</a> <a href="#fnref:1:2" class="footnote-backref">↩<sup class="footnote-ref">2</sup></a></p>
197197
</li>
198198
</ol>
199199
</section>

0 commit comments

Comments
 (0)