` | `` | nothing |
@@ -180,6 +182,60 @@ A wrapping markup covers as many runs as its content has, so the emitters ask
one per run. A stretch continues only while the layers enclosing it do, so regions nest rather than
cross.
+## Markdown
+
+`MarkupFormat.Markdown` writes GitHub-flavoured Markdown, for a wiki page or a README that stores it.
+`WithAnsi()` registers the whole format, as it does BBCode.
+
+```csharp
+var line = MarkupText.Concat([
+ MarkupText.Wrap(AnsiMarkup.Create(bold: true), "Note:"),
+ MarkupText.Plain(" see "),
+ MarkupText.Wrap(AnsiMarkup.Create(linkUrl: "https://example.com/rules"), "the rules"),
+ MarkupText.Plain(" for *everything*.")]);
+
+line.Render(MarkupFormat.Markdown); // **Note:** see [the rules](https://example.com/rules) for \*everything\*.
+```
+
+- **Styling** is what GitHub's Markdown has: bold `**`, italic `*`, strikethrough `~~`. Colour,
+ underline, faint, blink, overline and reverse video are dropped and the text kept, and `HtmlMarkup`'s
+ `b`, `i`, `s` and their kin fold in as they do for BBCode. Styling that carries on from one run into the
+ next is written once round both (`**a *b***`), kept off the whitespace at either end, and closed and
+ opened again round a line ending, since emphasis cannot cross a blank line. Markdown itself does not
+ read a delimiter between punctuation and a letter, as in `**Note:**text`; leave a space there.
+- **Links**: a URL link is `[text](address)`, its address percent-encoded where Markdown would end it
+ early (a space, parentheses, angle brackets, a backslash, a pipe); an address `UrlSafety` refuses, and a
+ command link, are their text. A picture is `` when its address is http(s) or
+ relative, and its text otherwise; a picture inside a link is a linked image. Points — sounds, a bell, a
+ clear — write nothing, and the rest of the shared vocabulary writes its text.
+- **Escaping** (`TextEncoding.Markdown`): `\`, `` ` ``, `*`, `_`, `[`, `]`, `<`, `|` and `~` are escaped
+ wherever they are, `&` where it would start an entity, and `#`, `>`, `-`, `+`, `=` and the `.` or `)` of a
+ list number at the start of a line, so stored text reads back as itself. Indentation at the start of a
+ line, which a reader would take for code, is dropped. A line ending is written `\n`, which Markdown
+ reads as a soft break inside a paragraph; a blank line is a new paragraph.
+
+A layout is drawn from its tree, with nothing laid out to a width: a `Table` is a pipe table, its delimiter
+row carrying each column's alignment and its cells escaped, a line ending in a cell written as `
`.
+
+```csharp
+var scores = new Table(
+ [new TableColumn(MarkupText.Plain("Name")), new TableColumn(MarkupText.Plain("Score")) { Alignment = Alignment.Right }],
+ [[new TextBlock(MarkupText.Plain("Lyra")), new TextBlock(MarkupText.Plain("10"))],
+ [new TextBlock(MarkupText.Plain("Bo|Ash")), new TextBlock(MarkupText.Empty)]]);
+
+BlockLayout.Build(scores, 78).Render(MarkupFormat.Markdown);
+// | Name | Score |
+// | --- | ---: |
+// | Lyra | 10 |
+// | Bo\|Ash | |
+```
+
+Lists are lists, a rule is `---`, and a box or a titled rule is its title in bold over what it holds; the
+[layout table](layout.md#how-it-fits-together) has every block. A cell holds one line, so a block in one is
+its lines joined by `
`, and a table in one is its rows as labelled values. Two lists in a row are written
+with different markers (`-` then `*`, `.` then `)`) so that a reader keeps them apart, and a block is set
+apart from the text around it by a blank line.
+
## Colour fidelity
`AnsiColor` is a closed union — `Default`, `Standard(index, bright)`, `Xterm(index)`, `Rgb(r,g,b)`
@@ -269,7 +325,7 @@ text.Render(Latex, registry);
```
Formats compare by name, case-insensitively, and `Custom` refuses a name that matches one of the
-six built-ins — otherwise you could address a built-in's registry slots under a different
+seven built-ins — otherwise you could address a built-in's registry slots under a different
`TextEncoding` and get output that is escaped for the wrong medium.
Writing the emitters themselves is [Custom markup kinds](custom-markup.md).
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 13d3c2f..e478d32 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -10,7 +10,7 @@ dotnet add package MarkupString.Html
`MarkupString` alone gives you the text type and every operation on it, but it renders nothing:
emitters live in the kind packages. Take `MarkupString.Ansi` for terminal styling (which also
-covers HTML, Pueblo, MXP and BBCode output of that styling, and links), and `MarkupString.Html` if
+covers HTML, Pueblo, MXP, BBCode and Markdown output of that styling, and links), and `MarkupString.Html` if
you also need raw tags such as `` or a ``.
Requires .NET 10 or later.
diff --git a/docs/layout.md b/docs/layout.md
index 51bb15f..ba9eb81 100644
--- a/docs/layout.md
+++ b/docs/layout.md
@@ -288,7 +288,9 @@ var text = BlockLayout.Build(finger, 78);
That is `text.ToPlainText()` and what every terminal format writes. `Render(MarkupFormat.Html)`
draws the same tree as a `