| Crates.io | mdtablefix |
| lib.rs | mdtablefix |
| version | 0.3.1 |
| created_at | 2025-11-08 19:41:37.053648+00 |
| updated_at | 2025-11-08 19:41:37.053648+00 |
| description | `mdtablefix` unb0rks and reflows Markdown tables so that each column has a uniform width. When the `--wrap` option is used, it also wraps paragraphs and list items to 80 columns. |
| homepage | |
| repository | |
| max_upload_size | |
| id | 1923207 |
| size | 529,728 |
mdtablefix unb0rks and reflows Markdown tables so that each column has a
uniform width. When the --wrap option is used, it also wraps paragraphs and
list items to 80 columns.
Hyphenated words are treated as indivisible during wrapping, so
very-long-word will move to the next line intact rather than split at the
hyphen. The tool ignores fenced code blocks and respects escaped pipes (\|),
making it safe to use on Markdown with mixed content.
Install via Cargo:
cargo install mdtablefix
Or clone the repository and build from source:
cargo install --path .
mdtablefix [--version] [--wrap] [--renumber] [--breaks] [--ellipsis] [--fences]
[--footnotes] [--code-emphasis] [--headings] [--in-place] [FILE...]
When one or more file paths are provided, the corrected tables are printed to stdout.
Use --version to print the current version and exit.
Use --wrap to reflow paragraphs and list items to 80 columns. Task list
items (- [ ]/- [x]) are indented correctly.
Use --renumber to rewrite ordered lists with consistent sequential
numbering. The renumbering logic correctly handles nested lists by tracking
indentation (tabs are interpreted as four spaces) and restarts numbering
after a list is interrupted by other content, such as a paragraph at a lower
indentation level, a thematic break, or a heading. Blank lines between items
are ignored, so numbering continues uninterrupted.
Use --breaks to standardize thematic breaks to a line of 70 underscores
(configurable via the THEMATIC_BREAK_LEN constant).
Use --ellipsis to replace groups of three dots (...) with the ellipsis
character (…). Longer runs are processed left-to-right, so any leftover
dots are preserved.
Use --fences to normalize code block delimiters to three backticks before
other processing.
Use --footnotes to convert bare numeric references and the final numbered
list into GitHub-flavoured footnote links.
A bare numeric reference is a trailing number after punctuation, like
An example.1.
Use --code-emphasis to fix emphasis markers that directly adjoin inline
code without spaces, ensuring the code span remains intact.
Use --headings to convert Setext headings that use underline markers into
hash-prefixed headings. The underline must contain at least three matching
= or - characters, so the converter can distinguish headings from
thematic breaks and list markers.
Use --in-place to modify files in-place.
If no files are specified, input is read from stdin and output is written to stdout.
When multiple file paths are supplied, mdtablefix processes them in parallel
using the rayon crate. The CLI buffers each result,
so it can print them in the original order. This buffering uses extra memory.
It might outweigh the speed gains for small files.
Before:
|Character|Catchphrase|Pizza count| |---|---|---| |Speedy Cerviche|Here
come the Samurai Pizza Cats!|lots| |Guido Anchovy|Slice and dice!|tons|
|Polly Esther|Cat fight!|many|
After running mdtablefix:
| Character | Catchphrase | Pizza count |
| --------------- | --------------------------------- | ----------- |
| Speedy Cerviche | Here come the Samurai Pizza Cats! | lots |
| Guido Anchovy | Slice and dice! | tons |
| Polly Esther | Cat fight! | many |
Before:
1. The Big Cheese's evil plans.
4. Jerry Atric's schemes.
A brief intermission for pizza.
9. Bad Bird's ninja crows.
1. Crow #1
5. Crow #2
12. Miscellaneous robotic mayhem.
After running mdtablefix --renumber:
1. The Big Cheese's evil plans.
2. Jerry Atric's schemes.
A brief intermission for pizza.
1. Bad Bird's ninja crows.
1. Crow #1
2. Crow #2
2. Miscellaneous robotic mayhem.
The crate exposes helper functions for embedding the table-reflow logic in Rust projects:
use mdtablefix::{process_stream_opts, rewrite, Options};
use std::path::Path;
fn main() -> std::io::Result<()> {
let lines = vec!["|A|B|".to_string(), "|1|2|".to_string()];
let opts = Options {
wrap: true,
ellipsis: true,
fences: true,
footnotes: true,
headings: true,
..Default::default()
};
let fixed = process_stream_opts(&lines, opts);
println!("{}", fixed.join("\n"));
rewrite(Path::new("table.md"))?;
Ok(())
}
The footnotes option also rewrites bare numeric references:
use mdtablefix::{process_stream_opts, Options};
let lines = vec![
"A tip.1".to_string(),
"",
"1. Footnote text".to_string(),
];
let opts = Options { footnotes: true, ..Default::default() };
let out = process_stream_opts(&lines, opts);
assert_eq!(out[0], "A tip.[^1]");
It converts a trailing numbered list into footnote definitions:
use mdtablefix::{process_stream_opts, Options};
let lines = vec![
"More text.".to_string(),
"".to_string(),
"1. First note".to_string(),
"2. Second note".to_string(),
];
let opts = Options { footnotes: true, ..Default::default() };
let out = process_stream_opts(&lines, opts);
assert_eq!(out[2], "[^1]: First note");
process_stream_opts(lines: &[String], opts: Options) -> Vec<String>
rewrites tables in memory. The options enable paragraph wrapping, ellipsis
substitution, fence normalization, Setext-to-ATX heading conversion, and
footnote conversion when footnotes is set to true. The flags are false
by default.
rewrite(path: &Path) -> std::io::Result<()> modifies a Markdown file on
disk in-place.
mdtablefix recognizes basic HTML <table> elements embedded in Markdown.
These are converted to Markdown in a preprocessing stage using
convert_html_tables, prior to reflow.
Only simple tables composed of <tr>, <th>, and <td> tags are supported.
Tag case and attributes are ignored. After conversion, they are reformatted
alongside regular Markdown tables.
See HTML table support for more details.
For an overview of how the crate's internal modules relate to each other, see
Module relationships.
The test suite is structured using the rstest crate. See
Rust testing with rstest fixtures
for details.
This project is licensed under the ISC License. See the LICENSE file for full details.