microsoft / microsoft/SwiftStreamingMarkdown

feature request: render footnotes ([^1])

Open
#126 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Swift
Stars
364
Forks
51
PR merge metrics
No merged PRs in 30d

Description

summary
footnotes are on the README's "Not yet supported" list. unlike task lists (#118), the parser gives us nothing here: swift-markdown attaches only the table, strikethrough, and tasklist cmark-gfm extensions and has no footnote node types at all, so footnote syntax survives parsing as plain literal text. i'd like to contribute rendering support via a preprocessing pass, following the same approach the library already uses for LaTeX — and i'd love a design ack before sending the PR, since there's an architectural choice involved.

minimal markdown input

here is a footnote reference.[^1]

[^1]: and here is the definition.

(the kitchen-sink fixture already exercises this — [^streaming] around lines 229–231.)

current behavior
the reference renders inline as the literal text "here is a footnote reference.[^1]", and the definition renders as a regular paragraph "[^1]: and here is the definition." — readable, as the README promises, but far from the GitHub rendering.

proposed change
a FootnotePreProcessor alongside the existing LaTexPreProcessor (whose own doc comment describes preprocessing as "a less heavy-weight approach than forking commonmark-gfm and swift-markdown" — same reasoning applies here):

  • collect single-line definitions ([^id]: text) and remove them from the source;
  • number references by order of first appearance (GFM semantics — labels like [^note] render as numbers);
  • replace each reference with a specially-marked inline construct that the inline layer renders as a real superscript (smaller font + baseline offset) — the same marker technique the LaTeX preprocessor already uses for inline math;
  • append a footnotes section at the end of the document: thematic break + ordered list with the definition texts (inline formatting inside definitions is preserved, since the emitted text goes through the normal markdown parse);
  • skip anything inside fenced code blocks or inline code spans, so code samples containing [^1] aren't transformed.

GFM parity for the edges: references without a definition stay literal; definitions never referenced are dropped.

v1 scope / open questions

  • display-only: no tap-to-scroll between reference and definition (the block-based architecture makes that a separate, bigger conversation — can be a follow-up).
  • single-line definitions only; GFM's multi-line/indented continuations are out of scope for v1 and keep today's behavior.
  • streaming: the preprocessor is a pure function of each snapshot, so numbering stays stable as text grows; a partially streamed [^ renders as literal text until the bracket closes (same class of jitter as other constructs).
  • your architecture notes describe preprocessing as "not ideal" with in-parser math on the roadmap — if you'd rather not grow this stage, happy to discuss alternatives (a post-parse rewriter, or waiting on upstream swift-markdown support). could also gate it behind MarkdownParseOption like latexMatchingRules if you want it opt-out.

validation plan

  • unit tests for the preprocessor (pure string → string: numbering, missing definitions, unreferenced definitions, code-fence immunity, idempotence on already-processed text);
  • a unit test for the superscript inline conversion;
  • snapshot tests (iOS + macOS variants) for a document with references and the footnotes section;
  • kitchen-sink fixture update once supported, plus the README support-list move.

if this sounds good, i'll send a focused PR.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the existing LaTexPreProcessor and its preprocessing notes, then inspect the kitchen-sink fixture around lines 229–231 and the current inline and snapshot tests. Define the preprocessor and superscript conversion behavior from the proposed validation plan, including code immunity and missing or unreferenced definitions. Done means passing unit and iOS/macOS snapshot tests, an updated kitchen-sink fixture, and the README support-list change.

Written by the indexing model from the issue text.

Assessment

Tech stack
markdown, swift
Domain
content, frontend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.