Skip to main content

An mdformat plugin for slw

Project description

mdformat-slw

Build Status PyPI version

An mdformat plugin for semantic line wrapping (slw).

This plugin wraps markdown text by inserting line breaks after sentence-ending punctuation, making diffs cleaner and easier to review.

Features

  • Automatic sentence wrapping at configurable punctuation marks (default: .!?:)
  • Enabled by default - no flags needed to activate
  • Optional maximum line width enforcement with --slw-wrap
  • Preserves markdown formatting (bold, italic, links, etc.)
  • Handles edge cases: quoted text, parentheses, brackets

mdformat Usage

Add this package wherever you use mdformat and the plugin will be auto-recognized. Sentence wrapping is enabled by default. See additional information on mdformat plugins here

CLI

# Sentence wrapping enabled by default
mdformat document.md

# With line width enforcement
mdformat document.md --slw-wrap 80 --wrap=keep

# Disable sentence wrapping
mdformat document.md --no-wrap-sentences

Options

Basic Options:

  • --no-wrap-sentences: Disable sentence wrapping (enabled by default)
  • --slw-markers TEXT: Characters that mark sentence endings (default: .!?:)
  • --slw-wrap INTEGER: Maximum line width for wrapping (default: 80)

Abbreviation Detection:

  • --slw-lang TEXT: Space-separated language codes for abbreviation lists (default: ac)
    • Supported: ac (all-caps only), en, de, es, fr, it
  • --slw-abbreviations-mode TEXT: Abbreviation detection mode (default: default)
    • default: Use built-in language lists
    • off: Disable abbreviation detection
    • extend: Add custom abbreviations to built-in lists
    • override: Replace built-in lists with custom abbreviations
  • --slw-abbreviations TEXT: Comma-separated custom abbreviations (e.g., Dr.,Prof.,etc.)
  • --slw-suppressions TEXT: Space-separated words to add to suppression list
  • --slw-ignores TEXT: Space-separated words to remove from suppression list
  • --slw-case-sensitive: Enable case-sensitive abbreviation matching (default: case-insensitive)

Note: When using --slw-wrap, consider adding --wrap=keep to disable mdformat's built-in line wrapping and avoid conflicts.

Configuration File

Create a .mdformat.toml file in your project root:

[plugin.slw]
# Disable sentence wrapping (enabled by default)
no_wrap_sentences = false

# Customize sentence markers
slw_markers = ".!?:"

# Set line width wrapping (default: 80)
slw_wrap = 80

# Configure abbreviation detection
lang = "en de"  # Use English and German abbreviations
abbreviations_mode = "extend"  # Add custom to built-in lists
abbreviations = "Dr.,Prof.,etc."  # Custom abbreviations
case_sensitive = false  # Case-insensitive matching (default)

# Recommended: disable mdformat's wrapping to avoid conflicts
[mdformat]
wrap = "keep"

pre-commit / prek

repos:
  - repo: https://github.com/executablebooks/mdformat
    rev: 1.0.0
    hooks:
      - id: mdformat
        additional_dependencies:
          - mdformat-slw

uvx

uvx --with mdformat-slw mdformat

Or with pipx:

pipx install mdformat
pipx inject mdformat mdformat-slw
mdformat document.md

Python API

import mdformat

text = """
This is a test. It has multiple sentences! Does it work?
"""

# Sentence wrapping enabled by default
result = mdformat.text(text, extensions={"slw"})

print(result)
# Output:
# This is a test.
# It has multiple sentences!
# Does it work?

# With line width wrapping
result = mdformat.text(
    text,
    extensions={"slw"},
    options={"slw_wrap": 80}
)

# Disable sentence wrapping
result = mdformat.text(
    text,
    extensions={"slw"},
    options={"no_wrap_sentences": True}
)

Example

Basic Wrapping

Input:

This is a long sentence. It contains multiple clauses! Does it work? Yes it does.

Output (default behavior):

This is a long sentence.
It contains multiple clauses!
Does it work?
Yes it does.

Abbreviation Detection

Input:

Dr. Smith met with Prof. Johnson at 3 p.m. They discussed the project etc. and other topics.

Output (abbreviations preserved):

Dr. Smith met with Prof. Johnson at 3 p.m.
They discussed the project etc. and other topics.

Link Protection

Input:

Check [example.com](https://example.com). Use `config.json` for settings. Done!

Output (links and code preserved):

Check [example.com](https://example.com).
Use `config.json` for settings.
Done!

How It Works

Wrapping Rules

When one of the limited number of characters (.!?: by default) which serve as end-of-sentence markers occur alone, mdformat-slw will wrap except when:

  1. Not in a context where auto-wrapping is possible:
    • Inline code, links, definition lists, etc.
    • Code Blocks
    • Tables
    • HTML Blocks
  2. When the wrapped term is an abbreviation:
    • Multiple end-of-sentence markers occur (such as p.m. or e.g.)
    • Identified as an abbreviation from language-specific lists (Dr., Prof., etc., etc.)
    • Matched against custom abbreviations specified via --slw-abbreviations
    • Part of user-specified suppression words via --slw-suppressions
  3. Abbreviation matching is case-insensitive by default (use --slw-case-sensitive to change)

Algorithm

  1. Insert a line break after every character that ends a sentence which complies with the above rules and exceptions
  2. Collapse all consecutive whitespace into a single space. While doing so, preserve both non-breaking spaces and linebreaks that are preceded by non-breaking spaces
  3. Before line wrapping, replace all spaces in link texts by non-breaking spaces (and similar inline content that can't be wrapped)
  4. Wrap lines that are longer than the maximum line width, if set, (80 characters by default) without splitting words or splitting at non-breaking spaces while also keeping indents in tact.

Acknowledgments

This plugin is inspired by and named after mdslw by @razziel89. The original mdslw is an excellent standalone tool for semantic line wrapping of markdown files.

Why create mdformat-slw?

The mdformat ecosystem uses a plugin architecture where formatters must integrate with mdformat's AST-based processing pipeline. While mdslw works great as a standalone tool, it cannot be used as an mdformat plugin directly. This plugin reimplements semantic line wrapping concepts to work natively within mdformat, enabling:

  • Seamless integration with other mdformat plugins
  • Consistent formatting when mdformat is your primary markdown formatter
  • Use in pre-commit hooks alongside mdformat's other capabilities

The plugin is named slw (not mdslw) to clearly distinguish it from the original tool and avoid confusion, since the implementations differ.

Contributing

See CONTRIBUTING.md

Project 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_slw-0.2.0.tar.gz (14.3 kB view details)

Uploaded Source

Built Distribution

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

mdformat_slw-0.2.0-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

Details for the file mdformat_slw-0.2.0.tar.gz.

File metadata

  • Download URL: mdformat_slw-0.2.0.tar.gz
  • Upload date:
  • Size: 14.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for mdformat_slw-0.2.0.tar.gz
Algorithm Hash digest
SHA256 46c94f539e04b76022b6b720eb8c76c0f845aeaf4caf35d17b7f8a58a4f19da7
MD5 0c652136bed230285b4ed3fd1c01890a
BLAKE2b-256 be66d80c0ed97236516c64fedff2c58f5a59d85387501a53dc0ed30cc703b28e

See more details on using hashes here.

Provenance

The following attestation bundles were made for mdformat_slw-0.2.0.tar.gz:

Publisher: tests.yml on KyleKing/mdformat-slw

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mdformat_slw-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: mdformat_slw-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 15.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for mdformat_slw-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 923f850c9e14aadfd01410e94018d2e8981d1b3193923a35f9e01ec7b1aacd5e
MD5 bab288dde04fb53f09e2a91efad0748b
BLAKE2b-256 d750a5b7ab63069fbe8a42c174e30be5461a27a5d9f5ef2bba4e463e0bf35005

See more details on using hashes here.

Provenance

The following attestation bundles were made for mdformat_slw-0.2.0-py3-none-any.whl:

Publisher: tests.yml on KyleKing/mdformat-slw

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page