Skip to main content

mdformat-space-control

Build Status PyPI version

An mdformat plugin that provides unified control over Markdown spacing:

  • EditorConfig support: Configure list indentation via .editorconfig files
  • Tight list formatting: Automatically removes unnecessary blank lines between list items
  • Frontmatter spacing: Normalizes spacing after YAML frontmatter (works with mdformat-frontmatter)
  • Consecutive blank line normalization: Limits runs of 3+ empty lines to a maximum of 2
  • Trailing whitespace removal: Strips trailing whitespace outside code blocks
  • Escaped link repair: Fixes malformed multi-line links from web-clipped content
  • Smart dash conversion: Converts -- to en-dash (–) and --- to em-dash (—), preserving code blocks, inline code, HTML comments, and HTML tags
  • Wikilink preservation: Handles Obsidian-style [[links]], [[links|aliases]], [[page#heading]], [[page#^blockid]], and ![[embeds]]
  • Soft break joining: Joins soft breaks (plain newlines within paragraphs) into single lines, normalizing to single-line paragraphs

Installation

pip install mdformat-space-control

Or with pipx for command-line usage:

pipx install mdformat
pipx inject mdformat mdformat-space-control

Usage

After installation, mdformat will automatically use this plugin:

mdformat your-file.md

EditorConfig Support

Create an .editorconfig file in your project:

# .editorconfig
root = true

[*.md]
indent_style = space
indent_size = 4

Nested lists will use the configured indentation:

Before:

- Item 1
  - Nested item
- Item 2

After (with 4-space indent):

- Item 1
    - Nested item
- Item 2

Tight List Formatting

Lists with single-paragraph items are automatically formatted as tight lists:

Before:

- Item 1

- Item 2

- Item 3

After:

- Item 1
- Item 2
- Item 3

Multi-paragraph items preserve loose formatting:

- First item with multiple paragraphs

  Second paragraph of first item

- Second item

Frontmatter Spacing

When used with mdformat-frontmatter, this plugin removes blank lines between the frontmatter closing delimiter and the first content block:

Before:

---
title: My Document
---


# Introduction

After:

---
title: My Document
---
# Introduction

Install both plugins for this feature:

pip install mdformat-space-control mdformat-frontmatter

EditorConfig Properties

Property Status Notes
indent_style Supported space or tab for list indentation
indent_size Supported Number of spaces per indent level
tab_width Supported Used when indent_size = tab

Python API

When using the Python API, you can set the file context for EditorConfig lookup:

import mdformat
from mdformat_space_control import set_current_file

set_current_file("/path/to/your/file.md")
try:
    result = mdformat.text(markdown_text, extensions={"space_control"})
finally:
    set_current_file(None)

Smart Dash Conversion

Markdown dash sequences are automatically converted to their Unicode equivalents:

  • -- → en-dash (–, U+2013)
  • --- → em-dash (—, U+2014)

Before:

The result---unexpected as it was---changed everything.
Pages 10--20 of the report.

After:

The result—unexpected as it was—changed everything.
Pages 10–20 of the report.

Dashes are preserved inside fenced code blocks, inline code spans, HTML comments, and HTML tags. Thematic breaks (---), GFM table separator rows (| -- | -- |), and frontmatter delimiters are not affected. Sequences of 4+ dashes are left unchanged.

These exclusions apply equally inside blockquotes, at any nesting depth: leading > markers are stripped before block-level patterns are matched, so tables and code fences in a blockquote or Obsidian callout are preserved just as they are at the top level.

Wikilink Preservation

Obsidian-style wikilinks are preserved during formatting:

Link to [[another note]] or [[note|with alias]].
Embed an image: ![[photo.jpg]]
Link to heading: [[note#section]]
Block reference: [[note#^blockid]]

Wikilinks inside markdown link text are correctly handled without duplication:

[![[image.jpg]]](http://example.com)

Literal square brackets inside a target are preserved (e.g. a note titled like an email subject), and are not escaped as stray link syntax:

[[[EXTERNAL] requesting feedback]]

Inside GFM table cells, an alias pipe is escaped to \| so the table parser does not split the wikilink across two columns (this requires mdformat-gfm). The escaped pipe renders correctly in Obsidian, and prose wikilinks keep a bare |:

| Note | Status |
| -- | -- |
| [[path/to/note|Short Alias]] | Active |

Soft Break Joining

Soft breaks (plain newlines within paragraphs) are joined into single lines with spaces. This normalizes editor-inserted line wraps to single-line paragraphs, matching CommonMark rendering behavior where soft breaks produce spaces in HTML output. The joining applies to paragraphs, list items, and blockquotes.

Before:

This is a paragraph with
a soft line break in the source.

After:

This is a paragraph with a soft line break in the source.

Explicit hard breaks (\ + newline) are preserved unchanged.

Compatible Plugins

This plugin is tested to work alongside:

For formatting files in an Obsidian vault, the recommended install is:

pip install mdformat-space-control mdformat-frontmatter mdformat-gfm

Note: Wikilink support is built-in; mdformat-wikilink is not needed.

Development

# Install dependencies
uv sync

# Run tests
uv run python -m pytest

# Run with coverage
uv run python -m pytest --cov=mdformat_space_control

License

MIT - see LICENSE file for details.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mdformat_space_control-0.4.10.tar.gz (24.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mdformat_space_control-0.4.10-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

File details

Details for the file mdformat_space_control-0.4.10.tar.gz.

File metadata

  • Download URL: mdformat_space_control-0.4.10.tar.gz
  • Upload date:
  • Size: 24.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.14

File hashes

Hashes for mdformat_space_control-0.4.10.tar.gz
Algorithm Hash digest
SHA256 4b6860836c847ab1fb48981d58132b5c802ae21f63d72bb2a8c4e6d138b6ad82
MD5 710ce5b6959a459ca6b2e4914e3052d6
BLAKE2b-256 ecd2cc0c243eaa565cc9d4371241294c899f0bc051545ae0c9b418c0d52392f4

See more details on using hashes here.

File details

Details for the file mdformat_space_control-0.4.10-py3-none-any.whl.

File metadata

File hashes

Hashes for mdformat_space_control-0.4.10-py3-none-any.whl
Algorithm Hash digest
SHA256 3834343c9b297e017db7196a55026da0b13048911e45eef8beafa04d945afa82
MD5 d2057b3c83fdaeec69ed19e36956a00f
BLAKE2b-256 6325ec56bd6079b0437aec68fbc453185a25bf9516ffcda44d0ce7007f9c6d70

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.4.10 This release

2 files

0.4.9

2 files

0.4.8

2 files

0.4.7

2 files

0.4.6

2 files

0.4.5

2 files

0.4.4

2 files

0.4.3

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.3.2

2 files

0.3.0

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page