Skip to content

Y-jiji/tinymist-kitty.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tinymist-kitty.nvim

A Neovim plugin that renders a live Typst preview directly into a terminal window via the Kitty graphics protocol. No browser, no external viewer, no file watcher — the preview lives inside the Neovim split that already shows the source file.

Status

v0.1.0 — single-buffer preview works end-to-end on Ghostty 1.3+ with the default fit-to-width mode. See docs/ARCHITECTURE.md for the system shape and HANDOFF.md for the original design framing.

Features

  • Live preview inside Neovim, rendered by the host terminal — no extra window.
  • Per-page pixmap-hash dedup: only changed pages are re-uploaded.
  • Cursor → page autoscroll via tinymist-preview's changeCursorPosition, anchored to the source window's vertical ratio.
  • Mouse-click → source jump (Kitty protocol cell → document position → winrestview).
  • Outline sidebar and compileStatus → statusline integration.
  • Fit modes: width (default) and within; quality-multiplier dpi on top.
  • Multi-page documents: <leader>pn, <leader>pp, <leader>pg{N}.
  • :checkhealth typst_term_preview.

Requirements

  • Neovim 0.10+.
  • A terminal that implements the Kitty graphics protocol and the Unicode placeholder extension. Verified: Ghostty 1.3+. Kitty itself, WezTerm, and foot should work but are untested.
  • Rust toolchain (stable) to build the typst-term-preview server binary.
  • tmux is unsupported unless built with passthrough.

Install

lazy.nvim

{
  "Y-jiji/tinymist-kitty.nvim",
  ft = "typst",
  build = "cargo build --release --bin typst-term-preview",
  opts = {
    binary     = vim.fn.stdpath("data") .. "/lazy/tinymist-kitty.nvim/target/release/typst-term-preview",
    auto_start = true,
  },
}

packer.nvim

use {
  "Y-jiji/tinymist-kitty.nvim",
  ft  = "typst",
  run = "cargo build --release --bin typst-term-preview",
  config = function()
    require("typst_term_preview").setup({
      binary     = vim.fn.stdpath("data") .. "/site/pack/packer/start/tinymist-kitty.nvim/target/release/typst-term-preview",
      auto_start = true,
    })
  end,
}

Manual

git clone https://github.com/Y-jiji/tinymist-kitty.nvim.git \
  ~/.local/share/nvim/site/pack/plugins/start/tinymist-kitty.nvim
cd ~/.local/share/nvim/site/pack/plugins/start/tinymist-kitty.nvim
cargo build --release --bin typst-term-preview

Then put the release binary on $PATH or point binary = "/abs/path" in setup().

Quick start

require("typst_term_preview").setup({
  binary     = "typst-term-preview",  -- or absolute path
  auto_start = true,
  dpi        = 96,
  fit_mode   = "width",
})

Open a .typ file and the preview split appears. If auto_start = false, run :TypstTermPreview to launch the session.

Cell-pixel calibration

The server probes terminal cell size via CSI 16t at startup, but Neovim owns the TTY in raw mode and usually consumes the response first — the 9×18 fallback then kicks in and the preview looks slightly off. Measure the real value from a plain shell:

./scripts/measure-cell-px.sh

…and plug it into setup:

require("typst_term_preview").setup({
  cell_px = { w = 9, h = 17 },  -- whatever the script reports
})

Configuration

key default effect
binary "typst-term-preview" absolute path or $PATH lookup
auto_start false spawn on FileType typst
dpi 96 quality multiplier on top of fit scale
cell_px nil { w, h } override of the CSI 16t result
fit_mode "width" "width" or "within"
scroll_anchor 0.2 fallback when dynamic source-anchor is unavailable
emit_debounce_ms 250 idle window before flushing queued frame uploads

Commands

command effect
:TypstTermPreview start a preview session for the current buffer
:TypstTermPreviewStop stop the session
:TypstTermPreviewToggle toggle on/off
:TypstTermPreviewUpdate force an immediate re-render
:checkhealth typst_term_preview diagnose terminal protocol support and binary path

Diagnostic toggles for bisecting flicker: :TypstFlickerToggleEmit, :TypstFlickerToggleRebuild, :TypstFlickerToggleScroll, :TypstFlickerToggleOverlay, :TypstFlickerLogToggle, :TypstFlickerStatus.

Keymaps (typst buffer-local)

keys action
<leader>pn next page
<leader>pp previous page
<count><leader>pg jump to page <count>
<leader>p+ zoom in
<leader>p- zoom out
<leader>p0 reset zoom

Architecture in one paragraph

Three processes: the host terminal, Neovim + the Lua plugin, and the Rust typst-term-preview server. The plugin spawns the server and connects over an AF_UNIX socket carrying a newline-delimited JSON control plane (mirroring tinymist-preview's ControlPlaneMessage). The server holds a tinymist-world snapshot, rasterizes pages with tiny-skia at a viewport-driven scale, PNG-encodes them, and emits frame events. The plugin unpacks each frame into a Kitty a=t upload + a=p,U=1 virtual placement keyed by U+10EEEE placeholder cells in the [Preview] buffer — so Neovim's own redraw cycle keeps the image stable on screen. Full details: docs/ARCHITECTURE.md.

Non-goals

  • Sixel or non-Kitty-protocol terminals.
  • Non-typst document types.
  • Remote / SSH workflows.
  • Multi-document preview sessions.

Acknowledgements

License

See LICENSE (if present) or the source headers.

About

Live typst preview rendered into Neovim via Kitty graphics protocol; tinymist-preview backend, no browser

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors