Skip to content

Repository files navigation

mdv icon

CONTRIBUTORS FORKS STARS

CRATES.IO DOWNLOADS

Fast, themeable Markdown viewer for the terminal

Overview

Tip

Русская версия: README-RU.md

Note

mdv is a terminal Markdown viewer focused on precise rendering inside ANSI-capable terminals. It offers:

  • Terminal-first rendering - Syntax highlighted output, optional HTML export, and careful handling of inline formatting.
  • Reusable layouts - Control width, wrapping strategy, heading indentation, and table behavior to match your workspace.
  • Link presentation control - Switch between clickable, inline, or tabular links and choose how long URLs are truncated.
  • Rich theming - Built-in color schemes plus on-the-fly overrides for UI and syntax palettes.
  • Live monitoring - Watch files with --monitor to refresh the view whenever the source changes.
  • Script friendly CLI - Read from stdin, jump to sections with --from, and share configuration files across machines.

Important

Required dependencies:

  • Rust toolchain
  • Terminal with ANSI color support for the best experience

Installation

Install from crates.io

cargo install mdv

This installs the latest published release from crates.io into your Cargo bin directory.

Install with Nix (Flake)

nix run github:WhoSowSee/mdv
nix profile install github:WhoSowSee/mdv

The Nix flake builds mdv from flake.nix and installs the mdv binary into the Nix profile. Use nix run to try it without installing, or nix profile install for a persistent install.

Install from source

git clone https://github.com/WhoSowSee/mdv.git
cd mdv
cargo install --path .

The command above builds mdv and places the binary into the Cargo bin directory (usually ~/.cargo/bin).

Run locally without installing

cargo build --release
./target/release/mdv README.md

Use the mdv binary from target/release directly or add it to your PATH.

Usage

mdv [OPTIONS] [FILE]
mdv help

Also, mdv supports reading from standard input (stdin) and working in pipelines

mdv [OPTIONS] -
cat <FILE> | mdv

Output and workflow

  • --html — prints HTML instead of terminal formatting.
  • -E, --render-html — renders raw HTML fragments as terminal-formatted content instead of displaying their tags literally.
  • -N, --line-numbers [<MODE>] — prefixes terminal and pager rows with line numbers. Without a mode, it numbers rendered rows; source uses physical Markdown source lines, separator adds a separator, and "source;separator" combines both.
  • --no-colors — strips ANSI styling regardless of the selected theme.
  • --hide-comments — removes Markdown comments from the rendered output.
  • --theme-info [FILE] — shows the active palette; when FILE is provided it renders the file along with palette information.
  • --from <TEXT> — starts rendering from the first match of <TEXT>. Adding :<lines> limits the number of lines (for example --from "Install:20").
  • -r, --reverse — renders the document starting from the end while keeping block formatting intact.
  • -p, --pager — opens the rendered output in the built-in minus pager. Press E|e or У|у to open the current file in the configured editor; saved changes are rendered automatically.
  • -i, --interactive — opens the interactive document browser. Running mdv without arguments opens the current directory, and passing a directory opens that directory. The browser recursively finds Markdown files while honoring hidden-file and .gitignore rules.
  • --monitor — watches the source file and re-renders when it changes.
  • -F, --config-file <CONFIG_DIR> — reads configuration from the provided directory.
  • -P, --preset <NAME> — applies a built-in or user preset above the configuration file and below explicit CLI options.
  • --preset-info — lists available presets when no positional FILE is provided. mdv --preset-info FILE --preset NAME renders the document and prints Current preset: NAME; with FILE but no --preset, the flag does not alter rendering.
  • -n, --no-config — skips config.yaml/config.yml; presets remain available.
  • --init-config [CONFIG_DIR] — creates the default config file. Uses the provided directory, --config-file, MDV_CONFIG_PATH, or the default config directory.

Theming

  • -t, --theme <NAME> — chooses a built-in theme (default terminal).
  • -T, --code-theme <NAME> — sets the syntax highlight palette (default terminal).
  • --syntaxes-dir <DIR> — recursively loads custom .sublime-syntax files on top of the embedded syntax set. Custom entries take precedence over matching built-in syntaxes.
  • -b, --code-block-style <basic|simple|pretty>[:show-name;show-icon] — selects an indented borderless block, a single gutter, or a boxed frame. Labels are hidden by default; show-name displays the language name, show-icon displays its icon, and both options may be combined (default basic).
  • --custom-theme <key=value;...> — overrides UI colors on top of the selected theme.
  • --inline-style <STYLES> — overrides decorations for emphasis, strong, strong_emphasis, code, strikethrough, and highlight. Use element:property=true,property=false entries separated by ;; properties are backticks, bold, italic, underline, and strikethrough (for example --inline-style 'code:backticks=false,bold=true;highlight:underline=true').
  • --custom-code-theme <key=value;...> — overrides syntax colors using the same format as --custom-theme.
  • --custom-code-block <lang:icon=...,label=...,aliases=...>[;...] — overrides the icon, label, and aliases for specific code block languages. Multiple languages are separated by ;, options within one language by ,, and aliases by | (for example, python:icon=*,label=Python,aliases=py|py3;rust:icon=). Works for any language hint, even if it is not in the built-in icon mapping. Syntax highlighting is applied only when the language is supported by mdv's syntax highlighting logic. Use default:icon=... to set the fallback icon for unknown languages.

Callouts

  • -C, --callout-style <pretty|simple>[:show-icons;fold-icons;label-inside;uppercase] — sets the callout layout and label behavior. label-inside is only supported with pretty, fold-icons requires show-icons.
  • --custom-callout <name:icon=...,color=...;...> — overrides or adds callout labels. icon and color are optional; color formats match --custom-theme.
  • Icons require Nerd Fonts in the terminal to render correctly.

Checkboxes

  • -x, --pretty-checkbox <square|circle> — renders task-list checkboxes as Nerd Font icons instead of the default [ ] / [x] markers. Requires a Nerd Font in the terminal.
  • --custom-checkbox <PAIRS> — overrides built-in checkbox icons or adds new states (only with --pretty-checkbox). Each semicolon-separated pair is either <char>:<icon>[:<color>] or <char>:<color>. The color-only form keeps an existing icon or uses the default unchecked icon for a new state. Colors accept named, hex, rgb, and ansi(N) values.
    • Override: --custom-checkbox ' :󰀦' replace the unchecked icon
    • Add: --custom-checkbox '*:󰞋' add a new [*] checkbox state
    • Color: --custom-checkbox ' :󰀦:yellow' or #ff0000, 128,1,1, ansi(200)
    • Iconless: --custom-checkbox '?:red' keep the default [?] icon, apply red color
    • New iconless state: --custom-checkbox '*:yellow' use the default unchecked icon, apply yellow

Lists

  • -L, --pretty-list <style> — replaces the default - unordered-list markers with a level-aware icon set. The value is required and uses the format type:<nerd-font|unicode>;size:<large|small>, for example --pretty-list 'type:unicode;size:small'.
    • size changes only Nerd Font markers. Unicode accepts either value but renders the same markers; their spacing may vary by font. Verified with Nerd Font families, especially JetBrainsMono Nerd Font.
  • -D, --pretty-definition <unicode|nerd-font> — renders definition descriptions with a built-in Unicode or Nerd Font marker.
  • --uniform-list-marker <level:1-4|icon:glyph> — uses one marker at every nesting level (only with --pretty-list). level:2 reuses level 2 from the selected set; icon:* uses a custom glyph.
  • --custom-list <level>:<icon>[:<color>];... — overrides the marker icon and/or color for specific nesting levels (only with --pretty-list). Level is 1-based; icon is the marker glyph. Colors accept named (red), hex (#ff0000), rgb (255,0,0), and ansi(N) values.
    • Icon + color: --custom-list '1:*:yellow' marker * in yellow
    • Icon only: --custom-list '1:>' marker > in theme color
    • Color only: --custom-list '1:red' keep built-in icon, red color

Layout and wrapping

  • -c, --cols <N> — enforces the output width. When omitted mdv uses the detected terminal width or a fallback of 80 columns.
  • -m, --margin <right:N;left:N> — reserves separate left and right terminal margins. An omitted side defaults to 0.
  • --tab-length <N> — replaces tab characters with N spaces (default 4).
  • -w, --wrap <char|word|none> — selects the text wrapping mode (default char).
  • --reflow — collapses in-paragraph source newlines (soft breaks) and refills each line to the wrap width, so hard-wrapped source reflows to fit smaller screens. Requires wrapping to be enabled; hard breaks are preserved.
  • -W, --table-wrap <fit|wrap|none> — chooses how wide tables are handled (default fit).
  • -B, --pretty-table — restores full rounded table borders.
  • -S, --table-smart-indent — automatic table indent adjustment based on available width.
  • -H, --heading-layout <level|center|flat|none> — controls heading indentation (default level).
  • --show-heading-markers — prefixes headings with markdown-style markers matching their level.
  • -I, --smart-indent — smooths indentation jumps between heading levels in level mode.
  • --code-wrap-indent <none|base|double> — sets the hanging indent applied to wrapped code block lines (default double).
  • --block-spacing <spec> — overrides top and bottom blank lines per block. Omitted sides keep their defaults, and adjacent block gaps collapse to the larger value.

Content visibility

  • --show-empty-elements — keeps normally hidden empty headings, lists, block quotes, code blocks, and tables in the output.
  • --no-code-guessing — disables heuristic detection of code block languages (unknown blocks remain plain text).

Links

  • -u, --link-style <clickable|fclickable|inline|inlinetable|endtable|hide> — changes how links are displayed (default clickable).
  • -l, --link-truncation <wrap|cut|tablecut|none> — determines how long links are shortened (default wrap).

Footnotes

  • --footnote-style <endnotes|attached> — places footnotes at the end of the document or immediately after the block that references them, including paragraphs, tables, and list items.
  • --missing-footnote-style <show|hide> — controls placeholder entries for missing, invalid, or empty footnote definitions. show renders a placeholder message in the footnote block hide omits those entries entirely.

Information

  • mdv help — opens the full mdv --help output in the built-in pager. When input or output is redirected, it prints the same help directly.
  • -h, --help — shows the help text.
  • -V, --version — prints the current version.

Configuration

mdv merges settings from several sources in the following order of precedence:

  1. CLI options (highest priority).
  2. The preset selected with --preset.
  3. The configuration loaded from --config-file, MDV_CONFIG_PATH, or the user-level directory.
  4. Built-in defaults.

Create the default user config with mdv --init-config. Add a directory path (mdv --init-config custom/dir), use --config-file <CONFIG_DIR>, or set MDV_CONFIG_PATH to write it somewhere else.

Configuration files must be written in YAML (.yaml or .yml). See docs/examples/config.yaml for a complete template including inline documentation:

# docs/examples/config.yaml
theme: "terminal"
code_theme: null
inline_style: {}
wrap: "char"
table_wrap: "fit"
pretty_table: false
heading_layout: "level"
smart_indent: false
block_spacing: null
code_wrap_indent: "double"
link_style: "clickable"
link_truncation: "wrap"

inline_style is merged per element and property instead of replacing the whole mapping. Its effective order is semantic defaults, user theme, main config, preset, then --inline-style.

Presets

mdv ships with three presets:

  • reader — word wrapping, paragraph reflow, attached footnotes, an inline link table, and the nord theme for long-form reading.
  • compact — flat headings, simple code/callout blocks, hidden code labels, and end-of-document links for dense terminal output.
  • showcase — centered headings, tokyonight, rich code/callout frames, checkboxes, and list icons. This preset requires a Nerd Font for its icons.

Select one with mdv --preset reader README.md. Explicit CLI options override the selected preset, so mdv --preset compact --cols 100 README.md uses the compact preset at 100 columns.

User presets are *.yaml or *.yml files under <config_dir>/presets/. The directory follows the same resolution order as config.yaml: --config-file, MDV_CONFIG_PATH, then ~/.config/mdv/. It is optional, and --no-config does not disable it.

# <config_dir>/presets/project-docs.yaml
name: project-docs
theme: monokai
wrap: word
reflow: true
table_wrap: wrap
link_style: inlinetable
inline_style:
  code:
    backticks: false

Every preset accepts the same keys and values as docs/examples/config.yaml, plus the required non-empty name field. Presets are partial layers: omitted settings remain unchanged, while explicit values—including false, default-valued options, and null—override the configuration beneath them. A user preset with the same name as a built-in replaces the built-in. Run mdv --preset-info to list the active catalog. When a file and preset are both provided, mdv --preset-info FILE --preset NAME renders the file with Current preset: NAME; without --preset, the flag does not alter file rendering.

Environment variables

  • MDV_CONFIG_PATH — custom path to a configuration directory; also used by mdv --init-config when no directory is provided.
  • MDV_EDITOR — editor opened from pager mode; takes priority over EDITOR. Known GUI editors launch asynchronously while terminal editors block until exit; Emacs and Vim modes are selected from their CLI arguments. Unknown commands are treated as terminal editors.
  • MDV_EDITOR_MODE — optional editor launch mode: tui waits for the editor to exit, while gui launches it asynchronously. When unset, the mode is detected automatically. Explicit tui may be used with GUI launchers to pause the pager; explicit gui overrides unknown commands but is rejected for known terminal editors to prevent both processes from controlling the same terminal. Invalid values and conflicts are reported in the pager without launching the editor.
  • MDV_NO_COLOR — accepts True or False and enforces color usage regardless of CLI arguments or theme settings.

Themes

Built-in themes include:

terminal
Theme Terminal preview
Theme Terminal preview
Theme Terminal preview
monokai
Theme Monokai preview
Theme Monokai preview
Theme Monokai preview
solarized-dark
Theme Solarized Dark preview
Theme Solarized Dark preview
Theme Solarized Dark preview
nord
Theme Nord preview
Theme Nord preview
Theme Nord preview
tokyonight
Theme Tokyonight preview
Theme Tokyonight preview
Theme Tokyonight preview
kanagawa
Theme Kanagawa preview
Theme Kanagawa preview
Theme Kanagawa preview
gruvbox
Theme Gruvbox preview
Theme Gruvbox preview
Theme Gruvbox preview
material-ocean
Theme Material Ocean preview
Theme Material Ocean preview
Theme Material Ocean preview
catppuccin
Theme Catppuccin preview
Theme Catppuccin preview
Theme Catppuccin preview

Switch between them with --theme or set a default in your configuration file.

Use --custom-theme to override UI theme values and --custom-code-theme to fine-tune syntax highlighting. Overrides accept key=value pairs separated by semicolons, where keys match theme fields (for example text, h1, border, code_background, line_number, line_number_separator, pager_status_bar_transparent, keyword, function). pager_status_bar_transparent accepts true or false; optional inline foreground/background colors accept none; other color values can be hex codes (#rrggbb), comma-separated RGB (187,154,247), named ANSI colors (red, darkgrey), or 256-color indexes (ansi(42)).

Run mdv --theme-info to preview the active palette. Add a path (mdv --theme-info README.md) to inspect how colors apply to a document. Starting from examples/config.yaml you can build your own theme variants and keep them in version control.

User themes

Drop one or more *.yaml/*.yml files into <config_dir>/themes/ to register your own themes. The directory follows the same resolution order as config.yaml (the --config-file flag, $MDV_CONFIG_PATH, then ~/.config/mdv/). Two ready-to-use examples ship with the repository:

# <config_dir>/themes/warm.yaml
name: warm
description: Warm red accent layered on top of monokai.
extends: monokai
pager_status_bar_transparent: true

h1: "#ff5577"
link: "#66ccff"
background: "#1c1c1c"

inline_style:
  code:
    backticks: false
    underline: true

syntax:
  keyword: "#ff5577"

Field reference:

  • name (required) — the value accepted by --theme.
  • description (optional) — shown in mdv --theme-info; falls back to the base theme's description.
  • extends (optional) — names a built-in theme or any other theme file loaded earlier in the same directory (alphabetical order). When omitted, missing fields are filled from the default terminal theme.
  • pager_status_bar_transparent (optional) — false keeps the filled pager status bar and Help panel; true removes both backgrounds and separates footer sections with |. It inherits from the base theme when omitted.
  • Every color field is optional and inherits from the base theme when omitted. Available UI fields: text, text_light, line_number, line_number_separator, h1..h6, code, quote, link, emphasis, strong, strong_emphasis, strikethrough, highlight, highlight_background, emphasis_background, strong_background, strong_emphasis_background, code_background, strikethrough_background, background, border, list_marker, table_header, table_border, error, warning. strong_emphasis falls back to strong, while an omitted highlight keeps the surrounding foreground.
  • inline_style: (optional) — partially overrides backticks, bold, italic, underline, and strikethrough for emphasis, strong, strong_emphasis, code, strikethrough, and highlight. Omitted properties inherit from the base theme. The defaults are italic emphasis, bold strong, bold-italic strong emphasis, backticks around code, strikethrough decoration, and no extra highlight decoration.
  • syntax: (optional) — overrides the syntax-highlight palette. Each field is optional and merges against the base: keyword, string, comment, number, operator, function, variable, type_name.
  • Color values follow the same syntax as --custom-theme: named (red, darkgrey, dark_grey), hex (#ff5577), rgb (187,154,247), or 256-color (ansi(42) or 42).

A user theme with the same name as a built-in takes precedence and fully replaces it, which is the supported way to fork a built-in without copying every field. Broken or unrecognized files are skipped with a warning, so a single bad theme does not break the rest.

Star History

Stargazers over time

catppuccin

© 2026-present WhoSowSee

LICENSE

About

Fast Rust-powered Markdown viewer for the terminal with syntax highlighting, flexible themes and layout controls, rich link handling, and live file monitoring

Topics

Resources

Stars

12 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages