Fossil SCM
Handle unreferenced footnotes. If a labeled footnote is defined but there are no references to it, then add a special item at the end of footnotes. This item includes a label and the text of the strayed footnote - both rendered verbatim via <tt>html_escape()</tt>. Default skin makes such items visible and easily distinguishable. The order of such items match the order in the underlying source code.
Commit
ada55cd45ae34dfdf3317b3eb22551680ed6e900006668b4f99eb8e180847021
Parent
7f6a641808be00f…
4 files changed
+15
-2
+9
-2
+10
-6
+15
-3
+15
-2
| --- src/default.css | ||
| +++ src/default.css | ||
| @@ -1671,19 +1671,32 @@ | ||
| 1671 | 1671 | font-size: 90%; |
| 1672 | 1672 | } |
| 1673 | 1673 | div.content div.markdown > ol.footnotes > li { |
| 1674 | 1674 | margin-bottom: 0.5em; |
| 1675 | 1675 | } |
| 1676 | -div.markdown ol.footnotes > li.unreferenced-footnote, | |
| 1677 | 1676 | div.markdown ol.footnotes > li.misreferences { |
| 1678 | 1677 | background: #ffdddd; |
| 1679 | 1678 | } |
| 1680 | -div.markdown ol.footnotes > li.unreferenced-footnote:first-child, | |
| 1679 | +div.markdown ol.footnotes > li.unreferenced:first-child, | |
| 1681 | 1680 | div.markdown ol.footnotes > li.misreferences { |
| 1682 | 1681 | margin-top: 0.75em; |
| 1683 | 1682 | padding-top: 0.25em; |
| 1684 | 1683 | padding-bottom: 0.25em; |
| 1684 | +} | |
| 1685 | +div.markdown ol.footnotes > li.unreferenced { | |
| 1686 | + padding-left: 0.5em; | |
| 1687 | + color: gray; | |
| 1688 | +} | |
| 1689 | +div.markdown ol.footnotes > li.unreferenced > code { | |
| 1690 | + color: red; | |
| 1691 | + font-weight: bold; | |
| 1692 | +} | |
| 1693 | +div.markdown ol.footnotes > li.unreferenced > pre { | |
| 1694 | + color: gray; | |
| 1695 | + padding-left: 0.5em; | |
| 1696 | + margin-top: 0.25em; | |
| 1697 | + border-left: 3px solid red; | |
| 1685 | 1698 | } |
| 1686 | 1699 | div.content div.markdown > ol.footnotes > li > .footnote-backrefs { |
| 1687 | 1700 | margin-right: 0.5em; |
| 1688 | 1701 | font-weight: bold; |
| 1689 | 1702 | } |
| 1690 | 1703 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -1671,19 +1671,32 @@ | |
| 1671 | font-size: 90%; |
| 1672 | } |
| 1673 | div.content div.markdown > ol.footnotes > li { |
| 1674 | margin-bottom: 0.5em; |
| 1675 | } |
| 1676 | div.markdown ol.footnotes > li.unreferenced-footnote, |
| 1677 | div.markdown ol.footnotes > li.misreferences { |
| 1678 | background: #ffdddd; |
| 1679 | } |
| 1680 | div.markdown ol.footnotes > li.unreferenced-footnote:first-child, |
| 1681 | div.markdown ol.footnotes > li.misreferences { |
| 1682 | margin-top: 0.75em; |
| 1683 | padding-top: 0.25em; |
| 1684 | padding-bottom: 0.25em; |
| 1685 | } |
| 1686 | div.content div.markdown > ol.footnotes > li > .footnote-backrefs { |
| 1687 | margin-right: 0.5em; |
| 1688 | font-weight: bold; |
| 1689 | } |
| 1690 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -1671,19 +1671,32 @@ | |
| 1671 | font-size: 90%; |
| 1672 | } |
| 1673 | div.content div.markdown > ol.footnotes > li { |
| 1674 | margin-bottom: 0.5em; |
| 1675 | } |
| 1676 | div.markdown ol.footnotes > li.misreferences { |
| 1677 | background: #ffdddd; |
| 1678 | } |
| 1679 | div.markdown ol.footnotes > li.unreferenced:first-child, |
| 1680 | div.markdown ol.footnotes > li.misreferences { |
| 1681 | margin-top: 0.75em; |
| 1682 | padding-top: 0.25em; |
| 1683 | padding-bottom: 0.25em; |
| 1684 | } |
| 1685 | div.markdown ol.footnotes > li.unreferenced { |
| 1686 | padding-left: 0.5em; |
| 1687 | color: gray; |
| 1688 | } |
| 1689 | div.markdown ol.footnotes > li.unreferenced > code { |
| 1690 | color: red; |
| 1691 | font-weight: bold; |
| 1692 | } |
| 1693 | div.markdown ol.footnotes > li.unreferenced > pre { |
| 1694 | color: gray; |
| 1695 | padding-left: 0.5em; |
| 1696 | margin-top: 0.25em; |
| 1697 | border-left: 3px solid red; |
| 1698 | } |
| 1699 | div.content div.markdown > ol.footnotes > li > .footnote-backrefs { |
| 1700 | margin-right: 0.5em; |
| 1701 | font-weight: bold; |
| 1702 | } |
| 1703 |
+9
-2
| --- src/markdown.c | ||
| +++ src/markdown.c | ||
| @@ -2670,23 +2670,30 @@ | ||
| 2670 | 2670 | release_work_buffer(&rndr,tmp); |
| 2671 | 2671 | |
| 2672 | 2672 | /* footnotes rendering */ |
| 2673 | 2673 | if( rndr.make.footnote_item && rndr.make.footnotes ){ |
| 2674 | 2674 | Blob *all_items = new_work_buffer(&rndr); |
| 2675 | + int j = -1; | |
| 2675 | 2676 | for(i=0; i<COUNT_FOOTNOTES(notes); i++){ |
| 2676 | 2677 | const struct footnote* x = CAST_AS_FOOTNOTES(notes) + i; |
| 2677 | 2678 | if( x->bRndred ){ |
| 2678 | 2679 | rndr.make.footnote_item(all_items, &x->text, x->iMark, |
| 2679 | 2680 | x->nUsed, rndr.make.opaque); |
| 2681 | + j = i; | |
| 2680 | 2682 | } |
| 2681 | 2683 | } |
| 2682 | 2684 | if( rndr.notes.misref.nUsed ){ |
| 2683 | 2685 | rndr.make.footnote_item(all_items, 0, -1, |
| 2684 | 2686 | rndr.notes.misref.nUsed, rndr.make.opaque); |
| 2685 | 2687 | } |
| 2686 | - /* TODO: handle unreferenced (defined but not used) footnotes */ | |
| 2687 | - | |
| 2688 | + while( ++j < COUNT_FOOTNOTES(notes) ){ | |
| 2689 | + const struct footnote* x = CAST_AS_FOOTNOTES(notes) + j; | |
| 2690 | + assert( !x->nUsed ); | |
| 2691 | + assert( !x->bRndred ); | |
| 2692 | + assert( (&x->id) + 1 == &x->text ); /* see html_footnote_item() */ | |
| 2693 | + rndr.make.footnote_item(all_items,&x->text,0,0,rndr.make.opaque); | |
| 2694 | + } | |
| 2688 | 2695 | rndr.make.footnotes(ob, all_items, rndr.make.opaque); |
| 2689 | 2696 | release_work_buffer(&rndr, all_items); |
| 2690 | 2697 | } |
| 2691 | 2698 | release_work_buffer(&rndr, notes); |
| 2692 | 2699 | } |
| 2693 | 2700 |
| --- src/markdown.c | |
| +++ src/markdown.c | |
| @@ -2670,23 +2670,30 @@ | |
| 2670 | release_work_buffer(&rndr,tmp); |
| 2671 | |
| 2672 | /* footnotes rendering */ |
| 2673 | if( rndr.make.footnote_item && rndr.make.footnotes ){ |
| 2674 | Blob *all_items = new_work_buffer(&rndr); |
| 2675 | for(i=0; i<COUNT_FOOTNOTES(notes); i++){ |
| 2676 | const struct footnote* x = CAST_AS_FOOTNOTES(notes) + i; |
| 2677 | if( x->bRndred ){ |
| 2678 | rndr.make.footnote_item(all_items, &x->text, x->iMark, |
| 2679 | x->nUsed, rndr.make.opaque); |
| 2680 | } |
| 2681 | } |
| 2682 | if( rndr.notes.misref.nUsed ){ |
| 2683 | rndr.make.footnote_item(all_items, 0, -1, |
| 2684 | rndr.notes.misref.nUsed, rndr.make.opaque); |
| 2685 | } |
| 2686 | /* TODO: handle unreferenced (defined but not used) footnotes */ |
| 2687 | |
| 2688 | rndr.make.footnotes(ob, all_items, rndr.make.opaque); |
| 2689 | release_work_buffer(&rndr, all_items); |
| 2690 | } |
| 2691 | release_work_buffer(&rndr, notes); |
| 2692 | } |
| 2693 |
| --- src/markdown.c | |
| +++ src/markdown.c | |
| @@ -2670,23 +2670,30 @@ | |
| 2670 | release_work_buffer(&rndr,tmp); |
| 2671 | |
| 2672 | /* footnotes rendering */ |
| 2673 | if( rndr.make.footnote_item && rndr.make.footnotes ){ |
| 2674 | Blob *all_items = new_work_buffer(&rndr); |
| 2675 | int j = -1; |
| 2676 | for(i=0; i<COUNT_FOOTNOTES(notes); i++){ |
| 2677 | const struct footnote* x = CAST_AS_FOOTNOTES(notes) + i; |
| 2678 | if( x->bRndred ){ |
| 2679 | rndr.make.footnote_item(all_items, &x->text, x->iMark, |
| 2680 | x->nUsed, rndr.make.opaque); |
| 2681 | j = i; |
| 2682 | } |
| 2683 | } |
| 2684 | if( rndr.notes.misref.nUsed ){ |
| 2685 | rndr.make.footnote_item(all_items, 0, -1, |
| 2686 | rndr.notes.misref.nUsed, rndr.make.opaque); |
| 2687 | } |
| 2688 | while( ++j < COUNT_FOOTNOTES(notes) ){ |
| 2689 | const struct footnote* x = CAST_AS_FOOTNOTES(notes) + j; |
| 2690 | assert( !x->nUsed ); |
| 2691 | assert( !x->bRndred ); |
| 2692 | assert( (&x->id) + 1 == &x->text ); /* see html_footnote_item() */ |
| 2693 | rndr.make.footnote_item(all_items,&x->text,0,0,rndr.make.opaque); |
| 2694 | } |
| 2695 | rndr.make.footnotes(ob, all_items, rndr.make.opaque); |
| 2696 | release_work_buffer(&rndr, all_items); |
| 2697 | } |
| 2698 | release_work_buffer(&rndr, notes); |
| 2699 | } |
| 2700 |
+10
-6
| --- src/markdown_html.c | ||
| +++ src/markdown_html.c | ||
| @@ -435,18 +435,22 @@ | ||
| 435 | 435 | } |
| 436 | 436 | BLOB_APPEND_LITERAL(ob,"</sup>\n"); |
| 437 | 437 | BLOB_APPEND_BLOB(ob, text); |
| 438 | 438 | }else{ |
| 439 | 439 | /* a footnote was defined but wasn't used */ |
| 440 | + /* make.footnote_item() invocations should pass args accordingly */ | |
| 441 | + const struct Blob * id = text-1; | |
| 440 | 442 | assert( text ); |
| 441 | 443 | assert( blob_size(text) ); |
| 442 | - /* FIXME: not yet implemented */ | |
| 443 | - return; | |
| 444 | - BLOB_APPEND_LITERAL(ob, | |
| 445 | - "<li class='unreferenced-footnote' id='unreferenced-footnote"); | |
| 446 | - blob_appendf(ob,"%s-%i'>\n", unique, iMark); | |
| 447 | - BLOB_APPEND_BLOB(ob, text); | |
| 444 | + assert( blob_size(id) ); | |
| 445 | + BLOB_APPEND_LITERAL(ob,"<li class='unreferenced'>\n[^ <code>"); | |
| 446 | + html_escape(ob, blob_buffer(id), blob_size(id)); | |
| 447 | + BLOB_APPEND_LITERAL(ob, "</code> ] " | |
| 448 | + "<i>was defined but is not referenced</i>\n" | |
| 449 | + "<pre><code class='language-markdown'>"); | |
| 450 | + html_escape(ob, blob_buffer(text), blob_size(text)); | |
| 451 | + BLOB_APPEND_LITERAL(ob,"</code></pre>"); | |
| 448 | 452 | } |
| 449 | 453 | BLOB_APPEND_LITERAL(ob, "\n</li>\n"); |
| 450 | 454 | } |
| 451 | 455 | static void html_footnotes( |
| 452 | 456 | struct Blob *ob, const struct Blob *items, void *opaque |
| 453 | 457 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -435,18 +435,22 @@ | |
| 435 | } |
| 436 | BLOB_APPEND_LITERAL(ob,"</sup>\n"); |
| 437 | BLOB_APPEND_BLOB(ob, text); |
| 438 | }else{ |
| 439 | /* a footnote was defined but wasn't used */ |
| 440 | assert( text ); |
| 441 | assert( blob_size(text) ); |
| 442 | /* FIXME: not yet implemented */ |
| 443 | return; |
| 444 | BLOB_APPEND_LITERAL(ob, |
| 445 | "<li class='unreferenced-footnote' id='unreferenced-footnote"); |
| 446 | blob_appendf(ob,"%s-%i'>\n", unique, iMark); |
| 447 | BLOB_APPEND_BLOB(ob, text); |
| 448 | } |
| 449 | BLOB_APPEND_LITERAL(ob, "\n</li>\n"); |
| 450 | } |
| 451 | static void html_footnotes( |
| 452 | struct Blob *ob, const struct Blob *items, void *opaque |
| 453 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -435,18 +435,22 @@ | |
| 435 | } |
| 436 | BLOB_APPEND_LITERAL(ob,"</sup>\n"); |
| 437 | BLOB_APPEND_BLOB(ob, text); |
| 438 | }else{ |
| 439 | /* a footnote was defined but wasn't used */ |
| 440 | /* make.footnote_item() invocations should pass args accordingly */ |
| 441 | const struct Blob * id = text-1; |
| 442 | assert( text ); |
| 443 | assert( blob_size(text) ); |
| 444 | assert( blob_size(id) ); |
| 445 | BLOB_APPEND_LITERAL(ob,"<li class='unreferenced'>\n[^ <code>"); |
| 446 | html_escape(ob, blob_buffer(id), blob_size(id)); |
| 447 | BLOB_APPEND_LITERAL(ob, "</code> ] " |
| 448 | "<i>was defined but is not referenced</i>\n" |
| 449 | "<pre><code class='language-markdown'>"); |
| 450 | html_escape(ob, blob_buffer(text), blob_size(text)); |
| 451 | BLOB_APPEND_LITERAL(ob,"</code></pre>"); |
| 452 | } |
| 453 | BLOB_APPEND_LITERAL(ob, "\n</li>\n"); |
| 454 | } |
| 455 | static void html_footnotes( |
| 456 | struct Blob *ob, const struct Blob *items, void *opaque |
| 457 |
+15
-3
| --- test/markdown-test3.md | ||
| +++ test/markdown-test3.md | ||
| @@ -3,15 +3,19 @@ | ||
| 3 | 3 | ================================ |
| 4 | 4 | |
| 5 | 5 | **This document** should help with testing of footnotes support that |
| 6 | 6 | is introduced by the ["`markdown-footnotes`"][branch] branch. |
| 7 | 7 | It **might look pretty misformatted unless rendered by the proper Fossil |
| 8 | -executable that incorporates the abovementioned branch.**[^1] | |
| 8 | +executable** that incorporates the abovementioned branch.[^1] | |
| 9 | +That is also a humble attempt to explore the robustness of the Markdown parser. | |
| 10 | +So please excuse for the mess in the [source code of this document][src]. | |
| 11 | +By no means the normal use of footnotes should look that scarry. | |
| 9 | 12 | |
| 10 | 13 | Developers are invited to add test cases here[^here]. |
| 11 | 14 | It is suggested that the more simple is a test case the earlier it should |
| 12 | 15 | appear in this document.[^ if glitch occurs ] |
| 16 | + | |
| 13 | 17 | |
| 14 | 18 | [^lost3]: This note was defined at the begining of the document. |
| 15 | 19 | |
| 16 | 20 | [^duplicate]: This came from the begining of the document. |
| 17 | 21 | |
| @@ -28,12 +32,16 @@ | ||
| 28 | 32 | |
| 29 | 33 | [^lost2]: This note was defined in the middle of the document. |
| 30 | 34 | It references [its previous][^lost3] |
| 31 | 35 | and [the forthcoming][^lost1] siblings. |
| 32 | 36 | |
| 33 | -[^i am unreferenced]: If this is rendered wihin footnotes, | |
| 34 | - then there is a BUG! | |
| 37 | +[^i am strayed]: | |
| 38 | + This should be presented **verbatim** (without any [markup][^]) | |
| 39 | + in the end of the footnotes. | |
| 40 | + | |
| 41 | + Default skin renders label in red bold font and the main text as gray. | |
| 42 | + Other styling may also apply. | |
| 35 | 43 | |
| 36 | 44 | Inline footnotes are supported.(^These may be usefull for adding |
| 37 | 45 | <s>small</s> comments.) |
| 38 | 46 | |
| 39 | 47 | If [undefined label is used][^] then red "`misref`" is emited instead of |
| @@ -52,10 +60,12 @@ | ||
| 52 | 60 | |
| 53 | 61 | [^ 1]: Footnotes is a Fossil' extention of |
| 54 | 62 | Markdown. Your other tools may have limited support for these. |
| 55 | 63 | |
| 56 | 64 | [^here]: [History of test/markdown-test3.md](/finfo/test/markdown-test3.md) |
| 65 | + | |
| 66 | +[src]: /file/test/markdown-test3.md?ci=markdown-footnotes&txt&ln | |
| 57 | 67 | |
| 58 | 68 | [^if glitch occurs]: |
| 59 | 69 | So that simple cases are processed even if |
| 60 | 70 | a glitch happens for more tricky cases. |
| 61 | 71 | |
| @@ -76,8 +86,10 @@ | ||
| 76 | 86 | It defines an inline note. |
| 77 | 87 | |
| 78 | 88 | (^This is inline note defined inside of [a labeled note][^lost1].) |
| 79 | 89 | |
| 80 | 90 | [^markup]: E.g. *emphasis*, and [so on](/md_rules). |
| 91 | + BTW, this note may not have a backreference to the "stray". | |
| 81 | 92 | |
| 82 | 93 | [^undefined label is used]: For example due to a typo. |
| 83 | 94 | |
| 95 | +[^another stray]: Just to verify the correctness of ordering and styling. | |
| 84 | 96 |
| --- test/markdown-test3.md | |
| +++ test/markdown-test3.md | |
| @@ -3,15 +3,19 @@ | |
| 3 | ================================ |
| 4 | |
| 5 | **This document** should help with testing of footnotes support that |
| 6 | is introduced by the ["`markdown-footnotes`"][branch] branch. |
| 7 | It **might look pretty misformatted unless rendered by the proper Fossil |
| 8 | executable that incorporates the abovementioned branch.**[^1] |
| 9 | |
| 10 | Developers are invited to add test cases here[^here]. |
| 11 | It is suggested that the more simple is a test case the earlier it should |
| 12 | appear in this document.[^ if glitch occurs ] |
| 13 | |
| 14 | [^lost3]: This note was defined at the begining of the document. |
| 15 | |
| 16 | [^duplicate]: This came from the begining of the document. |
| 17 | |
| @@ -28,12 +32,16 @@ | |
| 28 | |
| 29 | [^lost2]: This note was defined in the middle of the document. |
| 30 | It references [its previous][^lost3] |
| 31 | and [the forthcoming][^lost1] siblings. |
| 32 | |
| 33 | [^i am unreferenced]: If this is rendered wihin footnotes, |
| 34 | then there is a BUG! |
| 35 | |
| 36 | Inline footnotes are supported.(^These may be usefull for adding |
| 37 | <s>small</s> comments.) |
| 38 | |
| 39 | If [undefined label is used][^] then red "`misref`" is emited instead of |
| @@ -52,10 +60,12 @@ | |
| 52 | |
| 53 | [^ 1]: Footnotes is a Fossil' extention of |
| 54 | Markdown. Your other tools may have limited support for these. |
| 55 | |
| 56 | [^here]: [History of test/markdown-test3.md](/finfo/test/markdown-test3.md) |
| 57 | |
| 58 | [^if glitch occurs]: |
| 59 | So that simple cases are processed even if |
| 60 | a glitch happens for more tricky cases. |
| 61 | |
| @@ -76,8 +86,10 @@ | |
| 76 | It defines an inline note. |
| 77 | |
| 78 | (^This is inline note defined inside of [a labeled note][^lost1].) |
| 79 | |
| 80 | [^markup]: E.g. *emphasis*, and [so on](/md_rules). |
| 81 | |
| 82 | [^undefined label is used]: For example due to a typo. |
| 83 | |
| 84 |
| --- test/markdown-test3.md | |
| +++ test/markdown-test3.md | |
| @@ -3,15 +3,19 @@ | |
| 3 | ================================ |
| 4 | |
| 5 | **This document** should help with testing of footnotes support that |
| 6 | is introduced by the ["`markdown-footnotes`"][branch] branch. |
| 7 | It **might look pretty misformatted unless rendered by the proper Fossil |
| 8 | executable** that incorporates the abovementioned branch.[^1] |
| 9 | That is also a humble attempt to explore the robustness of the Markdown parser. |
| 10 | So please excuse for the mess in the [source code of this document][src]. |
| 11 | By no means the normal use of footnotes should look that scarry. |
| 12 | |
| 13 | Developers are invited to add test cases here[^here]. |
| 14 | It is suggested that the more simple is a test case the earlier it should |
| 15 | appear in this document.[^ if glitch occurs ] |
| 16 | |
| 17 | |
| 18 | [^lost3]: This note was defined at the begining of the document. |
| 19 | |
| 20 | [^duplicate]: This came from the begining of the document. |
| 21 | |
| @@ -28,12 +32,16 @@ | |
| 32 | |
| 33 | [^lost2]: This note was defined in the middle of the document. |
| 34 | It references [its previous][^lost3] |
| 35 | and [the forthcoming][^lost1] siblings. |
| 36 | |
| 37 | [^i am strayed]: |
| 38 | This should be presented **verbatim** (without any [markup][^]) |
| 39 | in the end of the footnotes. |
| 40 | |
| 41 | Default skin renders label in red bold font and the main text as gray. |
| 42 | Other styling may also apply. |
| 43 | |
| 44 | Inline footnotes are supported.(^These may be usefull for adding |
| 45 | <s>small</s> comments.) |
| 46 | |
| 47 | If [undefined label is used][^] then red "`misref`" is emited instead of |
| @@ -52,10 +60,12 @@ | |
| 60 | |
| 61 | [^ 1]: Footnotes is a Fossil' extention of |
| 62 | Markdown. Your other tools may have limited support for these. |
| 63 | |
| 64 | [^here]: [History of test/markdown-test3.md](/finfo/test/markdown-test3.md) |
| 65 | |
| 66 | [src]: /file/test/markdown-test3.md?ci=markdown-footnotes&txt&ln |
| 67 | |
| 68 | [^if glitch occurs]: |
| 69 | So that simple cases are processed even if |
| 70 | a glitch happens for more tricky cases. |
| 71 | |
| @@ -76,8 +86,10 @@ | |
| 86 | It defines an inline note. |
| 87 | |
| 88 | (^This is inline note defined inside of [a labeled note][^lost1].) |
| 89 | |
| 90 | [^markup]: E.g. *emphasis*, and [so on](/md_rules). |
| 91 | BTW, this note may not have a backreference to the "stray". |
| 92 | |
| 93 | [^undefined label is used]: For example due to a typo. |
| 94 | |
| 95 | [^another stray]: Just to verify the correctness of ordering and styling. |
| 96 |