Adding Markdown rendering to Pixie — two approachesWe're considering Markdown rendering support in Pixie. There are two viable paths and they have very different tradeoffs. Looking for input on which way to go.
Option A — MD → HTML → existing HTML engineConvert Markdown to HTML in a small new unit, then feed the output to
TPixieHtmlView. The HTML/CSS engine handles everything else.
Pros- Minimal new code: just a CommonMark/GFM → HTML converter (~1-2k lines, mostly parser).
- Full CommonMark + GFM compliance for free, including raw HTML passthrough (<kbd>, <details>, <img width="...">, <sub>, <div align="center"> — common in real-world READMEs).
- MD extensions are trivial: footnotes become anchored sections, task lists become checkboxes, math becomes MathML or img tags, mermaid becomes <pre class="mermaid">. Renderer doesn't change.
- Full CSS-based theming: users can override anything per-element.
- PDF export, image loading, SVG embedding, text selection, clipboard, find-in-page, link hover, focus, accessibility — all inherited from the existing HtmlView.
- Future-proof: new MD features = parser-only changes.
Cons- Brings the entire HTML engine (~60k lines) into any application that wants Markdown rendering.
- Heavier runtime: HTML parser builds a DOM, CSS cascade computes styles, formatting contexts run, render tree builds — even for a one-paragraph chat message.
- Higher memory footprint per document.
- Pays for HTML quirks (margin collapse, float positioning, complex layout) even where not needed.
- Wrong shape for embedded log viewers, chat bubbles, or anything where you want a fast, lean MD widget.
Option B — parallel MD-only rendererA self-contained Markdown engine: own parser, own minimal node tree, own layout pass. Depends only on
common/ (canvas, font descriptions, colours, types).
Pros- Order-of-magnitude smaller: estimated ~3-5k lines total (parser + layout + inline wrapper + components).
- Depends only on common/ — apps that don't need HTML don't pay for HTML.
- Single-pass parse, single-pass layout. No CSS cascade, no style invalidation, no formatting-context machinery.
- Predictable performance and memory — well-suited to log viewers, chat UIs, in-app help, notes apps.
- Simple theme record (fonts, colours, spacing) covers the common customisation cases without CSS.
- Same TPixieCanvas abstraction means D2D / Cairo / CG / Qt / FMX / PDF backends all work.
Cons- No HTML passthrough. Real-world .md files use HTML constructs constantly (<kbd>, <details>/<summary>, <img width="...">, <sub>, <div align="center">, etc.). CommonMark explicitly allows this; a pure-MD renderer mis-renders these into literal text or has to silently strip them. This is the load-bearing tradeoff.
- Every MD extension (footnotes, task lists, math, mermaid, definition lists, front-matter) requires parser + node + layout + theme changes. Closed system.
- No per-element styling — theme is global. "This one heading in red" requires inventing a directive syntax.
- We re-implement features the HtmlView already has: text selection across blocks, clipboard formatting, link hit-testing, find-in-page, keyboard navigation. Each is bounded but still ~300-500 lines.
- PDF export needs to be wired up explicitly (uses the same canvas API, but it's not free).
- Inline math is genuinely hard without a real typesetter — likely punt to "code block" rendering.
- Two parallel rendering codebases to maintain long-term.
Comparison at a glance| Dimension | Option A (MD → HTML) | Option B (parallel) |
| New code added | ~1-2k lines | ~3-5k lines |
| Total engine cost | ~60k lines (HTML engine) | ~3-5k + common/ |
| Performance | HTML pipeline overhead | Single-pass, lean |
| Memory per doc | Higher (DOM + render tree + computed styles) | Low (flat node tree) |
| CommonMark compliance | Full, including raw HTML | MD subset, no HTML |
| GFM extensions | Easy to add (parser only) | Each requires layout work |
| Custom styling | Full CSS | Fixed theme record |
| PDF export | Free | Wire up via PdfCanvas |
| Selection / clipboard / links | Inherited | Reimplement |
| Best fit | Render arbitrary README files, full-fidelity docs | Chat / log / notes / in-app help |
The real decisionThe choice is essentially:
- A if the goal is "render arbitrary .md files, including ones from the wild" with full fidelity, and the engine size cost is acceptable.
- B if the goal is "fast, lean MD widget for our own content" where we control the input and never need HTML escape hatches, and minimising dependency footprint matters.
I am leaning towards option A. Thoughts?