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
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mdformat_slw-0.4.0.tar.gz.
File metadata
- Download URL: mdformat_slw-0.4.0.tar.gz
- Upload date:
- Size: 17.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
93a8e40f47ab2ded82831c18264c3eb0356820602c63f3ab79bbc013c3dfb6a6
|
|
| MD5 |
8d1ea32e1186fe97569673b08878f82c
|
|
| BLAKE2b-256 |
dfe4875b5de5ab59c6f9c3d21e49d45245c7da0ebcae0f64b6ced9497e4bfd4a
|
Provenance
The following attestation bundles were made for mdformat_slw-0.4.0.tar.gz:
Publisher:
tests.yml on KyleKing/mdformat-slw
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mdformat_slw-0.4.0.tar.gz -
Subject digest:
93a8e40f47ab2ded82831c18264c3eb0356820602c63f3ab79bbc013c3dfb6a6 - Sigstore transparency entry: 2340735731
- Sigstore integration time:
-
Permalink:
KyleKing/mdformat-slw@8553711be804644e16cf92affa371680690c7516 -
Branch / Tag:
refs/tags/v0.4.1 - Owner: https://github.com/KyleKing
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
tests.yml@8553711be804644e16cf92affa371680690c7516 -
Trigger Event:
push
-
Statement type:
File details
Details for the file mdformat_slw-0.4.0-py3-none-any.whl.
File metadata
- Download URL: mdformat_slw-0.4.0-py3-none-any.whl
- Upload date:
- Size: 16.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8bbd18e8ec5facd383668bcc5a5cc14d53a58f16ffd47134631cef2ae66f8334
|
|
| MD5 |
a8dadf9079101c0277205db96ceb83d9
|
|
| BLAKE2b-256 |
04a02b29ed72e9afb60a93ec1d72ae2d079e46582919a5b794b7a22e268ece17
|
Provenance
The following attestation bundles were made for mdformat_slw-0.4.0-py3-none-any.whl:
Publisher:
tests.yml on KyleKing/mdformat-slw
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mdformat_slw-0.4.0-py3-none-any.whl -
Subject digest:
8bbd18e8ec5facd383668bcc5a5cc14d53a58f16ffd47134631cef2ae66f8334 - Sigstore transparency entry: 2340735740
- Sigstore integration time:
-
Permalink:
KyleKing/mdformat-slw@8553711be804644e16cf92affa371680690c7516 -
Branch / Tag:
refs/tags/v0.4.1 - Owner: https://github.com/KyleKing
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
tests.yml@8553711be804644e16cf92affa371680690c7516 -
Trigger Event:
push
-
Statement type: