Skip to content

Markdown

Files ending in .md or .markdown are formatted by the Markdown pack (rainbow_fmt.languages.markdown, grammar tree-sitter-markdown, block grammar only).

# Title
Some   *text*   with   inline   spacing   kept.
-   an item
    continued
- another
| a | bb |
|-|:-:|
| 1 | 22 |
```python
x = {'a':1,'b':2}
```

becomes

# Title

Some   *text*   with   inline   spacing   kept.

- an item
  continued
- another

| a   | bb  |
| --- | :-: |
| 1   | 22  |

```python
x = {'a': 1, 'b': 2}
```

What changes and what does not

The pack formats the block structure of a document and prints the text inside the blocks as written: it never rewraps paragraphs, changes emphasis markers, escapes or link syntax, or touches the words.

  • Blocks are separated by one blank line; up to core.max_blank_lines (default 1) written blank lines are kept. Blank lines at the start and end of the file go.
  • Inside a list the blank lines are as written (capped the same way), so a tight list stays tight and a loose one loose. Items are printed as their marker (-, +, *, 1., 1), a task box [ ]/[x], each as written), one space, and the item's blocks aligned under the first; a nested list is indented by the width of its parent's marker. Numbers are not renumbered.
  • Pipe tables are aligned column by column: every cell padded to the widest cell in its column (at least three characters), the delimiter row made of dashes to the same width with its alignment colons kept, and every row given leading and trailing pipes. A table whose aligned rows would be wider than table_width (180 columns by default) is written condensed instead — one space around each cell, --- delimiters — since padding such a table only moves the long cells further apart.
  • The content of a fenced code block whose info string starts with a language rainbow-fmt formats (python/py, javascript/js/jsx, typescript/ts, json/jsonc, css, html, svelte, toml, yaml/yml, sql; case does not matter, the rest of the info string is ignored) is formatted by that pack with the options the same configuration gives that language ([language.python] and so on), as a file of that language would be. Content with syntax errors, and code in other languages, is printed as written. The fences and the info string are as written.
  • Headings, paragraphs, block quotes, HTML blocks, indented code, link reference definitions and thematic breaks are printed as written; inside a list item they are re-indented with the item. (A block quote is one block: a list or table inside it is not formatted.)
  • Line endings follow core.line_ending; trailing whitespace is removed except inside rainbow: off regions.

Embedded code is indented with the host document's core.indent_size (4 by default), as embedded code is in HTML: a Python block indents with 4 spaces, and YAML, which indents with spaces of its own (indent_size 2 for YAML files), keeps its own width.

Options

Key Values Default
language.markdown.fenced_code "format": fenced code in a language rainbow-fmt formats is formatted by that pack; "preserve": every fence as written "format"
language.markdown.table_width integer ≥ 1: the widest row an aligned pipe table may have; a wider table is written condensed:
\| a \| b \|
\| --- \| --- \|
180

Set fenced_code = "preserve" for documentation whose code blocks show code before formatting (as this repository's does), or put <!-- rainbow: skip-next --> before such a block.

Directives

An HTML comment on a line of its own carries a directive:

<!-- rainbow: off -->
| a hand-aligned table | kept   as   written |
|----------------------|---------------------|
<!-- rainbow: on -->

<!-- rainbow: skip-next -->
- a   list   printed   as   written

off … on and skip-next print the blocks they cover exactly as written (blank lines included); the other directives (skip-line, set) are not supported in Markdown and are reported as errors. Code in a fenced block can use the directives of its own language (# rainbow: off in Python).

What the verifier checks

As for every pack, the output is parsed again and compared with the input: the same blocks with the same children, every token's text equal with whitespace runs collapsed where the pack re-indents (a paragraph's lines, a list marker's spacing, a table cell's padding; the | the pack adds around table rows and the dashes of a delimiter row are optional), and the content of a fenced block in a formatted language compared by that language's rules. Formatting must be stable: a second pass changes nothing.

Known limitations

  • tree-sitter-markdown 0.5.1 rejects a heading at the very end of a file without a final newline; the pack adds one before parsing, so such files format normally.
  • A fenced block inside a list item is formatted with the item's indentation removed, but the verifier compares its content with the indentation still there, so code whose formatting changes more than whitespace (a quote style, say) inside a list item is reported as a meaning change; use <!-- rainbow: skip-next --> on such an item, or move the code out of the list.
  • Markdown in a Markdown fence is printed as written.