rumdl 0.2.38

A fast Markdown linter written in Rust (Ru(st) MarkDown Linter)
Documentation
# MD077 - List continuation content indentation

Aliases: `list-continuation-indent`

## What this rule does

Checks that continuation content inside a list item lines up with the item's
content column (the W+N rule from the CommonMark spec). Two mistakes are flagged:

- **Under-indentation after a blank line**, which lets the content escape the
  list item and render as a separate paragraph.
- **Over-indentation**, in both tight continuation (no blank line) and loose
  continuation (after a blank line), which pushes the body past the content
  column so it no longer aligns under the item text.

Content indented to the content column + 4 or more after a blank line is an
indented code block, not continuation, and is left untouched. Under the MkDocs
flavor, a minimum of 4 spaces is enforced to satisfy Python-Markdown's stricter
requirement.

## Why this matters

- **Rendering correctness**: Insufficient indentation after a blank line causes
  the content to "escape" the list item. Most renderers will close the list and
  render the content as a separate paragraph, which is usually not what the
  author intended.
- **MkDocs compatibility**: Python-Markdown (used by MkDocs) requires at least
  4 spaces of indentation for ordered list continuation, even when the marker is
  only 3 characters wide (e.g., `1. `). CommonMark accepts 3 spaces in this
  case, so documents can silently break when deployed to MkDocs.

## Examples

### Unordered list

#### Correct

```markdown
- Item

  Continuation paragraph (2-space indent matches `- ` marker width).
```

#### Incorrect

```markdown
- Item

 Continuation paragraph (1-space indent — not enough for `- ` marker).
```

> **Note**: Content at 0 indent after a blank line starts a new paragraph and is
> not flagged. MD077 only flags content with *partial* indentation (above the
> marker column but below the content column), which signals an indentation
> mistake rather than an intentional new paragraph.

### Ordered list (CommonMark)

#### Correct

```markdown
1. Item

   Continuation paragraph (3-space indent matches `1. ` marker width).
```

#### Incorrect

```markdown
1. Item

  Continuation paragraph (2-space indent — not enough for `1. ` marker).
```

### Ordered list (MkDocs flavor)

#### Correct

```markdown
1. Item

    Continuation paragraph (4-space indent required by Python-Markdown).
```

#### Incorrect

```markdown
1. Item

   Continuation paragraph (3 spaces — valid CommonMark but breaks in MkDocs).
```

### Multi-digit markers

```markdown
10. Item

    Continuation paragraph (4-space indent matches `10. ` marker width).
```

## Flavor-aware behavior

| Flavor   | Required indent                          |
| -------- | ---------------------------------------- |
| Standard | content column (W+N from marker width)   |
| MkDocs   | max(content column, 4)                   |

Under MkDocs flavor, both ordered and unordered list items require at least
4 spaces of continuation indent to ensure Python-Markdown compatibility.

## Code blocks inside list items

An **under-indented** fenced code block (`` ``` `` or `~~~`) is checked and
fixed, because too little indentation lets the block escape the list item. The
content *between* the fences is not inspected for its own indentation; only the
opener and closer lines decide whether the block belongs to the list item.

```markdown
1. Item

    ```toml        ← checked (fence opener)
    key = "value"  ← not checked (code content)
    ```             ← checked (fence closer)
```

> **Note**: The automatic fix for an under-indented block reindents the fence
> opener and closer up to the list item's content column. Interior lines that
> sit *below* the content column are promoted up to it (so the fence stays
> paired inside the list item's scope); interior lines already at or above the
> content column keep their indent. You may still want to manually adjust
> interior alignment for visual consistency.

> **Over-indented code blocks are left untouched.** An over-indented fenced
> block still renders correctly inside the list item, and moving only its
> delimiters (the body is not reindented) would change the literal code
> content. So unlike prose, an over-indented code block is not flagged or
> fixed.

## Tight continuation (no blank line)

Content that directly follows a list item without a blank line is called "tight
continuation." MD077 flags tight continuation lines that are **over-indented** —
indented beyond the item's content column:

```markdown
1. Item
    Over-indented continuation (4 spaces — should be 3 for `1. `).
```

The same normalization applies **after a blank line** (loose continuation). A
body line indented past the content column, but not far enough to become an
indented code block (content column + 4), is snapped back to the content column:

```markdown
* Item

   Over-indented after a blank line (3 spaces, snapped back to 2 for `* `).
```

Zero-indent lazy continuation is valid CommonMark and is not flagged:

```markdown
- Item
continuation (lazy — not flagged by MD077)
```

Correctly indented tight continuation is also not flagged:

```markdown
1. Item
   Correctly indented continuation (3 spaces matches `1. ` width).
```

## GFM task list items

Task list items (`- [ ] `, `- [x] `, `- [X] `, and the same with `*`, `+`,
or ordered markers) accept two valid continuation columns:

1. The item's CommonMark content column (same as for any other list item).
2. The column *after* the checkbox prefix — `content_column + 4` for
   `[ ] `, `[x] `, or `[X] `.

Both layouts are treated as correct so MD077 does not fight with
[MD013](md013.md)'s `reflow-mode = "normalize"`, which wraps long task
items at the post-checkbox column to keep the text visually aligned under
the task body. Without this accommodation MD077 would re-flag every
reflowed task line and the fix loop would never converge.

```markdown
- [ ] Long task text
  continuation at column 2 (content column) — valid.

- [ ] Long task text
      continuation at column 6 (post-checkbox) — valid.

- [ ] Long task text
    continuation at column 4 — flagged (neither column).
```

When a continuation is flagged, the auto-fix snaps to the *nearer* of the
two valid columns. For example, `       wrap` (7 spaces) under `- [ ] `
is 1 away from column 6 and 5 away from column 2, so it's repaired to 6
— preserving the author's apparent intent to align after the checkbox.

### Equidistant ties: context-aware resolution

When the flagged indent is *exactly* equidistant from both valid columns
(for example, 4 spaces under `- [ ] `, which is 2 away from both column
2 and column 6), the fix looks at other continuation lines in the same
item to infer which column the author is already using. The tie resolves
to that column:

| Siblings at content col | Siblings at task col | Tie resolves to |
| ----------------------- | -------------------- | --------------- |
| no                      | no                   | content col     |
| yes                     | no                   | content col     |
| no                      | yes                  | task col        |
| yes                     | yes                  | content col     |

When siblings exist at *both* valid columns the author's pattern is
self-contradictory, so the fix falls back to the CommonMark-canonical
content column. When no siblings give a signal, the fix also falls back
to the content column.

## Configuration

```toml
[MD077]
# How strictly continuation-line indentation is enforced.
#   "any"     - (default) permit any indent in [0, content column], i.e.
#               CommonMark lazy continuation. Only over-indentation and content
#               that escapes the list after a blank line are flagged.
#   "aligned" - require every continuation line to align to its item's content
#               column (mdformat parity). Tight under-indented lazy
#               continuation is additionally flagged and snapped up.
style = "any"
```

### `style = "aligned"`

By default (`style = "any"`), a wrapped list item may continue at zero indent
(lazy continuation) or at the content column, and both are accepted. This means
a single list can mix the two styles:

```markdown
- a long line
that continues at column 0
- another long line
  that continues at the content column
```

With `style = "aligned"`, every continuation line must sit at the item's content
column, so the document above is normalized to a single consistent style:

```markdown
- a long line
  that continues at the content column
- another long line
  that continues at the content column
```

Notes on `aligned`:

- **GFM task items** still accept the post-checkbox column (`content column + 4`)
  in addition to the content column, so `aligned` does not fight
  [MD013]md013.md's `reflow-mode = "normalize"`.
- **Structural blocks are left alone.** A blockquote, fenced code block, or
  table that sits tight under a list item is a list-breaking construct, not
  prose continuation, so `aligned` never reindents it (doing so would pull it
  into the item and change the rendered structure).
- **Nested lists**: a tight lazy continuation that follows a nested item is, per
  CommonMark, continuation of the *innermost* open item, so it aligns to that
  inner item's content column.
- There is intentionally no "flush to column 0" style: after a blank line,
  zero-indent content is a new paragraph that has left the list, so it cannot be
  enforced as a consistent continuation style.

## Automatic fixes

This rule can automatically fix violations by adjusting the leading whitespace
to the required indent level.

```bash
rumdl check --fix document.md
```

## Related rules

- [MD005 - Inconsistent indentation for list items at the same level]md005.md
- [MD007 - Unordered list indentation]md007.md
- [MD013 - Line length (`reflow-mode = "normalize"` produces post-checkbox
  alignment for wrapped task items)](md013.md)
- [MD030 - Spaces after list markers]md030.md
- [MD076 - List item spacing should be consistent]md076.md