A fullscreen markdown pager for the terminal, like less but it actually renders the markdown.
mdr file.md
cat file.md | mdr
llm "explain quicksort" | mdr # streams live, follows the tail
# H1→ big 3-row block-letter banner##/###→ coloured & underlined- bold, italic,
strike,code, links - bullets / numbered lists with hanging indent + word wrap
>blockquotes```fenced code blocks with a box gutter---rules- GFM tables with box borders,
:--:alignment, in-cell word wrap - GitHub alerts (
> [!NOTE]/ TIP / IMPORTANT / WARNING / CAUTION) and<img src=...>images → truecolor half-block pixels (or kitty graphics where supported); decoded via theimagecrate so PNG/JPEG/GIF/WebP/BMP/etc all work- Basic HTML is stripped (
<br>,<picture>,<source>, …);<img>is rendered
Auto-detects light vs dark by sending an OSC 11 query (ESC]11;?BEL) to the
terminal and reading back the actual background colour. This is the only
approach that works everywhere — macOS, Linux, BSD, Windows Terminal, over
SSH, inside tmux — because it asks the terminal itself, not the OS. Falls back
to the COLORFGBG env var, then to dark.
It re-probes every ~2s while running, so if you flip your system/terminal
theme mid-session, mdr recolours itself within a couple of seconds. Override
with --light / --dark if your terminal doesn't answer OSC 11.
j/k or arrows · space/b page · d/u half-page · g/G top/bottom · q quit
In streaming mode it auto-follows the tail; scroll up to pause, G to resume.
cargo build --release
cp target/release/mdr ~/.local/bin/
- macOS + Linux (glibc x86_64/aarch64) supported via cfg'd raw libc FFI.
- Streaming re-render is incremental: only the tail past the last safe block boundary is re-parsed on each chunk, so cost is O(chunk) not O(total).