Class FootnoteHtmlNodeRenderer

  • All Implemented Interfaces:
    NodeRenderer

    public class FootnoteHtmlNodeRenderer
    extends java.lang.Object
    implements NodeRenderer
    HTML rendering for footnotes.

    Aims to match the rendering of cmark-gfm (which is slightly different from GitHub's when it comes to class attributes, not sure why).

    Some notes on how rendering works:

    • Footnotes are numbered according to the order of references, starting at 1
    • Definitions are rendered at the end of the document, regardless of where the definition was in the source
    • Definitions are ordered by number
    • Definitions have links back to their references (one or more)

    Nested footnotes

    Text in footnote definitions can reference other footnotes, even ones that aren't referenced in the main text. This makes them tricky because it's not enough to just go through the main text for references. And before we can render a definition, we need to know all references (because we add links back to references).

    In other words, footnotes form a directed graph. Footnotes can reference each other so cycles are possible too.

    One way to implement it, which is what cmark-gfm does, is to go through the whole document (including definitions) and find all references in order. That guarantees that all definitions are found, but it has strange results for ordering or when the reference is in an unreferenced definition, see tests. In graph terms, it renders all definitions that have an incoming edge, no matter whether they are connected to the main text or not.

    The way we implement it:

    1. Start with the references in the main text; we can render them as we go
    2. After the main text is rendered, we have the referenced definitions, but there might be more from definition text
    3. To find the remaining definitions, we visit the definitions from before to look at references
    4. Repeat (breadth-first search) until we've found all definitions (note that we can't render before that's done because of backrefs)
    5. Now render the definitions (and any references inside)
    This means we only render definitions whose references are actually rendered, and in a meaningful order (all main text footnotes first, then any nested ones).