Fence normalization

Version 0.5.0 Updated Jul 27, 2026

Pass --fences to normalize fenced code blocks before later processing. Safe outer fences are compressed to three backticks, which keeps simple code blocks consistent before later formatting steps run. Indentation and any language identifiers are preserved.

Outer delimiters are compressed only when doing so is structurally safe. If normalization would turn an inner literal fence into a structural close, the outer fence is kept, so the inner content remains literal. Preservation applies when the inner fence uses the same marker character as the outer fence, or when a tilde outer fence wraps a literal inner backtick fence.

A fence closes only on a bare marker line (``` or ~~~) optionally followed by ASCII spaces or tabs. A same-marker line that also carries an info string — trailing non-whitespace text — is literal content rather than a closing fence, per CommonMark. This keeps pipe lines and other content inside such blocks verbatim.

If a language specifier starts a block, either at the start of the file or immediately after a blank line, and appears before the next unlabelled opening fence with only blank lines in between, mdtablefix attaches it to that fence and drops the blank lines when attachment succeeds. Specifiers that follow prose or other content are intentionally not attached. If no suitable fence follows, the specifier line and any intervening blank lines are left unchanged, preserving document spacing. Orphan-specifier attachment only happens when the identifier line starts a block and both the identifier line and the target fence are outside any already-open fenced block.

Before:

````markdown
```rust
fn main() {}
```
````

After running mdtablefix --fences:

````markdown
```rust
fn main() {}
```
````

Before:

```rust
fn main() {}
```

After running mdtablefix --fences:

```rust
fn main() {}
```