mdformat-slw
An mdformat plugin for semantic line wrapping (slw), which breaks lines after sentence-ending punctuation so that diffs stay small and readable.
Wrapping is on by default. A break is inserted after each end-of-sentence marker (.!?) except when:
- The line is shorter than the minimum length (40 characters by default), which keeps short sentences together. Set
--slw-min-line=0to always wrap - The text can't be wrapped: inline code, links, definition lists, code blocks, tables, and HTML blocks
- The marker ends an abbreviation, either because multiple markers occur (
p.m.,e.g.) or because the word is in the language list or in--slw-abbreviations. Matching is case-insensitive
The algorithm collapses consecutive whitespace to a single space (preserving non-breaking spaces and the linebreaks that follow them), finds the protected regions, inserts the sentence breaks, replaces spaces in link text with non-breaking spaces, and finally wraps anything still longer than --slw-wrap without splitting words or indents.
For examples, see ./tests/pre-commit-test.md and ./tests/format/fixtures
mdformat Usage
Add this package wherever you use mdformat and the plugin will be auto-recognized. For additional information on plugins, see the official mdformat documentation here
mdformat document.md
# Recommended when using --slw-wrap, because --wrap=keep turns off mdformat's own wrapping
mdformat document.md --slw-wrap=88 --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
Configuration
mdformat-slw adds the CLI arguments:
--no-wrap-sentencesto turn off sentence wrapping--slw-markersfor the characters that end a sentence (default:.!?)--slw-wrapfor the maximum line width (default:88, set to0to disable)--slw-min-linefor the shortest line that may be wrapped (default:40, set to0to always wrap)--slw-langfor the built-in abbreviation list (default:ac, one ofac,en,de,es,fr, orit)--slw-abbreviationsfor a comma-separated list of extra abbreviations, such as"NASA,FBI,CustomCorp"--slw-abbreviations-onlyto use only those abbreviations and skip the language list
You can also use the toml configuration (https://mdformat.readthedocs.io/en/stable/users/configuration_file.html):
# .mdformat.toml
[plugin.slw]
no_wrap_sentences = false
slw_markers = ".!?"
slw_wrap = 88
slw_min_line = 40
lang = "en"
abbreviations = "Corp,Inc,NASA"
abbreviations_only = false
[mdformat]
wrap = "keep"
Or the Python API:
import mdformat
mdformat.text("This is a test. It has multiple sentences!", extensions={"slw"})
# 'This is a test. It has multiple sentences!\n'
mdformat.text("This is a test. It has multiple sentences!", extensions={"slw"}, options={"slw_min_line": 0})
# 'This is a test.\nIt has multiple sentences!\n'
Example
Dr. Smith met with Prof. Johnson at 3 p.m. to review the draft. They discussed the wrapping rules etc. and agreed on the defaults.
Becomes:
Dr. Smith met with Prof. Johnson at 3 p.m. to review the draft.
They discussed the wrapping rules etc. and agreed on the defaults.
p.m. and etc. are abbreviations, so no break follows them.
Language Support
Abbreviation lists are built in for ac (Author's Choice, the 77-abbreviation default covering titles, time, Latin, academic, business, and geography terms), en (17), de (54), es (36), fr (42), and it (40).
mdformat-slw targets non-symbolic, left-to-right languages. Sentence detection relies on whitespace after a marker and wrapping relies on space-delimited words, but neither are applicable CJK or RTL scripts. Doing those properly means Unicode line breaking (UAX #14), kinsoku shori, word segmentation, and bidi handling, which is a different project, so they aren't planned:
- CJK text has no spaces between sentences, so no boundaries are found. The text passes through unchanged (wcwidth accounts for double-width characters when measuring line length), and wrapping only applies if you space the sentences yourself, e.g.
これは最初の文です。 これは2番目の文です。, and set--slw-markers=".!?。!?". Seetests/format/fixtures/lang_ja.mdandlang_ko.md - Arabic and other RTL text gets no bidi handling, and the native punctuation (
؟U+061F,،U+060C,؛U+061B) isn't in the default marker set. ASCII markers still work and--slw-markers/--slw-abbreviationscan add the rest for partial support
Acknowledgments
This plugin is inspired by and named after razziel89/mdslw, which is an excellent standalone tool for semantic line wrapping. mdslw can't be used as an mdformat plugin because mdformat formats from its own AST, so this package reimplements the idea natively, which lets it run alongside other mdformat plugins and in the same pre-commit hook. Overtime, the implementations have diverged, but I'm always open to submissions and feature requests to continually improve the developer experience.
Contributing
See CONTRIBUTING.md
Metadata
Release files for mdformat-slw 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mdformat_slw-0.4.0.tar.gz | 17.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mdformat_slw-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 33.8 kB
Release files / mdformat_slw-0.4.0.tar.gz
| Download URL | mdformat_slw-0.4.0.tar.gz |
|---|---|
| Size | 17.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
93a8e40f47ab2ded82831c18264c3eb0356820602c63f3ab79bbc013c3dfb6a6
|
|
BLAKE2b-256 checksum How to use checksums |
dfe4875b5de5ab59c6f9c3d21e49d45245c7da0ebcae0f64b6ced9497e4bfd4a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 4, 2026.
Transparency logRelease files / mdformat_slw-0.4.0-py3-none-any.whl
| Download URL | mdformat_slw-0.4.0-py3-none-any.whl |
|---|---|
| Size | 16.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8bbd18e8ec5facd383668bcc5a5cc14d53a58f16ffd47134631cef2ae66f8334
|
|
BLAKE2b-256 checksum How to use checksums |
04a02b29ed72e9afb60a93ec1d72ae2d079e46582919a5b794b7a22e268ece17
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 4, 2026.
Transparency log