[Pitch] Adding Footnotes to Swift-DocC

Introduction

Hi all!

I'm pitching a little feature that I think can add a lot to support more book-like content using Swift-DocC: footnotes.

For a few years now Github Flavored Markdown (GFM) has supported footnotes but in Swift-Markdown this option is turned off: Usage of footers and other markdown extension · Issue #115 · apple/swift-markdown · GitHub.

Footnotes allow authors to cite sources, add some context or elaborate on something and annotate text without distracting the reader from the main text.

Usage

I propose to enable GFM footnotes and thus also use their syntax. A quick overview for people who are not familiar with that syntax:


Here is a simple footnote[^1].

A footnote can also have multiple lines[^2].

[^1]: My reference.

[^2]: To add line breaks within a footnote, prefix new lines with 2 spaces.

This is a second line.

This is the basic syntax for footnotes. They consist of an identifier and an explanation. The identifier can be a number or words but cannot contain spaces or tabs.

It will be displayed as a superscript link to the explanation. The explanation can be placed anywhere in the document but will always be rendered at the bottom of the page

Examples

Footnotes are technically part of the article itself, thus it should be placed before the See Also section.

Feedback

I'd love to hear your thoughts and feedback on this proposal. If someone wants to (help me) implement this, also let me know!

16 Likes

To lay out the expected effort to make this happen end-to-end, this feature would need three PRs:

  1. One in Swift-Markdown, enabling the feature and ensuring that its AST and MarkupWalker infrastructure can support it. We would likely need to pull in the footnote's ID (the text string given in the authored Markdown) and its text (the content written out-of-band). cmark-gfm does not store a footnote's numbering in its AST; that is generated during HTML rendering. However, this shouldn't be too much of a problem.
  2. One in Swift-DocC, adding support for footnotes into the Render JSON being outputted. I'm not 100% certain of the layout of Render JSON, but we would need to store the mapping of footnote reference IDs to their footnote text as a new kind of reference (or some other kind of out-of-band mapping), and then include the footnote references in the body text as a new kind of render node. cc @marcus_ortiz, i'd love to get the Swift-DocC-Render team's input here.
  3. One in Swift-DocC-Render, adding support for rendering the footnotes based on the Render JSON outputted by Swift-DocC.

Like i mentioned in the issue, the syntax support for GitHub-Flavored Markdown's implementation of footnotes already exists, so we wouldn't need to implement any new parsing behavior for this. IMO, the bulk of the work comes down to coordinating the work among the repos and ensuring that Swift-DocC and Swift-DocC-Render are working from the same JSON format.

4 Likes

On the Swift-DocC side there's also a question regarding what content would be allowed in footnote text. For example; can a footnote text be anything other than paragraphs of text? Can a footnote text be more than one paragraph? Can a footnote text's inline content (the elements in the paragraph) contain images or other footnotes?

2 Likes

Nice! We should also look at what sort of diagnostics to emit, e.g. a warning when a footnote reference has no associated footnote, and the other way around. In the case of a footnote reference with no footnote, we could even offer a fix-it that inserted [^whatever]: near the bottom of the section.

2 Likes

i don't really like the idea of swift inventing its own flavor of markdown. i realize with block directives it has already not been possible to parse "swift-flavored markdown" with a regular GFM parser for a long time, but this sounds like we are barreling ahead towards a full "hey let's invent our own implementation-defined rich text format" model, and i don't like that.

edit: i completely misread the earlier post and realized footnotes are actually a GFM feature that is just not exposed in swift-markdown.

1 Like

I haven't found a definitive explanation of what the gfm footnotes can and cannot contain but i found this issue: footnotes missing from the spec · Issue #283 · github/cmark-gfm · GitHub.

It seems it can contain:

  • basic inline markup like bold, italic, ...
  • links
  • a reference to a new footnote (there should be a failsafe in the parser to prevent circular references)
  • images is not very obvious but it does support that indeed I discoverd after some experimenting on a README.md page
  • as shown in the example code multiple lines can be achieved by indenting the next paragraphs.

Block elements aren't supported. If they are used the footnote will be treated as normal text.

1 Like

What’s wrong with circular references?

1 Like

I'm sorry I read it too quickly I was talking about this part cmark-gfm/footnotes.c at master · github/cmark-gfm · GitHub

are circular references useful for anything motivating?

This is the piece I'm most concerned about. I find most implementations of footnotes on the web to have a pretty sub-optimal UX. This is the typical flow I experience:

  1. I see a footnote indicator and wonder if the footnote contains information that is relevant/interesting me.
  2. I click on the footnote link which has a (typically) tiny touch target at the upper-right of a word.
  3. Watch the page abruptly scroll to the bottom.
  4. Read the footnote (which might not include information that's interesting to me).
  5. Click on another tiny touch target at the end of the footnote.
  6. Watch the page abruptly scroll back to an approximation of where I was before.

This is all pretty disorienting, especially on mobile.

The other common UX I've seen is with a small popover that appears when you click on the small footnote indicator. This solves some of the problems encountered with the flow I described above – but is arguably worse for actually reading the footnote.

Before we consider adding footnotes to Swift-DocC, I'd like to see a UX in DocC-Render that makes footnotes accessible and great to use.

I'm curious if anyone has encountered an implementation of footnotes that they really love? Or maybe my dislike of the more typical UX is unusual?

4 Likes

it would be really cool if the footnotes expanded as a sidebar, so you wouldn’t lose your place in the main flow. but this is probably really hard to do in the frontend.

2 Likes

What does motivation have to do with requiring a “parser failsafe”? Does the documentation parser need protection from demotivating parses?

it’s a potential DoS attack surface.

What does the parser do that would make it so? At the presentation level, we’re talking just two links to two anchors, are we not?

not necessarily the parser, though the parser could also be vulnerable. documentation tools (like mine) run a lot of algorithms over markdown trees, and things like circular references can send them into infinite loops if you’re not careful.

last year, swiftinit had a bug where if a symbolgraph had a circular sourceOrigin chain it would keep dereferencing that chain forever, which would cause the server to hang. luckily, people can’t upload symbolgraphs to swiftinit (yet).

That seems like a critical vulnerability not specific to footnotes at all, no? In the general case, there are plenty of legitimate reasons why an intimately related pair of APIs might want to cross-reference each other—for instance, init(_: String) and description on a lossless string convertible type. Arbitrary limiting this functionality for footnotes would be, well, arbitrary—unless there’s something specific about the parsing of footnotes that would be particularly a footgun for documentation tools?

this is codelink (“symbollink” in DocC parlance) resolution, not footnote resolution. depending on implementation, codelink resolution can suffer from poor worst-case performance, but i am not currently aware of any “inherent” server-killing attacks that can be performed against codelink resolution.

i suppose if codelink resolution became more sophisticated (e.g. resolving through conformances implied by where constraints) there would be a lot more ways to sabotage it. but right now the algorithms are relatively “dumb”, which makes them harder to break.

Wikipedia combines both in a way thats quite alright I think.

On wide screens it uses the regular links. On small screens they still have the footnote section at the bottom but when you click on the link to a footnote it actually shows a special pop over box that takes up no more than half of the screen. If it is too large it will be scrollable.



I think this way is sufficient. If wikipedia implements it this way mobile users will probably also expect the same behavior. We can however style the links to be a bit larger somehow to make it easier to click on them.

2 Likes

Sure—however named, my question is whether there's anything about footnote resolution that is particularly susceptible to causing vulnerabilities due to circularity, seeing as something at least conceptually similar exists and ought to be (in my view at least) supported in the form what you call "codelink" resolution, and seeing as you can already cite other instances of circular chains encountered during handling of existing markdown trees which documentation tools have to handle correctly.

cc @marcus_ortiz @marinaaisa @dhristov, it looks like Nio is working on getting the change implemented in DocC and needs to help coordinating it with DocC-Render. Would one of you be willing to work with him to coordinate the change between DocC and DocC-Render?

1 Like