How markdown parsing works with swift-cmark and GFM extensions
MarkdownView uses swift-cmark — Apple’s Swift wrapper around the reference CommonMark implementation — to parse markdown into an Abstract Syntax Tree (AST). This ensures spec-compliant parsing with full GitHub Flavored Markdown (GFM) support.
func withParser<T>(_ block: (UnsafeMutablePointer<cmark_parser>) -> T) -> T { let parser = cmark_parser_new(CMARK_OPT_DEFAULT)! cmark_gfm_core_extensions_ensure_registered() let extensionNames = [ "autolink", "strikethrough", "tagfilter", "tasklist", "table", ] for extensionName in extensionNames { guard let syntaxExtension = cmark_find_syntax_extension(extensionName) else { assertionFailure() continue } cmark_parser_attach_syntax_extension(parser, syntaxExtension) } defer { cmark_parser_free(parser) } return block(parser)}
The parser is created on-demand and freed after use to minimize memory footprint. This design allows parsing to be fully synchronous while keeping overhead low.
Compare previousMarkdown and newMarkdown to find the longest common prefix.
2
Reuse prefix blocks
Keep the AST nodes for the unchanged prefix without reparsing them.
3
Parse tail only
Parse the changed suffix starting from the stable boundary.
4
Merge results
Concatenate stable prefix blocks with newly parsed tail blocks.
let result = parser.parseIncremental( previousMarkdown: oldText, newMarkdown: newText, previousBlocks: oldBlocks)if let result = result { // Reuse first N blocks, append new tail let merged = oldBlocks.prefix(result.stablePrefixBlockCount) + result.tailResult.document}
Incremental parsing provides a ~5ms speedup for 300-block documents when only the end is modified. See the performance benchmarks.
public struct RootBlockRange { public let type: MarkdownNodeType public let startIndex: String.Index public let endIndex: String.Index public let outputBlockCount: Int}public func parseBlockRange(_ markdown: String) -> [RootBlockRange]
import MarkdownParserlet markdown = """# Math ExampleThe quadratic formula is $x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}$.```swiftlet result = parser.parse(text)
Parse block math
Parse inline math
"""
let parser = MarkdownParser()
let result = parser.parse(markdown)print(“Blocks: (result.document.count)”)
print(“Math expressions: (result.mathContext.count)”)// Output:
// Blocks: 4 (heading, paragraph, code block, task list)
// Math expressions: 1 (the quadratic formula)
The parsed AST is now ready for rendering by the MarkdownView module.