rumdl 0.2.75

A fast Markdown linter and formatter written in Rust
Documentation
# MD090 - Horizontal rules should not precede headings

Aliases: `no-hr-before-heading`

**Disabled by default.** This rule is opt-in: enable it explicitly with
`extend-enable`. There is no markdownlint equivalent; this is a rumdl-specific
structure rule.

## What this rule does

Flags a horizontal rule (`---`, `***`, `___`, or a spaced form such as `- - -`)
whose only separation from the heading below it is blank lines. The heading
already marks the section boundary, so the rule draws the same line twice.

Only blank lines may sit between the rule and the heading. A comment, a
reference definition, or any other line in between means the rule is not
directly above the heading, and nothing is reported. Both the rule and the
heading must be at the top level of the document: a horizontal rule inside a
blockquote or a list item belongs to that container and is left alone.
Containers whose body is ordinary Markdown, such as a fenced div or a MyST
directive, are treated like top-level content, so a rule directly above an
ATX heading inside one is still reported. Only ATX headings are reported
there: a container's opening marker followed by a dash run
(`::: note` above `---`) is parsed as a setext heading though it opens a
container rather than a section, and since removing a rule deletes a line,
this rule leaves every setext heading inside a container alone rather than
guessing which ones are real.

Containers whose body is indented rather than fenced, such as a MkDocs
admonition or a content tab, are not reported at all: an indented dash run
is not read as a horizontal rule anywhere in rumdl. A MyST directive written
with backticks (```` ```{note} ````) rather than colons is silent for the same
reason: its body starts out as a code fence, so nothing inside it is read as a
horizontal rule. Write the directive with colons to have it checked.

A `---` written directly under a line of text is not a horizontal rule at all.
It is the underline of a setext heading, and this rule never touches it.

## Why this matters

Generated Markdown, LLM output in particular, separates almost every section
with a horizontal rule right before the next heading. Rendered, that is a line
followed by a larger, bolder line; in source it is noise between sections that
the headings already delimit. Removing the redundant rules keeps the heading
structure as the single expression of the document's outline.

## Why it is opt-in

Slide formats (Marp, Slidev, reveal.js, Pandoc slide decks) use a horizontal
rule as the slide separator, and the next slide almost always opens with a
heading. In those documents every rule this check would remove is a slide
boundary, so the rule stays off unless a project turns it on.

## Configuration

This rule has no configuration options.

```toml
[global]
extend-enable = ["MD090"]
```

## Examples

### Incorrect

```markdown
## Topic

Prose.

---

## Next Topic
```

### Correct

```markdown
## Topic

Prose.

## Next Topic
```

A horizontal rule between two paragraphs is fine; the rule only speaks when a
heading follows:

```markdown
Prose.

---

More prose under the same heading.
```

## Automatic fixes

The rule is removed together with the blank lines between it and the heading.
The blank line above the rule is kept, so the heading stays separated from the
paragraph before it. When no blank line sits above the rule, the fix leaves
one behind, so the text above never touches the heading. A run of rules
directly above one heading is removed in one pass.

## Related rules

- [MD022 - Add blank lines around headings]md022.md
- [MD035 - Keep line breaks consistent]md035.md
- [MD065 - Blank lines around horizontal rules]md065.md
- [MD082 - Headings should have content before the next heading]md082.md