sucher
A fast terminal viewer for the files that are awkward to open in a browser — markdown, spreadsheets, PDF, images, SVG, video, Word/PowerPoint/Keynote, archives, and raw binary — behind one tiny command:
Sucher is German for the camera viewfinder — the little window you look through to frame a shot. This one frames files: it picks a viewer by file extension and renders it in place, using your terminal's graphics protocol for real pixels where one is available.
Demo

| Directory browser | Markdown & docs | Video & images |
|---|---|---|
![]() |
![]() |
![]() |
Highlights
- One launcher, many formats — dispatch by extension, sensible TUI per type.
- Directory browser — point
sat a folder (or run it bare) for a fast, two-pane navigator: live preview pane, fuzzy filter, andEnteropens the selection in its viewer, then drops you back where you were. - Handles huge files — a 240 MB / 800k-row spreadsheet opens in ~160 ms and stays scrollable, because sheets stream in on a background thread instead of being loaded whole.
- Real graphics — images, rasterised SVGs, PDF pages, video frames, and
Keynote previews render as actual pixels via the kitty / iTerm2 / sixel
protocols (with a Unicode half-block fallback), through
ratatui-image. - Real typography in pipe mode —
s --plain doc.mdemits the kitty text-sizing protocol so headings render larger on supporting terminals; detected at runtime, with graceful fallback. - Responsive — event-driven redraw (no idle CPU churn) and background work for the expensive bits.
Supported formats
| Category | Extensions | Backend |
|---|---|---|
| Markdown | .md .markdown .mdx |
pulldown-cmark |
| Text / source | code, .txt .log, config files, extension-less UTF-8 text |
syntax-highlighted text viewer (no soft-wrap; pan + search) |
| Spreadsheet | .xlsx, .xlsm |
streaming reader (zip + quick-xml) on a worker thread |
| Spreadsheet | .xls, .ods, .xlsb, .csv, .tsv |
calamine (eager); csv/tsv parsed into the grid |
.pdf |
poppler pdftocairo → graphics |
|
| Image | .png .jpg .jpeg .gif .webp .bmp .tiff .ico |
image → graphics |
| SVG | .svg |
resvg rasteriser → picture above scrolling source |
| Video | .mp4 .mov .mkv .webm .avi .m4v |
streaming ffmpeg pipe → graphics |
| Word | .docx |
unzip + streaming XML → markdown renderer |
| Presentation | .pptx |
unzip + streaming XML (slide text) → markdown renderer |
| Keynote | .key |
embedded QuickLook preview image → graphics |
| Archive | .zip .tar .tar.gz .tgz .gz |
navigable table of contents (folders + path + size); no extraction |
| Binary | unrecognized non-text files | scrolling canonical hexdump (offset │ hex │ ASCII) |
| Directory | any folder | two-pane file browser (list + live preview) |
Comma/tab-separated values (.csv .tsv) open in the spreadsheet grid.
Legacy office binaries (.doc .rtf .odt .ppt) and audio have no viewer:
opening one shows a one-line size/modified summary rather than launching a viewer
or dumping bytes. Other archive types (.7z .rar .xz .bz2 .zst) are
recognized but have no lister; extract them with a shell tool.
When stdout is not a TTY (piped), sucher prints a sensible text dump instead of
launching the TUI (pdftotext for PDF, TSV for sheets, metadata for video,
styled text for markdown/docx/pptx, faithful bytes for text/source, raw XML for
SVG, a canonical hexdump for binary, a size⇥path table for archives, a plain
listing for directories).
Install
Requires a recent Rust toolchain.
# Quickest — installs the `sucher` binary into ~/.cargo/bin:
Or clone for the short s alias and make targets:
make install puts the binary in ~/.cargo/bin and creates a short s
symlink next to it. (make uninstall removes both.)
Optional runtime dependencies
These are only needed for the formats that shell out to them:
| For | Needs | macOS |
|---|---|---|
poppler (pdftocairo, pdfinfo, pdftotext) |
brew install poppler |
|
| Video | ffmpeg, ffprobe |
brew install ffmpeg |
For pixel-perfect images / PDF / video, use a terminal with a graphics protocol — kitty, ghostty, WezTerm, iTerm2, or any sixel-capable terminal. Without one, sucher falls back to Unicode half-blocks.
Usage & keys
|
Directory — j/k ↑/↓ move · d/u half-page · g/G top/bottom ·
Enter/l/→ open file or enter folder · h/←/Backspace parent ·
/ smart filter · . toggle dotfiles · q quit. The right pane renders a live
preview of the selection: images, SVGs, PDFs (page 1), video posters, and
Keynote previews as real pixels, markdown/docx/pptx with full typography, a
grid preview for spreadsheets (including csv/tsv), a table of contents for
archives, a hexdump for binary, a child listing for folders, and the head
of the file for text/code. Previews are cached as you move.
The / filter mixes free-text fuzzy matching with structured predicates, e.g.
report kind:pdf size:>1mb modified:<7d ext:rs. Plain words fuzzy-match the
name; four key:value predicates narrow by metadata:
kind:—pdf,image,video,audio,sheet,doc,markdown,code,archive,folder,binary(and aliases).ext:— a file extension, e.g.ext:rs.size:—>1mb,<=100kb,500(unitsb/kb/mb/gb/tb; bare = at least).modified:— file age, e.g.<7d,>2w(unitss/m/h/d/w/mo/y).
Outside the filter, just type a name to jump to the first matching entry
(type-to-select); a brief pause or Esc ends the jump, and the vim motion keys
keep working whenever you're not mid-type.
Markdown — j/k ↑/↓ scroll · d/u half-page · g/G top/bottom ·
t table of contents · / search (n/N next/prev) · l link picker ·
i image gallery (for docx/pptx embedded media; n/p cycle) · ? help ·
q quit.
Text / source — j/k ↑/↓ scroll · d/u half-page · g/G
top/bottom · h/l pan long lines · / search (n/N next/prev) · q quit.
Spreadsheet — h/j/k/l or arrows move cell · PgUp/PgDn ·
g/G top/bottom · Tab / [ ] switch sheet · / search all cells
(n/N cycle) · q quit. Status bar shows the cell ref, value, and load
progress.
PDF — j/k, ←/→, or space page · g/G first/last · q quit.
Visited pages are cached.
Image — q quit.
SVG — the rasterised picture fills the top pane; the XML source scrolls
below it with j/k ↑/↓ · g/G top/bottom · q quit.
Video — auto-plays on open · space play/pause · ←/→ ±5 s ·
↑/↓ ±30 s · ,/. frame step · g/G start/end · q quit. No audio.
Archive — j/k ↑/↓ move · d/u half-page · g/G top/bottom ·
Enter/l open folder · h/Backspace parent · q quit. A read-only,
navigable table of contents (path + size) with a breadcrumb; sucher lists and
lets you browse folders, but never extracts.
Binary (hex) — j/k ↑/↓ scroll · d/u page · g/G top/end ·
q quit.
How it works
main.rs dispatch by format; TTY → TUI, pipe → text dump
format.rs single classification registry (one source of truth)
dir.rs directory browser (list + live preview), opens files via main
markdown.rs parse → logical lines + TOC + links; width-aware wrap/layout
tui.rs markdown TUI (scroll / TOC / search / links)
text.rs source/plain-text TUI (highlight, no wrap, pan + search)
plain.rs one-shot markdown renderer (kitty text-sizing in pipe mode)
sheet.rs grid UI over a `Book` (streaming xlsx, or eager calamine)
xlsx.rs background streaming .xlsx reader (zip + quick-xml), capped
pdf.rs poppler page raster + page cache, sized to the display
imgview.rs image viewer
svg.rs resvg rasteriser + split image/source viewer
video.rs streaming ffmpeg pipe + background decoder, paced w/ frame-drop
docx.rs .docx → markdown (reuses the markdown renderer)
pptx.rs .pptx slide text → markdown (reuses the markdown renderer)
keynote.rs .key → embedded QuickLook preview image
archive.rs zip/tar/gz table-of-contents lister
hex.rs canonical hexdump viewer for binary files
media.rs shared graphics pane (ratatui-image protocol probe + render)
Design notes:
- One classifier.
format.rsowns a singleFormatregistry that answers both which viewer opens a file and how the browser colours / labels it, so the two can never drift. Classification is a pure, unit-tested function (extension first; a byte head disambiguates only unknown / extension-less files). Only legacy office binaries (.doc/.rtf/.odt/.ppt) and audio lack a viewer: they show a one-line size/modified summary instead of opening, and their bytes are never fed to a text or markdown renderer. - Spreadsheets stream. Only the current sheet is held in memory; rows are parsed incrementally on a worker thread and the grid reads them live, so opening is independent of total file size. Switching sheets frees the previous one. A row cap bounds pathological files.
- PDF renders to display size (
pdftocairo -scale-to-x <terminal px>) rather than a fixed DPI, and caches rendered pages. - Video drives a single long-lived
ffmpegprocess emitting raw frames; a decoder thread paces to real time and keeps only the latest frame, so a slow terminal drops frames instead of falling behind. Effective frame rate is bounded by how fast the terminal can transmit images, not by decoding.
Development
A large-workbook benchmark is included but ignored by default:
SUCHER_BIG=/path/to/big.xlsx
Limitations
- DOCX/PPTX keep text structure (headings, bold/italic, lists, tables; slide
text as bullets). Embedded images are viewable in an image gallery (
i) but not shown inline; page layout and exact styling are dropped. - Keynote shows the embedded QuickLook preview (cover / first slide), not per-slide content — the IWA protobuf body isn't decoded.
- SVG rasterises shapes, gradients, and paths;
<text>needs system fonts, which the headless rasteriser doesn't load, so text elements may not appear. - Archives are listed and folder-navigable, but never extracted: you can browse into directories, though individual entries can't be opened or unpacked.
- Spreadsheet dates show as serial numbers (style table isn't read); the streaming reader caps very large sheets.
- Video has no audio, and terminal frame rate is capped by image transmission.
- Inside the full-screen TUI, markdown headings use color/bold (not the
text-sizing protocol — that applies to
--plain/ pipe output). - In the directory browser, previews render synchronously as you move the
selection, so a PDF or video poster adds a brief raster pause on first visit
(cached afterward). Video shows a poster frame, not playback — press
Enterto open the full player.
License
MIT — see LICENSE.


