From 2f22fb97a9b22dafa4499598d0388b5d5f96d3b3 Mon Sep 17 00:00:00 2001 From: Alexandre Velia Date: Fri, 18 Sep 2026 09:24:54 +0400 Subject: [PATCH 1/2] feat: provision yazi (TUI file manager) with previews Ports the macOS setup to the Ubuntu provisioning so both machines get the same file manager: - install yazi + ya from the upstream release zip (not packaged for 24.04), following the jira-cli pattern: download, locate the binaries with find so the archive's internal layout doesn't matter, install into ~/.local/bin - add the preview dependencies to the apt list: ffmpeg (video), poppler-utils (PDF), imagemagick (raster), unzip (to unpack the release itself) - new `yazi` stow package holding a config shared by both OSes; the openers are split with `for = "macos"` / `for = "linux"` rather than forked into two files, so there is a single config to keep in sync - new `y` shell function: yazi cannot change its parent shell's cwd, so it writes the last directory to --cwd-file and the wrapper cds there. It calls `command rm`, because a bare `rm` is aliased to `trash` in this config and zsh expands aliases when a function is *defined*, which would send every temp cwd file to the trash - tmux: allow-passthrough on, without which the kitty graphics protocol is swallowed by tmux and image previews silently never render - cover the new stow package in the CI conflict check Verified locally on macOS: shellcheck clean (the exact CI command), config parses under yazi 26.9.1, `y` cds correctly. The Ubuntu paths (apt, the release download, stow) are only exercised by CI. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 4 +-- dotfiles/tmux/.config/tmux/tmux.conf | 1 + dotfiles/yazi/.config/yazi/yazi.toml | 39 +++++++++++++++++++++++++ dotfiles/zsh/.zsh/functions/40-yazi.zsh | 15 ++++++++++ install/10-packages.sh | 34 ++++++++++++++++++++- install/50-stow.sh | 2 +- 6 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 dotfiles/yazi/.config/yazi/yazi.toml create mode 100644 dotfiles/zsh/.zsh/functions/40-yazi.zsh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9eacd62..39bd3cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,6 +35,6 @@ jobs: - name: Dry-run bootstrap (headless, no security) run: | su tester -c 'cd ~/forge && ./bootstrap.sh --dry-run --yes --no-desktop --no-security' - - name: Validate stow packages link cleanly (zsh/git/tmux) + - name: Validate stow packages link cleanly (zsh/git/tmux/yazi) run: | - su tester -c 'cd ~/forge && stow --no --target=$HOME --dir dotfiles zsh git tmux 2>&1 | tee /tmp/stow.log; ! grep -i conflict /tmp/stow.log' + su tester -c 'cd ~/forge && stow --no --target=$HOME --dir dotfiles zsh git tmux yazi 2>&1 | tee /tmp/stow.log; ! grep -i conflict /tmp/stow.log' diff --git a/dotfiles/tmux/.config/tmux/tmux.conf b/dotfiles/tmux/.config/tmux/tmux.conf index 2d70987..9310834 100644 --- a/dotfiles/tmux/.config/tmux/tmux.conf +++ b/dotfiles/tmux/.config/tmux/tmux.conf @@ -18,6 +18,7 @@ set -g default-terminal "tmux-256color" set -ag terminal-overrides ",xterm-kitty:RGB,xterm-256color:RGB" set -sg escape-time 0 # pas de délai après Échap (crucial pour nvim) set -g focus-events on # nvim sait quand le pane reprend le focus +set -g allow-passthrough on # laisse passer le protocole graphique kitty (previews d'images yazi) set -g history-limit 50000 # scrollback généreux set -g base-index 1 # fenêtres numérotées à partir de 1 (plus proche du clavier) setw -g pane-base-index 1 diff --git a/dotfiles/yazi/.config/yazi/yazi.toml b/dotfiles/yazi/.config/yazi/yazi.toml new file mode 100644 index 0000000..3d854aa --- /dev/null +++ b/dotfiles/yazi/.config/yazi/yazi.toml @@ -0,0 +1,39 @@ +# Yazi 26.x — note the section is [mgr]; [manager] is the old deprecated name. +# Shared between macOS and Ubuntu: openers are split with `for =` rather than +# forked into two files, so there is only one config to keep in sync. + +[mgr] +ratio = [1, 3, 4] # parent | current | preview +sort_by = "natural" # file2 before file10 +sort_dir_first = true +linemode = "size" +show_hidden = false # toggle at runtime with . +show_symlink = true +scrolloff = 5 + +[preview] +max_width = 1200 # generous: kitty draws real pixels, not cells +max_height = 1200 +image_filter = "lanczos3" +tab_size = 2 + +[opener] +edit = [ + { run = '$EDITOR "$@"', desc = "$EDITOR", block = true }, +] +open = [ + { run = 'open "$@"', desc = "Open in default app", for = "macos", orphan = true }, + { run = 'xdg-open "$@"', desc = "Open in default app", for = "linux", orphan = true }, +] +reveal = [ + { run = 'open -R "$1"', desc = "Reveal in Finder", for = "macos", orphan = true }, + { run = 'xdg-open "$(dirname "$1")"', desc = "Reveal enclosing folder", for = "linux", orphan = true }, +] + +[open] +prepend_rules = [ + # Text-ish files go to $EDITOR instead of the desktop default app. + { url = "*.log", use = "edit" }, + { url = "*.toml", use = "edit" }, + { url = "*.lock", use = "edit" }, +] diff --git a/dotfiles/zsh/.zsh/functions/40-yazi.zsh b/dotfiles/zsh/.zsh/functions/40-yazi.zsh new file mode 100644 index 0000000..990981e --- /dev/null +++ b/dotfiles/zsh/.zsh/functions/40-yazi.zsh @@ -0,0 +1,15 @@ +# y: yazi wrapper that leaves you in the directory you quit from. +# Yazi runs in its own process, so a plain `yazi` call can't change the shell's +# cwd — it dumps the last directory into --cwd-file and we cd there ourselves. +y() { + # Usage: y [path] + local tmp cwd + tmp="$(mktemp -t yazi-cwd.XXXXXX)" || return + yazi --cwd-file="$tmp" "$@" + cwd="$(<"$tmp")" + # `command rm`: bare rm is aliased to trash here, and zsh expands aliases when + # the function is *defined*, which would litter the trash with every cwd file. + command rm -f -- "$tmp" + # Quitting with Q (instead of q) writes nothing, which keeps you put on purpose. + [ -n "$cwd" ] && [ "$cwd" != "$PWD" ] && builtin cd -- "$cwd" +} diff --git a/install/10-packages.sh b/install/10-packages.sh index 739c50f..cb419e5 100755 --- a/install/10-packages.sh +++ b/install/10-packages.sh @@ -11,7 +11,8 @@ ARCH="$(dpkg --print-architecture)" # amd64 / arm64 log "Core CLI tools from apt" apt_install \ zsh tmux neovim ripgrep fd-find bat jq tree htop btop \ - fzf zoxide direnv trash-cli unrar p7zip-full \ + fzf zoxide direnv trash-cli unrar p7zip-full unzip \ + ffmpeg poppler-utils imagemagick \ fonts-firacode # Ubuntu ships fd as `fdfind` and bat as `batcat`; expose the canonical names. @@ -87,4 +88,35 @@ fi # --- 8. tldr (tealdeer) ------------------------------------------------------ apt_install tealdeer || warn "tealdeer not in repos; skip (optional)" +# --- 9. yazi (TUI file manager) — release binary ----------------------------- +# Not packaged for Ubuntu 24.04, so we take the upstream zip. It ships two +# binaries (yazi + ya, the plugin/package manager) nested in a versioned dir. +# The image previews need ffmpeg / poppler / imagemagick from section 1, plus +# `allow-passthrough on` in tmux — see dotfiles/tmux. +if ! have yazi; then + log "Installing yazi" + YAZI_VER="$(curl -fsSL https://api.github.com/repos/sxyazi/yazi/releases/latest \ + | grep -Po '"tag_name": *"v\K[^"]*' || echo '26.9.1')" + case "$ARCH" in + amd64) YAZI_ARCH="x86_64" ;; + arm64) YAZI_ARCH="aarch64" ;; + *) YAZI_ARCH="$ARCH" ;; + esac + tmp="$(mktemp -d)" + if run bash -c "curl -fsSL 'https://github.com/sxyazi/yazi/releases/download/v${YAZI_VER}/yazi-${YAZI_ARCH}-unknown-linux-gnu.zip' -o '$tmp/yazi.zip'"; then + run unzip -q "$tmp/yazi.zip" -d "$tmp" + for b in yazi ya; do + bin="$(find "$tmp" -type f -name "$b" | head -n1)" + if [[ -n "$bin" ]]; then + run install -m 0755 "$bin" "$HOME/.local/bin/$b" + else + warn "yazi archive did not contain '$b'; check the upstream layout." + fi + done + else + warn "yazi download failed; install manually later." + fi + rm -rf "$tmp" +fi + ok "packages installed" diff --git a/install/50-stow.sh b/install/50-stow.sh index a43d833..73d19bf 100755 --- a/install/50-stow.sh +++ b/install/50-stow.sh @@ -12,7 +12,7 @@ DOTFILES="$FORGE_DIR/dotfiles" [[ -d "$DOTFILES" ]] || die "missing $DOTFILES" # Desktop packages only stow when a GUI is present. -PACKAGES=(zsh starship git tmux kitty aerc jira) +PACKAGES=(zsh starship git tmux kitty aerc jira yazi) if has_gui; then PACKAGES+=(sway waybar dunst) fi From e76e7236ee46849a1fd91d18b663f48a582dcc21 Mon Sep 17 00:00:00 2001 From: Alexandre Velia Date: Fri, 18 Sep 2026 09:30:22 +0400 Subject: [PATCH 2/2] fix: no false yazi warning under --dry-run Under --dry-run, run() only prints, so nothing is downloaded or unzipped and the find over the temp dir is legitimately empty. The diagnostic fired anyway and every dry-run logged two warnings that looked like an upstream layout change. Keep the warning for real runs, where it is the useful signal. Co-Authored-By: Claude Opus 5 (1M context) --- install/10-packages.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/install/10-packages.sh b/install/10-packages.sh index cb419e5..edab9c7 100755 --- a/install/10-packages.sh +++ b/install/10-packages.sh @@ -109,7 +109,9 @@ if ! have yazi; then bin="$(find "$tmp" -type f -name "$b" | head -n1)" if [[ -n "$bin" ]]; then run install -m 0755 "$bin" "$HOME/.local/bin/$b" - else + elif [[ "${FORGE_DRY_RUN:-0}" != "1" ]]; then + # Under --dry-run nothing was downloaded or unzipped, so an empty find + # is expected and warning about it would be a false alarm. warn "yazi archive did not contain '$b'; check the upstream layout." fi done