mdview-tui 0.6.0

A minimal terminal markdown reader: opens a .md file in a centered column in the alternate screen, with syntax-highlighted code blocks and box-drawn tables.
mdview-tui-0.6.0 is not a library.

mdview

crates.io license

A minimal terminal markdown reader written in Rust. Published on crates.io as mdview-tui; the installed binary is mdview.

mdview notes.md
mdview --help       # usage
mdview --version    # version
mdview --licenses   # what this binary contains

What it does

Renders a single markdown file in a centered, fixed-width column inside the alternate screen. Toggle between the rendered view and the raw source with Tab. Scroll with the trackpad/mouse wheel, or with j/k and arrow keys — a thumb on the right border tracks your position. Press ? for the full key list.

YAML front matter — the ----delimited block some files open with — renders as an aligned key/value header with a rule under it, not as markdown. Body paragraphs are justified to the column width. Standalone images render inline at up to 80% of the column width, or at their own size if they are smaller than that — as the real picture in terminals that support iTerm2's inline image protocol (iTerm2, WezTerm, Rio, including over ssh), and as half-block () pixel previews everywhere else. Press o or click one (the bottom bar shows click: <file> while hovering) to open the original in your system viewer, which is also how SVG and PDF are handled since neither can be drawn inline. LaTeX math renders as Unicode: $\gamma^d$γᵈ, $h_{\min}$hₘᵢₙ, \mathbb{E}[S] → 𝔼[S], with $$…$$ display equations centered on their own line. Complex TeX degrades to readable linear form (\frac{a}{b}(a)/(b)) rather than raw source.

Install

cargo install mdview-tui

The crate is published as mdview-tui (the mdview name on crates.io was already taken), but the binary it installs is mdview — so you still run mdview notes.md after installing.

Or build from source:

git clone https://github.com/Ivapo/mdview
cd mdview
cargo build --release
./target/release/mdview README.md

Keys

Key Action
Tab Toggle rendered ↔ raw view
j / Scroll down one line
k / Scroll up one line
Space / PgDn Scroll down a page
PgUp Scroll up a page
g / Home Jump to top
G / End Jump to bottom
Mouse wheel Scroll
- / + Narrow / widen the content column
o Open first visible image in system viewer
Left-click on image Open that image in system viewer
r Reload the file from disk
y Copy the file path to the clipboard
? Toggle the keybinding overlay
q / Esc Quit

Tweaks

A few constants near the top of src/main.rs control the look:

const MAX_CONTENT_WIDTH:     u16 = 130;   // cap on column width
const MIN_CONTENT_WIDTH:     u16 = 80;    // floor for -/+ adjustments
const DEFAULT_CONTENT_WIDTH: u16 = 90;    // startup width target
const SIDE_MARGIN:           u16 = 4;     // breathing room left+right
const WIDTH_STEP:            u16 = 4;     // cells per -/+ press
const FRAME_COLOR:           Color = Color::DarkGray;
const TITLE_COLOR:           Color = Color::Green;

Startup column = min(DEFAULT_CONTENT_WIDTH, terminal_width - SIDE_MARGIN). Adjust live with - and + (clamped to [MIN_CONTENT_WIDTH, min(MAX_CONTENT_WIDTH, terminal_width - SIDE_MARGIN)]); each press re-renders the cached markdown.

Images have their own constants near the top of src/render.rs:

const IMAGE_WIDTH_PCT:   u32 = 80;   // share of the column an image may fill
const IMAGE_CELL_PX:     u32 = 8;    // assumed cell width; decides when an image is "small"
const IMAGE_PX_PER_CELL: u32 = 8;    // inline-protocol resolution: sharpness vs bytes per frame

An image is drawn min(IMAGE_WIDTH_PCT of the column, source_width / IMAGE_CELL_PX) cells wide, with the height following the source aspect ratio — so large figures fit the column and small ones keep their own size rather than being blown up. Height is not capped: a tall image is simply taller than the viewport and you scroll through it.

IMAGE_PX_PER_CELL affects only the inline protocol. Raising it is sharper on a retina display, but there are no image ids in the protocol, so every scroll step resends the payload — push it too far and the half-block underlay starts showing through while scrolling. Set MDVIEW_NO_INLINE_IMAGES=1 to turn inline rendering off entirely and use half-blocks everywhere.

Stack

The markdown renderer is a hand-rolled walk over the pulldown-cmark event stream — see src/render.rs. It handles headings (with / underbars on h1/h2), bold/italic/strikethrough/links, inline code, fenced code blocks (syntect-highlighted with a dark background and a language tag), ordered and unordered lists with nesting, blockquotes with a left bar, horizontal rules, tables with box-drawing borders that shrink columns to fit the content width, justified paragraphs, half-block image previews, and TeX math via a small hand-rolled converter (src/math.rs). On terminals that speak iTerm2's inline image protocol, src/graphics.rs paints the real image over those half-block rows, cropped to whatever part of it is on screen; set MDVIEW_NO_INLINE_IMAGES=1 to force the half-block fallback.

License

MIT — see LICENSE.