An mdformat plugin for slw
Project description
mdformat-slw
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
- Supported:
--slw-abbreviations-mode TEXT: Abbreviation detection mode (default:default)default: Use built-in language listsoff: Disable abbreviation detectionextend: Add custom abbreviations to built-in listsoverride: 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=keepto 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:
- Not in a context where auto-wrapping is possible:
- Inline code, links, definition lists, etc.
- Code Blocks
- Tables
- HTML Blocks
- When the wrapped term is an abbreviation:
- Multiple end-of-sentence markers occur (such as
p.m.ore.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
- Multiple end-of-sentence markers occur (such as
- Abbreviation matching is case-insensitive by default (use
--slw-case-sensitiveto change)
Algorithm
- Insert a line break after every character that ends a sentence which complies with the above rules and exceptions
- 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
- Before line wrapping, replace all spaces in link texts by non-breaking spaces (and similar inline content that can't be wrapped)
- 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
Release history Release notifications | RSS feed
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.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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
46c94f539e04b76022b6b720eb8c76c0f845aeaf4caf35d17b7f8a58a4f19da7
|
|
| MD5 |
0c652136bed230285b4ed3fd1c01890a
|
|
| BLAKE2b-256 |
be66d80c0ed97236516c64fedff2c58f5a59d85387501a53dc0ed30cc703b28e
|
Provenance
The following attestation bundles were made for mdformat_slw-0.2.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.2.0.tar.gz -
Subject digest:
46c94f539e04b76022b6b720eb8c76c0f845aeaf4caf35d17b7f8a58a4f19da7 - Sigstore transparency entry: 731849918
- Sigstore integration time:
-
Permalink:
KyleKing/mdformat-slw@20a2678e78da054b7e44013ee35cf953e328aeed -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/KyleKing
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
tests.yml@20a2678e78da054b7e44013ee35cf953e328aeed -
Trigger Event:
push
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
923f850c9e14aadfd01410e94018d2e8981d1b3193923a35f9e01ec7b1aacd5e
|
|
| MD5 |
bab288dde04fb53f09e2a91efad0748b
|
|
| BLAKE2b-256 |
d750a5b7ab63069fbe8a42c174e30be5461a27a5d9f5ef2bba4e463e0bf35005
|
Provenance
The following attestation bundles were made for mdformat_slw-0.2.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.2.0-py3-none-any.whl -
Subject digest:
923f850c9e14aadfd01410e94018d2e8981d1b3193923a35f9e01ec7b1aacd5e - Sigstore transparency entry: 731849921
- Sigstore integration time:
-
Permalink:
KyleKing/mdformat-slw@20a2678e78da054b7e44013ee35cf953e328aeed -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/KyleKing
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
tests.yml@20a2678e78da054b7e44013ee35cf953e328aeed -
Trigger Event:
push
-
Statement type: