| Crates.io | mdriver |
| lib.rs | mdriver |
| version | 0.13.0 |
| created_at | 2026-01-05 21:38:43.991135+00 |
| updated_at | 2026-01-25 00:46:52.912742+00 |
| description | Streaming markdown printer for the terminal with syntax highlighting |
| homepage | |
| repository | https://github.com/llimllib/mdriver |
| max_upload_size | |
| id | 2024616 |
| size | 6,204,041 |
A streaming markdown printer for the terminal that renders GitHub Flavored Markdown with ANSI escape codes. The key feature is incremental emission: blocks are emitted immediately once parsed, not waiting for the entire document.
Warning: I wrote this code as an experiment in LLM development. I do not speak fluent rust and I have not read the markdown parser. I'm pretty sure it cannot do anything dangerous, but you've been warned.
brew install llimllib/tap/mdriver
cargo install mdriver
Download the latest release for your platform from the GitHub Releases page:
mdriver-x86_64-unknown-linux-gnu.tar.gzmdriver-x86_64-apple-darwin.tar.gz (Intel) or mdriver-aarch64-apple-darwin.tar.gz (Apple Silicon)Extract and add to your PATH:
tar xzf mdriver-*.tar.gz
sudo mv mdriver /usr/local/bin/
git clone https://github.com/llimllib/mdriver.git
cd mdriver
cargo build --release
The binary will be available at target/release/mdriver.
# Read from file
mdriver README.md
# Pipe markdown from a file
cat document.md | mdriver
# Pipe from echo
echo "# Hello World" | mdriver
# Redirect from file
mdriver < document.md
# Use a specific syntax highlighting theme
mdriver --theme "InspiredGitHub" README.md
# Set default theme via environment variable
MDRIVER_THEME="Solarized (dark)" mdriver README.md
# List available themes
mdriver --list-themes
# Render images using kitty graphics protocol
mdriver --images kitty document.md
# Control color output (auto, always, never)
mdriver --color=always README.md | less -R
# Show help
mdriver --help
$ echo "# Demo\n\nThis is **bold** and *italic*." | mdriver
Output (with ANSI colors in your terminal):
# Heading with blue/bold formatting``` and syntax highlighting-) and ordered (1.) lists**bold**, *italic*, `code` with nested support[text](url) converted to clickable OSC8 terminal links with kitty graphics protocol supportmdriver uses the syntect library for syntax highlighting, supporting 100+ languages with customizable color themes.
Use mdriver --list-themes to see all available themes. Popular options include:
There are three ways to configure the theme (in order of precedence):
mdriver --theme "InspiredGitHub" file.mdexport MDRIVER_THEME="Solarized (dark)"base16-ocean.dark# Use InspiredGitHub theme
mdriver --theme "InspiredGitHub" README.md
# Set environment variable for persistent default
export MDRIVER_THEME="Solarized (dark)"
mdriver README.md
# Combine with piping
MDRIVER_THEME="base16-mocha.dark" cat file.md | mdriver
mdriver can render images inline in your terminal using the kitty graphics protocol. This feature works with any terminal that supports the kitty graphics protocol (kitty, WezTerm, Ghostty, etc.).
Use the --images kitty flag to enable image display:
# Render local images
mdriver --images kitty document.md
# Works with remote URLs
echo "" | mdriver --images kitty
# Combine with theme selection
mdriver --theme "InspiredGitHub" --images kitty README.md
--images flag, images render as plain text # My Document
Here's a screenshot:

And a remote image:

# Render with images
mdriver --images kitty document.md
Note: Image rendering requires a terminal that supports the kitty graphics protocol. In terminals without support, images will display as alt text.
By default, mdriver automatically detects whether to use ANSI colors based on whether stdout is a terminal. You can override this behavior with the --color flag.
| Mode | Description |
|---|---|
auto |
Use colors only when stdout is a terminal (default) |
always |
Always emit ANSI color codes, even when piping |
never |
Never use colors; pass markdown through unchanged |
# Default behavior (auto-detect)
mdriver README.md # Colors in terminal
mdriver README.md | less # No colors (not a tty)
# Force colors when piping to a pager
mdriver --color=always README.md | less -R
# Disable colors entirely
mdriver --color=never README.md
# Alternative syntax (space instead of =)
mdriver --color always README.md
Piping to a pager with colors:
mdriver --color=always README.md | less -R
The -R flag tells less to interpret ANSI escape sequences.
Saving colored output to a file:
mdriver --color=always README.md > output.txt
The file will contain ANSI codes that display colors when cated to a terminal.
Plain text output:
mdriver --color=never README.md > plain.md
Passes the markdown through without any formatting.
mdriver decodes HTML entities in markdown text, supporting both named entities and numeric character references.
| Entity | Character | Description |
|---|---|---|
| Essential (XML) | ||
& |
& |
Ampersand |
< |
< |
Less than |
> |
> |
Greater than |
" |
" |
Quotation mark |
' |
' |
Apostrophe |
| Whitespace | ||
|
Non-breaking space | |
| Typographic | ||
– |
– |
En dash |
— |
— |
Em dash |
… |
… |
Horizontal ellipsis |
‘ |
' |
Left single quote |
’ |
' |
Right single quote |
“ |
" |
Left double quote |
” |
" |
Right double quote |
• |
• |
Bullet |
· |
· |
Middle dot |
| Symbols | ||
© |
© |
Copyright |
® |
® |
Registered |
™ |
™ |
Trademark |
° |
° |
Degree |
± |
± |
Plus-minus |
× |
× |
Multiplication |
÷ |
÷ |
Division |
| Fractions | ||
¼ |
¼ |
One quarter |
½ |
½ |
One half |
¾ |
¾ |
Three quarters |
| Currency | ||
¢ |
¢ |
Cent |
£ |
£ |
Pound |
€ |
€ |
Euro |
¥ |
¥ |
Yen |
| Arrows | ||
← |
← |
Left arrow |
→ |
→ |
Right arrow |
↑ |
↑ |
Up arrow |
↓ |
↓ |
Down arrow |
In addition to named entities, mdriver supports numeric references for any Unicode character:
© → ©© → ©$ echo "5 < 10 — Tom & Jerry © 2024" | mdriver
5 < 10 — Tom & Jerry © 2024
This project uses a comprehensive conformance test suite to verify streaming behavior, markdown parsing, and ANSI formatting.
Tests are written as TOML fixture files that specify:
name = "heading-basic"
description = "Heading should emit after newline is received"
[[chunks]]
input = "#"
emit = ""
[[chunks]]
input = " Hello"
emit = ""
[[chunks]]
input = "\n"
emit = "\u001b[1;34m# Hello\u001b[0m\n"
Key Points:
[[chunks]] represents a piece of markdown fed to the parserinput: The markdown chunkemit: Expected terminal output (empty "" means no emission yet)\u001b format (TOML Unicode escape)Tests are organized in tests/fixtures/:
blocks/ - Individual block types (headings, paragraphs, code blocks, lists)streaming/ - Incremental emission and block boundary detectionansi/ - ANSI escape sequence formatting (bold, italic, colors)complex/ - Real-world documents with mixed block types# Run all conformance tests
cargo test
# Run specific test category
cargo test test_block_fixtures
cargo test test_streaming_fixtures
cargo test test_ansi_fixtures
cargo test test_complex_fixtures
# Run with verbose output
cargo test -- --nocapture
When tests fail, you see clear diagnostics:
Running 4 tests from blocks...
✗ heading-basic
Heading should emit after newline is received
Chunk 4 failed:
Input: "\n"
Expected: "\u{1b}[1;34m# Hello\u{1b}[0m\n"
Actual: ""
.toml file in the appropriate tests/fixtures/ subdirectory\u001b for ESC character in ANSI codesExample ANSI codes:
\u001b[1m...\u001b[0m\u001b[3m...\u001b[0m\u001b[1;34m...\u001b[0m (bold blue)\u001b[48;5;235m...\u001b[0mAll Systems Operational ✅
Test Coverage:
Potential areas for expansion:
mdriver/
├── Cargo.toml
├── README.md
├── CLAUDE.md # AI assistant context and guidelines
├── gfmspec.md # GitHub Flavored Markdown specification
├── .clippy.toml # Clippy linting configuration
├── src/
│ ├── lib.rs # StreamingParser implementation
│ └── main.rs # CLI binary
└── tests/
├── conformance.rs # Test runner
├── common/
│ ├── mod.rs
│ └── fixture_loader.rs
└── fixtures/
├── blocks/ # 4 tests: heading, paragraph, code_block, list
├── streaming/ # 2 tests: incremental_emit, block_boundaries
├── ansi/ # 1 test: inline_formatting
└── complex/ # 1 test: mixed_document
This project maintains strict code quality requirements:
# All must pass before committing:
cargo fmt # Format code
cargo build # No warnings
cargo build --release # No warnings
cargo clippy --all-targets --all-features -- -D warnings # No errors
cargo test # All tests pass
See CLAUDE.md for comprehensive development guidelines and best practices.
CLAUDE.md: Comprehensive guide for AI assistants and developersgfmspec.md: GitHub Flavored Markdown specification (authoritative source).clippy.toml: Linting configurationtests/fixtures/: Conformance test cases in TOML formatMIT