I’m building a Markdown notes app for the Mac (Margin) where the file on disk stays plain Markdown, so I’ll disclose that up front and you can discount accordingly.
The editor is CodeMirror 6 on `@lezer/markdown` with a few inline extensions of my own. There’s no HTML render step anywhere: the document is always the Markdown source, and the rendered look is decorations painted over it, revealed back to raw markup when the cursor enters a node. So “which implementation do you render with” has a slightly odd answer, which is none.
What I keep running into isn’t parsing. It’s deciding what *not* to parse. Three cases, and I’m least sure about the third.
1. Embeds I can’t honour
I parse `[[wikilinks]]` as a single opaque inline node and render a page chip. I deliberately don’t match `![[embed]]`. Transclusion isn’t supported, and in practice most embeds point at images rather than notes, so claiming the token would turn a working image embed into a page chip that goes nowhere. Left unmatched it stays plain text, which is at least honest about what the app does.
Precedence note for anyone doing the same: the wikilink parser has to run `before: “Link”`, or `[[Name]]` is taken as a bracketed shortcut reference before you ever see it.
2. Tables that aren’t quite tables
My table parser returns null for anything that isn’t a well-formed GFM pipe table, and the caller falls back to rendering the source as plain text. The alternative is guessing at a repair, and a guessed repair means a malformed table silently becomes a *different* table the first time it round-trips, with the original gone.
Related, and the thing that actually cost me a weekend: GFM splits cells on pipes before inline parsing, so a literal `|` inside an inline code span in a table still has to be written `\|`. The backslash is eaten by the table parser, not by the code span. Everyone I’ve watched hit this assumes the code span protects the pipe, which is a very reasonable thing to assume.
3. Display options with nowhere to live
This is the one I’d like opinions on. A table can be striped, or have its header row hidden. That’s presentation, GFM has no way to express it, and I didn’t want to invent syntax that every other tool renders as garbage. What I do now is put an HTML comment on the line above:
<!-- margin-table-noheader -->
| Item | Qty |
| ---- | --- |
A comment renders as nothing everywhere else, so the file stays valid and readable in any other editor. But it’s positional, it’s invisible to anyone reading the raw file who doesn’t know the convention, and it is plainly not what HTML comments are for.
The generic directives thread has been running here for years and `:::` fenced directives would be the principled answer, except almost nothing else renders those either, so I’d be trading an invisible comment for a visible block of syntax that degrades worse in the tools my users actually open these files in.
For anyone who has shipped an app with presentation state that Markdown can’t express: HTML comments, directives, a frontmatter key, or did you land on it not belonging in the file at all?
(Margin is not downloadable yet. Waitlist is at https://gomargin.app/cm if the plain-files part is interesting)