preview/ holds a yazi.toml and a pdf-hidpi plugin that fix unreadable PDF previews. Yazi calls pdftoppm without -r (150 DPI) and then caps the image at 600x900, so pages are downscaled and upscaled again; the plugin renders at 300 DPI as PNG and the cap goes to 1600x2400, turning that into supersampling. Previewer and preloader both have to be overridden — they share the cache file. README documents this plus what video previews can and cannot do: the preview is a single ffmpeg keyframe by design, J/K scrubs it, and the opener offers mpv --vo=kitty with shared-memory transfer for inline playback. Targets the 26.9 plugin API (fs.cha, not main's fs.stat). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
168 lines
6.4 KiB
Markdown
168 lines
6.4 KiB
Markdown
# yazi-gruvbox
|
|
|
|
A [Gruvbox Dark](https://github.com/morhetz/gruvbox) `theme.toml` for
|
|
[Yazi](https://github.com/sxyazi/yazi) — including the **icon table**, so the
|
|
devicons in front of your files stop looking like a paint spill on an otherwise
|
|
muted colour scheme.
|
|
|
|
Written against **Yazi 26.9**. It uses the current schema (`[mgr]`, `[tabs]`,
|
|
`[pick]`, `[cmp]`, `[indicator]`, …), not the pre-25.x one — older Gruvbox
|
|
themes floating around still use `[manager]` and `[select]` and will throw
|
|
errors on a current Yazi.
|
|
|
|
## What it covers
|
|
|
|
Panel chrome, status bar, tabs, mode indicator, which-key, confirm/spot/notify
|
|
popups, picker, input, completion, task manager, help — plus:
|
|
|
|
**File and directory names** (`[filetype]`):
|
|
|
|
| | |
|
|
|---|---|
|
|
| directories | `#83a598` blue |
|
|
| regular files | `#ebdbb2` fg1 |
|
|
| executables | `#b8bb26` green |
|
|
| archives | `#fe8019` orange |
|
|
| images | `#fabd2f` yellow |
|
|
| audio / video | `#d3869b` purple |
|
|
| PDF / doc | `#8ec07c` aqua |
|
|
| orphan symlinks | red background |
|
|
|
|
**Icons** (`[icon]`): all 725 entries of Yazi's preset table, every glyph colour
|
|
remapped to its nearest Gruvbox tone.
|
|
|
|
**Syntax highlighting** (`gruvbox-dark.tmTheme`): 39 scope rules for the file
|
|
preview, written from scratch against
|
|
[morhetz/gruvbox](https://github.com/morhetz/gruvbox)'s own vim highlight links
|
|
— comments gray italic, strings green, constants purple, keywords red,
|
|
identifiers blue, functions green bold, types yellow, preprocessor aqua,
|
|
operators plain foreground.
|
|
|
|
## How the icon colours were derived
|
|
|
|
Yazi's preset ships 725 icon entries using 221 distinct colours from the
|
|
nvim-tree/devicons palette — saturated web colours that clash badly with
|
|
Gruvbox's muted ground.
|
|
|
|
`regen-icons.py` maps each of them onto the Gruvbox palette:
|
|
|
|
- **Nearest neighbour in Oklab**, so the match is perceptual rather than a naive
|
|
RGB distance.
|
|
- **Lightness weighted down (0.7)** in the distance metric, so *hue* drives the
|
|
result. Docker blue stays blue, Ruby red stays red, instead of everything
|
|
collapsing toward whatever tone happens to be equally bright.
|
|
- **Chromatic and greyish sources are matched from separate pools** (split at
|
|
Oklab chroma 0.04). Without that split a vivid magenta can land on grey, and
|
|
white can land on orange.
|
|
- **Low-contrast targets are excluded.** `#cc241d` (2.69:1) and `#7c6f64`
|
|
(3.03:1) on `#282828` were dropped from the target palette — icons are
|
|
non-text, so 3:1 is the bar. The dimmest icon now sits at **3.48:1**.
|
|
|
|
221 colours end up on 19 Gruvbox tones. Icons stay colourful and stay
|
|
distinguishable; they just stop shouting.
|
|
|
|
## Install
|
|
|
|
```sh
|
|
git clone https://git.opennerds.org/templis/yazi-gruvbox
|
|
cp yazi-gruvbox/theme.toml yazi-gruvbox/gruvbox-dark.tmTheme ~/.config/yazi/
|
|
```
|
|
|
|
`theme.toml` overrides Yazi's built-in `theme-dark.toml`; anything it does not
|
|
set keeps the default.
|
|
|
|
Both files are needed — `theme.toml` points at the `.tmTheme` for syntax
|
|
highlighting in file previews.
|
|
|
|
## Sharper previews (optional)
|
|
|
|
Not part of the colour scheme, but it belongs in the same corner of
|
|
`~/.config/yazi` — the files are under `preview/`.
|
|
|
|
```sh
|
|
cp preview/yazi.toml ~/.config/yazi/yazi.toml
|
|
cp -r preview/plugins/pdf-hidpi.yazi ~/.config/yazi/plugins/
|
|
ya cache clear
|
|
```
|
|
|
|
### Why PDFs look mushy by default
|
|
|
|
Two bottlenecks stack up:
|
|
|
|
1. Yazi calls `pdftoppm` **without `-r`**, so pages render at poppler's 150 DPI
|
|
default — an A4 page is 1241x1754 px.
|
|
2. `[preview] max_width` / `max_height` default to **600x900**. The page is
|
|
squeezed to 600 px wide and then scaled back up to fill the pane.
|
|
|
|
On top of that the page is JPEG-compressed at quality 75, which smears glyph
|
|
edges.
|
|
|
|
`preview/yazi.toml` raises the cap to 1600x2400, and the `pdf-hidpi` plugin is
|
|
Yazi's own PDF previewer with two changes: `-r 300` and PNG instead of JPEG.
|
|
The page now renders at 2481x3508 and is downscaled into the cap, so the result
|
|
is supersampled rather than upscaled — and lossless where the glyphs are.
|
|
|
|
**Both the previewer and the preloader must be overridden.** They write the
|
|
same cache file, so replacing only one leaves the 150 DPI version in place.
|
|
`preview/yazi.toml` does both.
|
|
|
|
Yazi has no zoom. What it has is `J` / `K`, which turn PDF pages in the
|
|
preview, and whatever key you bound to maximise the preview pane.
|
|
|
|
### Videos
|
|
|
|
The video preview is **one still frame** by design: `ffmpeg` pulls a keyframe
|
|
at 5 % of the runtime and Yazi shows it as an image. Nothing animates, and no
|
|
setting changes that.
|
|
|
|
What does work:
|
|
|
|
| Key | |
|
|
|---|---|
|
|
| `J` / `K` | scrub the preview through the file, ±5 % per press |
|
|
| `Tab` | spot panel — codec, resolution, duration |
|
|
| `Enter` / `o` | open in an mpv window |
|
|
| `O` | pick an opener — including **Play here (Kitty)** |
|
|
|
|
The last one is the `[opener]` block in `preview/yazi.toml`: it runs
|
|
`mpv --vo=kitty --vo-kitty-use-shm=yes`, which draws the video into the
|
|
terminal pane through the Kitty graphics protocol. Yazi blocks until mpv
|
|
exits (`q`). Shared-memory transfer keeps it watchable; without it every frame
|
|
goes through the tty as base64 and it crawls. It is still a terminal doing a
|
|
framebuffer's job — fine for checking what a clip is, not for watching it.
|
|
|
|
Defining `play` replaces Yazi's preset list rather than merging into it, which
|
|
is why mpv appears twice there: once windowed, once inline.
|
|
|
|
## Keeping the icon table current
|
|
|
|
The `[icon]` block **replaces** Yazi's preset table wholesale. Icons added by
|
|
later Yazi releases will not show up until it is regenerated:
|
|
|
|
```sh
|
|
git clone --depth 1 https://github.com/sxyazi/yazi
|
|
awk '/^\[icon\]/{f=1} f' yazi/yazi-config/preset/theme-dark.toml > icons-src.toml
|
|
./regen-icons.py icons-src.toml # writes icon-gruvbox.toml
|
|
```
|
|
|
|
Then replace the `[icon]` block in `theme.toml` with the generated file. The
|
|
script prints which Gruvbox tone each source colour landed on.
|
|
|
|
`regen-tmtheme.py` does the same for `gruvbox-dark.tmTheme` — edit the palette
|
|
or the scope rules at the top of the script and re-run it.
|
|
|
|
Both generators and the `pdf-hidpi` plugin target the **26.9** plugin API. If
|
|
you build against Yazi's `main` branch instead of the tag you run, you will hit
|
|
renamed functions — `fs.cha()` was `fs.stat()` on main — and the error only
|
|
surfaces at preview time.
|
|
|
|
## Self-contained
|
|
|
|
Everything needed is in this repository — nothing has to be fetched from a
|
|
third-party theme repo, and no file here carries a copyleft licence.
|
|
|
|
## Licence
|
|
|
|
MIT — see `LICENSE`. The `.tmTheme` is original work; the derived icon data is
|
|
MIT as well. Notices in `THIRD-PARTY.md`.
|