TermPDF is a terminal PDF reader built with Rust, ratatui, PDFium, and the kitty image protocol.
It focuses on reader-oriented navigation for kitty-compatible terminals, with image-based PDF rendering instead of text reflow.
- Added a visible block cursor in normal mode with Vim-style text cursor motions (
h,j,k,l,w,b,^,$) and count support. - Added visual character selection (
v), visual line selection (V), visual block selection (Ctrl-v), and clipboard copy (y) as plain text using platform clipboard commands (pbcopy,wl-copy,xclip,xsel,clip). - Reworked the status bar: left-aligned color mode indicator (NORMAL / VISUAL / V-LINE / V-BLOCK) with a section divider before context-specific keybinding chips.
- Normal mode shows
/ search,f links,m mark,F5 present,q quit; visual modes showy copy. - Improved PDF line clustering to use glyph center lines and vertical overlap, with a second pass that merges small inline annotations (superscripts, subscripts, footnote markers) into their source-adjacent body line instead of creating spurious single-glyph lines.
- Changed
termpdf grepto default to regular expression search; use--literalfor plain text matching.
- Added tmux support through Kitty graphics passthrough. Enable it in
~/.tmux.confwithset -g allow-passthrough on. - Added mouse and touchpad navigation for scrolling, horizontal scrolling, zooming with
Ctrl+ scroll, and presentation navigation.
- PDFium-backed PDF rendering
- Kitty image protocol rendering for page images
- Smooth scrolling across multi-page documents
- Vim-style navigation and page jumps
- Search with image-level highlights
- Follow links with image-level tag overlays
- Marks for quick navigation
- Presentation mode
- Dark mode toggle
- Watch mode with live PDF reload
- Agent and LLM-oriented layout pack extraction with stable refs
- Vim-style visual selection with clipboard copy as plain text
yay -S tpdfHomebrew tap:
brew tap NiJingzhe/termpdf
brew install termpdfOr install directly:
brew install NiJingzhe/termpdf/termpdf- A supported release platform:
aarch64-apple-darwinx86_64-unknown-linux-gnuaarch64-unknown-linux-gnu
- A terminal with kitty graphics protocol support, such as kitty or ghostty
- tmux is supported when the outer terminal supports Kitty graphics and
set -g allow-passthrough onis enabled in~/.tmux.conf; TermPDF wraps Kitty image commands in tmux passthrough automatically termpdfand the matching packagedlibpdfiumin the same directory, unless you explicitly point to another PDFium build withPDFIUM_LIB_PATHor--pdfium-lib
Download the archive for your platform from the GitHub Releases page, then extract it:
tar -xzf termpdf-0.3.1-x86_64-unknown-linux-gnu.tar.gz
cd termpdf-0.3.1-x86_64-unknown-linux-gnu
./termpdf path/to/file.pdfEach release archive contains:
termpdf- the matching packaged
libpdfium LICENSEREADME.md
If you install the files manually into the filesystem, keep termpdf and libpdfium.so or libpdfium.dylib together in the same directory.
Build dependencies:
- Rust stable toolchain with
cargo ghorcurlandtarwhen using bundled PDFium variants (not required forTERMPDF_PDFIUM_VARIANT=SYSTEM)- A supported PDFium bundle variant, or another compatible PDFium dynamic library
Set the PDFium variant with an environment variable and build:
TERMPDF_PDFIUM_VARIANT=linux-x64-glibc cargo build --release
./target/release/termpdf path/to/file.pdfSupported source-build values for TERMPDF_PDFIUM_VARIANT:
macos-arm64linux-x64-glibclinux-arm64-glibcSYSTEM
When using a bundled variant, TermPDF automatically downloads the matching PDFium archive from bblanchon/pdfium-binaries into .cache/pdfium/, extracts it, and then copies the matching libpdfium next to the binary in target/<profile>/.
When set to SYSTEM, the build skips PDFium download/copy in build.rs and uses your system PDFium at runtime (or a path provided by PDFIUM_LIB_PATH / --pdfium-lib).
The binary looks for a packaged PDFium library next to itself first. For manual packaging, distro packaging, or AUR packaging, install the real executable and the matching PDFium library into the same directory.
A working Linux layout is:
/usr/lib/termpdf/termpdf
/usr/lib/termpdf/libpdfium.so
/usr/bin/termpdfWhere /usr/bin/termpdf is a small wrapper:
#!/usr/bin/env bash
exec /usr/lib/termpdf/termpdf "$@"For an AUR source package on x86_64, the build step should be equivalent to:
TERMPDF_PDFIUM_VARIANT=linux-x64-glibc cargo build --releaseFor an AUR binary package on x86_64, unpack the release tarball and install the bundled termpdf and libpdfium.so together without separating them.
For source builds, set TERMPDF_PDFIUM_VARIANT to the bundle that matches your machine, or set it to SYSTEM to use system PDFium.
TERMPDF_PDFIUM_VARIANT=linux-x64-glibc cargo run -- path/to/file.pdfWatch mode:
TERMPDF_PDFIUM_VARIANT=linux-x64-glibc cargo run -- path/to/file.pdf -wIf PDFium is not available in the system library path, TermPDF will try the downloaded cache under .cache/pdfium/. You can also point to a PDFium build explicitly:
cargo run -- path/to/file.pdf --pdfium-lib /path/to/pdfiumTermPDF can extract a stable layout pack for agents, LLMs, search pipelines, and other CLI tools:
termpdf extract path/to/file.pdf --out path/to/file.layoutIf --out is omitted, TermPDF writes next to the source PDF with a .layout suffix:
termpdf extract paper.pdf
# writes paper.layout/Use --overwrite to replace an existing TermPDF layout pack:
termpdf extract paper.pdf --overwriteEach layout pack contains:
manifest.json: schema, TermPDF version, source PDF hash, coordinate system, and file mappages.jsonl: one page record per lineblocks.jsonl: text line and link recordsglyphs.jsonl: one precise glyph record per visible characterrefs.jsonl: a global reference registry for quick lookup
Stable refs use one-based, type-namespaced addresses:
p1 page 1
p1.t1 page 1, text line 1
p1.t1.c1 page 1, text line 1, character 1
p1.link1 page 1, link 1
The layout schema is termpdf.layout.v1. Bboxes use PDF points with a bottom-left origin, matching PDFium extraction and TermPDF rendering projection.
Search a layout pack and return stable refs with grep:
termpdf grep "method" paper.layout
termpdf grep "method" paper.layout --refs-only
termpdf grep "method|approach" paper.layout --json
termpdf grep "literal.dot" paper.layout --literalBy default, grep treats the pattern as a regular expression and prints ref<TAB>text. Use --ignore-case for case-insensitive search and --literal when the pattern should be treated as plain text.
TERMPDF_PDFIUM_VARIANT selects which PDFium dynamic library Cargo should download and copy next to the built binary.
Supported values:
macos-arm64linux-x64-glibclinux-arm64-glibcSYSTEM(skip download/copy; use system PDFium)
Example:
TERMPDF_PDFIUM_VARIANT=linux-x64-glibc cargo build --releaseTERMPDF_PDFIUM_VARIANT is the recommended path for development, packaging, and CI because it keeps the build configuration explicit and local to the command being run.
The build currently supports automatic PDFium downloads for:
macos-arm64linux-x64-glibclinux-arm64-glibc
When TERMPDF_PDFIUM_VARIANT is set to one of the bundled variants above, build.rs downloads the matching PDFium archive if needed, caches it in .cache/pdfium/, and copies the matching libpdfium into target/<profile>/, so both cargo run and the final executable can load the packaged dynamic library from the binary directory.
When TERMPDF_PDFIUM_VARIANT=SYSTEM, build.rs skips bundling and relies on system PDFium resolution at runtime.
The older Cargo feature based bundle selection still works, but the recommended path for development is the environment variable above.
To refresh the vendored PDFium archives from upstream, run:
./scripts/fetch_pdfium.sh linux-x64-glibcTagged releases build artifacts for the currently supported packaged targets:
aarch64-apple-darwinx86_64-unknown-linux-gnuaarch64-unknown-linux-gnu
Each release archive contains:
termpdf- the matching packaged
libpdfium LICENSEREADME.md
h/j/k/l: move the text cursorw/b/^/$: move by word or line boundaryH/J/K/L: pan viewportCtrl-u/Ctrl-d: half-page up/downCtrl-b/Ctrl-f: full-page back/forwardgg,{count}gg,G: jump to page/,n,N,Esc: search, navigate results, hide highlightsf/F: follow visible linksv: visual character selectionV: visual line selectionCtrl-v: visual block selectiony: copy the active visual selection to the system clipboard as plain textm<char>/`<char>: set and jump to marksF5: presentation mode=/-/0: zoom in / out / reseti: toggle dark modeq: quit
This project is under active development.