Format Markdown files with Prettier for general formatting, then re-align tables using the yzhang.markdown-all-in-one table alignment algorithm
— with correct CJK and Emoji character width handling (which Prettier's byte-based alignment gets wrong).
Use --tables-only to skip Prettier and align tables alone.
It ships in two forms that share the same formatting core:
- a CLI (
md-fmt) that recursively formats files — documented below; - a VS Code extension that formats the active document via Format Document (
Shift+Alt+F) — seeextension/.
git clone <repo-url> md-format
cd md-format
npm install
npm linkAfter npm link, the md-fmt command is available globally.
md-fmt [options] <directory|file> [<directory|file> ...]| Option | Description | Default |
|---|---|---|
-h, --help |
Show help message | — |
-d, --dry-run |
Print what would be changed without writing | false |
--check |
Exit non-zero if any file needs formatting (for CI) | false |
--tables-only |
Only align tables; skip Prettier formatting | false |
--delimiter-no-pad |
Enable delimiterRowNoPadding |
false |
--normalize-indent |
Enable normalizeIndentation |
false |
--tab-size <n> |
Tab size for indentation normalization | 4 |
--hr-length <n> |
Length of standalone thematic breaks (<hr>, e.g. ---); min 3 |
3 |
# Format all .md files under ./docs
md-fmt ./docs
# Preview changes without writing
md-fmt --dry-run ./docs
# Format a single file
md-fmt ./README.mdPrettier formatting respects a standard .prettierrc, resolved relative to each target file's location via Prettier's own config lookup (not relative to where md-fmt runs).
On top of that, md-fmt always applies a built-in default of embeddedLanguageFormatting: "off", so fenced code blocks (JSON, JS, etc.) are left untouched
— this preserves things like multi-line JSON arrays and single-quoted JS regardless of the target location.
A target-local .prettierrc can override this default.
The table alignment step is configured separately:
Place a mdformat.config.js in the project root to override the default character width ranges:
module.exports = {
// Unicode ranges treated as double-width (CJK, arrows, symbols, etc.)
doubleWidthUnicodeRanges: [
'\u2014-\u2015', // Em Dash, horizontal bar
'\u2024-\u2026', // One Dot Leader, Two Dot Leader, Horizontal Ellipsis
'\u2030-\u2031', // Per Mille Sign, Per Ten Thousand Sign
'\u203b', // Reference Mark
'\u2190-\u2193', // Arrows (←, ↑, →, ↓)
'\u25a0-\u25ff', // Geometric Shapes
'\u2600-\u26ff', // Miscellaneous Symbols
'\u2713', // Check Mark
'\u2717', // Ballot X
'\u2e80-\u2eff', // CJK Radicals Supplement
'\u2f00-\u2fdf', // Kangxi Radicals
'\u3000-\u9fff', // CJK Unified Ideographs
'\uac00-\ud7af', // Hangul Syllables
'\uf900-\ufaff', // CJK Compatibility Ideographs
'\ufe30-\ufe4f', // CJK Compatibility Forms
'\ufe50-\ufe6f', // Small Form Variants
'\uff01-\uff60', // Fullwidth ASCII variants
],
// Characters matched by \p{Extended_Pictographic} but rendered as narrow (1-width) in your font — subtract them back to width 1
narrowOverrideUnicodeRanges: [
'\u2122', // ™ Trade Mark Sign
'\u2139', // ℹ Information Source
],
};If no config file is present, the defaults above are used.
md-fmt recursively formats files ending in .md or .markdown.
Create a .mdformatignore file to control what is skipped.
It uses full .gitignore syntax (anchoring, negation with !, comments, any-depth matching), matched relative to each target root.
If the file is present it replaces the built-in defaults; if it is absent, these defaults are used:
node_modules
vendor
.git
dist
build
.cache
Symlink cycles are detected (a directory is walked at most once by real path), and dangling symlinks are skipped.
The extension/ folder is a VS Code formatter extension built on the same core, so it produces output identical to the CLI.
Register it as your Markdown formatter and use Format Document (Shift+Alt+F / Shift+Opt+F) or Format Document With….
cd extension
npm install
npm run compile # bundle src/extension.js → dist/extension.js (esbuild)Press F5 from the repository root to launch an Extension Development Host, or run npm run package (in extension/) to build a .vsix.
Settings mirror the CLI options (mdFormat.tablesOnly, mdFormat.delimiterRowNoPadding, mdFormat.normalizeIndentation, mdFormat.tabSize, mdFormat.hrLength) plus mdFormat.doubleWidthUnicodeRanges / mdFormat.narrowOverrideUnicodeRanges; the extension also reads a workspace-root mdformat.config.js for width configuration.
See extension/README.md for details.
- Node.js 18+ (uses the built-in
node --testrunner fornpm test) - npm
MIT