automate/020_yazi-filemanager.sh

511 lines
16 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
DEST=${1:-/etc/skel}
TMP_DIR="${TMPDIR:-/tmp}"
YAZI_HOME=${DEST}/.config/yazi
YAZI_PLUGINS=${DEST}/.config/yazi/plugins
YAZI_THEMES=${YAZI_HOME}/flavors
# YAZI_DATA=${DEST}/.local/state/yazi
mkdir -p "${YAZI_PLUGINS}"
mkdir -p "${YAZI_THEMES}"
# A TUI filemanager written in rust.
# The yazi neovim plugin is installed with /var/tmp/automate/020_neovim-lazyvim_plugins.sh
# https://github.com/mikavilpas/yazi.nvim
# Yazi can be optionally extended with other command-line tools to enable additional features.
#
# nerd-fonts (recommended)
# ffmpeg (for video thumbnails)
# 7-Zip (for archive extraction and preview, requires non-standalone version)
# jq (for JSON preview) apt-get install jq
# poppler (for PDF preview) apt-get install poppler-utils
# fd (for file searching)
# rg (for file content searching) ripgrep
# fzf (for quick file subtree navigation, >= 0.53.0)
# zoxide (for historical directories navigation, requires fzf)
# resvg (for SVG preview)
# ImageMagick (for Font, HEIC, and JPEG XL preview, >= 7.1.1)
# xclip / wl-clipboard / xsel (for Linux clipboard support)
ARCH=$(dpkg-architecture -qDEB_HOST_GNU_CPU)
INSTALL_TYPE="${2:-deb_stable}" # Default to deb_stable: deb_stable, deb_nightly, cargo, cargo-git, skip_build
case "$INSTALL_TYPE" in
"deb_stable")
RELEASE=$(lastversion --format tag sxyazi/yazi)
URL="https://github.com/sxyazi/yazi/releases/download/${RELEASE}/yazi-${ARCH}-unknown-linux-gnu.deb"
wget -c -P /var/tmp "$URL"
sudo dpkg -i /var/tmp/yazi-"${ARCH}"-unknown-linux-gnu.deb
;;
"deb_nightly")
URL="https://github.com/sxyazi/yazi/releases/download/nightly/yazi-${ARCH}-unknown-linux-gnu.deb"
wget -c -P /var/tmp "$URL"
sudo dpkg -i /var/tmp/yazi-"${ARCH}"-unknown-linux-gnu.deb
;;
# These are a big one, the build in ${HOME}/.cargo grows to over 1GB
"cargo")
cargo install --force yazi-build
;;
"cargo-git")
cargo install --force --git https://github.com/sxyazi/yazi.git yazi-build
;;
"skip_build") ;;
*)
echo "Usage: $0 [deb_stable|deb_nightly|cargo|cargo-git|skip_build]"
exit 1
;;
esac
sudo apt-get update
sudo apt-get -f install
sudo apt install -y ffmpeg 7zip jq poppler-utils fd-find ripgrep fzf glow zoxide \
imagemagick xclip xsel wl-clipboard mediainfo resvg
# Install supporting cargo packages
cargo install ouch
# Configuration
# <https://github.com/nbaud/nico-yazi-config/blob/main/README.md>
conf_print_readme() {
cat <<'EOF'
# nico-yazi-config
The files I am currently using (18-01-2026) for my yazi configuration. Please
note that many software need to be installed for it to all work properly (I
might have forgotten a thing or two... let me know if you see something missing ^^)
Yazi plugins installed:
<https://github.com/yazi-rs/plugins/tree/main>
<https://github.com/AnirudhG07/awesome-yazi>
- fg ya pkg add lpnh/fr git clone https://github.com/lpnh/fr.yazi ${YAZI_PLUGINS}/fr.yazi
- zoxide
# git clone https://github.com/yazi-rs/plugins.git ${YAZI_PLUGINS}/yazi-rs/
- git ya pkg add yazi-rs/plugins:git https://github.com/yazi-rs/plugins/tree/main/git.yazi
- smart-enter ya pkg add yazi-rs/plugins:smart-enter https://github.com/yazi-rs/plugins/blob/main/smart-enter.yazi
- chmod ya pkg add yazi-rs/plugins:chmod https://github.com/yazi-rs/plugins/tree/main/chmod.yazi
- full-border ya pkg add yazi-rs/plugins:full-border https://github.com/yazi-rs/plugins/tree/main/full-border.yazi
- piper ya pkg add yazi-rs/plugins:piper https://github.com/yazi-rs/plugins/tree/main/piper.yazi
- ouch ya pkg add ndtoan96/ouch git clone https://github.com/ndtoan96/ouch.yazi.git ${YAZI_PLUGINS}/ouch.yazi
- glow ya pack -a Reledia/glow git clone https://github.com/Reledia/glow.yazi ${YAZI_PLUGINS}/glow.yazi
- office ya pkg add macydnah/office git clone https://github.com/macydnah/office.yazi ${YAZI_PLUGINS}/office.yazi
- lazygit ya pkg add Lil-Dank/lazygit git clone https://github.com/Lil-Dank/lazygit.yazi ${YAZI_PLUGINS}/lazygit.yazi
Preview and CLI tools:
- glow Render md apt-get install glow
- piper https://github.com/yazi-rs/plugins/tree/main/piper.yazi
- imagemagick (magick) apt-get install imagemagick
- mediainfo apt-get install mediainfo
- ouch compression cargo install ouch
- fzf apt-get install fzf
- ripgrep apt-get install ripgrep
Optional desktop integration:
- Typora - Paid Markdown reader/writer with preview
- VLC - video player
- Xreader
- Xviewer
- ripdrag
EOF
}
conf_print_readme | tee "${YAZI_HOME}"/README.md
# Install the plugins - avoiding ya so that base plugins can be installed to
# /etc/skel as well.
git clone --depth 1 https://github.com/yazi-rs/plugins.git "${TMP_DIR}"/yazi-rs/
for plugin_dir in "$TMP_DIR/yazi-rs"/*.yazi; do
if [ -d "$plugin_dir" ]; then
plugin_name=$(basename "$plugin_dir")
cp -r "$plugin_dir" "$YAZI_PLUGINS/$plugin_name"
fi
done
rm -rf "$TMP_DIR/yazi-rs"
git clone https://github.com/lpnh/fr.yazi "${YAZI_PLUGINS}"/fr.yazi
git clone https://github.com/ndtoan96/ouch.yazi.git "${YAZI_PLUGINS}"/ouch.yazi
git clone https://github.com/Reledia/glow.yazi "${YAZI_PLUGINS}"/glow.yazi
git clone https://github.com/macydnah/office.yazi "${YAZI_PLUGINS}"/office.yazi
# https://github.com/sxyazi/yazi/tree/shipped/yazi-config/preset
conf_print_yazi_init() {
cat <<'EOF'
-- Official Git Symbol Overrides
th.git = th.git or {}
th.git.modified_sign = "M"
th.git.untracked_sign = "U"
th.git.added_sign = "A"
-- 1. Official Git Plugin Setup
require("git"):setup()
-- 2. FZF Plugin Setup (Default to jump/reveal)
require("fg"):setup({
default_action = "jump",
})
-- 3. Zoxide Setup (Update database on navigation)
require("zoxide"):setup({
update_db = true,
})
require("full-border"):setup {
type = ui.Border.ROUNDED,
}
-- Helper to get the current Git branch
local function get_branch()
local output = io.popen("git branch --show-current 2>/dev/null"):read("*l")
return (output and output ~= "") and (" (" .. output .. ")") or ""
end
local branch_name = get_branch()
-- 1. Disable the Header (to hide the top-left date)
function Header:render() return ui.Line {} end
-- 2. Official-style Custom Linemode (Permissions, Size, Date, Branch)
function Linemode:size_and_mtime()
local year = os.date("%Y")
local time = math.floor(self._file.cha.mtime or 0)
local time_str = os.date(os.date("%Y", time) == year and "%b %d %H:%M" or "%b %d %Y", time)
local size_str = self._file:size() and ya.readable_size(self._file:size()) or "-"
-- Convert mode to permissions string (rwxr-xr-x format)
local function mode_to_perm(mode)
if not mode then return "" end
local perm = ""
local bits = {"r", "w", "x"}
for i = 8, 0, -1 do
local bit = math.floor(mode / (2 ^ i)) % 2
perm = perm .. (bit == 1 and bits[(8 - i) % 3 + 1] or "-")
end
return perm
end
local perm_str = ""
if ya.target_family() == "unix" and self._file.cha.mode then
local perms = mode_to_perm(self._file.cha.mode)
local user = ya.user_name(self._file.cha.uid) or tostring(self._file.cha.uid)
local group = ya.group_name(self._file.cha.gid) or tostring(self._file.cha.gid)
perm_str = perms .. " " .. user .. ":" .. group .. " "
end
return ui.Line {
ui.Span(perm_str):fg("magenta"), -- Permissions (rwxr-xr-x user:group)
ui.Span(size_str .. " "), -- Size
ui.Span(time_str):fg("gray"), -- Date
ui.Span(branch_name or ""):fg("blue"), -- Git Branch
}
end
EOF
}
conf_print_yazi_init | tee "${YAZI_HOME}"/yazi.toml
conf_print_yazi_toml() {
cat <<'EOF'
[manager]
linemode = "size_and_mtime"
[mgr]
linemode = "size_and_mtime"
show_header = true
sort_dir_first = true
sort_by = "alphabetical"
show_symlink = true
show_hidden = true
[plugin]
prepend_fetchers = [
{ id = "git", url = "*", run = "git" },
{ id = "git", url = "*/", run = "git" },
]
[[plugin.prepend_fetchers]]
id = "git"
url = "*"
run = "git"
[[plugin.prepend_fetchers]]
id = "git"
url = "*/"
run = "git"
# --- Official Piper Previewers ---
[[plugin.prepend_previewers]]
url = "*.md"
run = 'piper -- CLICOLOR_FORCE=1 /usr/bin/glow -w=$w -s=dark "$1"'
# KRA (Krita) preview - extracts mergedimage.png from the archive
[[plugin.prepend_previewers]]
url = "*.{kra,KRA}"
run = "kra"
# TIFF preview using built-in magick (requires ImageMagick)
[[plugin.prepend_previewers]]
mime = "image/tiff"
run = "magick"
[[plugin.prepend_previewers]]
url = "*.{tif,tiff,TIF,TIFF}"
run = "magick"
[[plugin.prepend_previewers]]
url = "*.{docx,xlsx,pptx,odt,ods,odp}"
run = "office"
[[plugin.prepend_previewers]]
mime = "{image,audio,video}/*"
run = "mediainfo"
[[plugin.prepend_previewers]]
mime = "application/x-subrip"
run = "mediainfo"
[[plugin.prepend_previewers]]
mime = "application/{*zip,tar,bzip2,7z*,rar,xz,zstd,java-archive}"
run = "ouch"
# --------------------------------
[preview]
max_width = 10000
max_height = 10000
[tasks]
image_bound = [65535, 65535]
[opener]
pdf = [{ run = 'xreader "$@"', desc = "Open PDF with Xreader", detach = true }]
img = [
{ run = 'xviewer "$@"', desc = "Open Image with Xviewer", detach = true },
]
extract = [
{ run = 'ouch d -y "$@"', desc = "Extract here with ouch", for = "unix" },
]
view-viu = [{ run = 'viu "$@"', desc = "View with viu", block = true }]
vlc = [
{ run = 'flatpak run org.videolan.VLC "$@"', desc = "Open with VLC", detach = true },
]
typora = [
{ run = 'flatpak run io.typora.Typora "$@"', desc = "Open with Typora", detach = true },
]
# Define your editor here
edit = [{ run = '${EDITOR:-vim} "$@"', desc = "Edit", block = true }]
[open]
prepend_rules = [
# Markdown files with Typora (prepended to ensure it matches first)
{ url = "*.{md,MD,markdown}", use = "typora" },
]
rules = [
# 0. PDF opening
{ mime = "application/pdf", use = "pdf" },
{ name = "*.{pdf,PDF}", use = "pdf" },
# 1. Image opening
{ mime = "image/*", use = "img" },
{ name = "*.{jpg,jpeg,png,webp,gif,tif,tiff,TIF,TIFF,JPG,JPEG,PNG,WEBP,GIF}", use = "img" },
# 2. Video opening
{ mime = "video/*", use = "vlc" },
{ name = "*.{mp4,mkv,avi,mov,wmv,flv,webm}", use = "vlc" },
# 3. Archive extraction
{ mime = "application/{*zip,tar,bzip2,7z*,rar,xz,zstd,java-archive}", use = "extract" },
# 4. Other text files with editor
{ mime = "text/*", use = "edit" },
{ name = "*.{yml,yaml,toml,lua}", use = "edit" },
]
EOF
}
conf_print_yazi_toml | tee "${YAZI_HOME}"/yazi.toml
conf_print_yazi_keymap_toml() {
cat <<'EOF'
[[mgr.prepend_keymap]]
on = "l"
run = "plugin smart-enter"
desc = "Enter child directory or open file"
[[mgr.prepend_keymap]]
on = "<Enter>"
run = "plugin smart-enter"
desc = "Enter child directory or open file"
[[mgr.prepend_keymap]]
on = "f"
run = "plugin fg -- fzf"
desc = "find file by fzf"
[[mgr.prepend_keymap]]
on = "F"
run = "plugin fg -- rg"
desc = "find file by fzf content"
[[mgr.prepend_keymap]]
on = "z"
run = "plugin zoxide"
desc = "Jump to a directory using zoxide"
[[mgr.prepend_keymap]]
on = "e"
run = "open"
desc = "Extract archive"
[[mgr.prepend_keymap]]
on = "C"
run = "plugin ouch"
desc = "Compress with ouch"
[[mgr.prepend_keymap]]
on = "<C-d>"
run = 'shell "ripdrag \"$@\"" --confirm'
desc = "Drag and Drop"
[[mgr.prepend_keymap]]
on = "M"
run = "plugin chmod"
desc = "Chmod"
[[mgr.prepend_keymap]]
on = [ "g", "i" ]
run = "plugin lazygit"
desc = "run lazygit"
# Create new directory with Shift+A
[[mgr.prepend_keymap]]
on = "A"
run = "create --dir"
desc = "Create a new directory"
# NOTE: Yazi doesn't have "undo" for file operations (copy/move/rename)
# These are real filesystem changes. To cancel ongoing operations:
# 1. Press 'w' to open task manager
# 2. Navigate to the task
# 3. Press 'x' to cancel it (only works if task hasn't completed yet)
# Task management - cancel ongoing operations
[[tasks.prepend_keymap]]
on = "x"
run = "cancel"
desc = "Cancel selected tasks"
[[tasks.prepend_keymap]]
on = "<C-c>"
run = "cancel"
desc = "Cancel selected tasks"
EOF
}
conf_print_yazi_keymap_toml | tee "${YAZI_HOME}/keymap.toml"
# Install themes
# https://yazi-rs.github.io/schemas/theme.json
if [[ -f ${YAZI_HOME}/theme.toml ]]; then
cp "${YAZI_HOME}"/theme.toml "${YAZI_HOME}/theme-backup.toml"
fi
# using ya pkg add will install into the user .local not $DEST
# The manual approach usong git, use ya pkg and then find the .git/config
if [[ ! -d "${YAZI_THEMES}"/vscode-dark-modern.yazi ]]; then
git clone \
--recurse-submodules \
"https://github.com/956MB/vscode-dark-modern.yazi.git" \
"${YAZI_THEMES}"/vscode-dark-modern.yazi
fi
set -x
git clone \
--depth 1 \
--recurse-submodules \
"https://github.com/yazi-rs/flavors.git" \
"$TMP_DIR/yazi-rs_flavors"
for theme_dir in "$TMP_DIR/yazi-rs_flavors"/*.yazi; do
if [ -d "$theme_dir" ]; then
theme_name=$(basename "$theme_dir")
cp -r "$theme_dir" "$YAZI_THEMES/$theme_name"
fi
done
rm -rf "${TMP_DIR}/yasi-rs_flavors"
set +x
# ${DEST}/.local/state/yazi/packages
# ya pkg add 956MB/vscode-dark-modern
# ya pkg add yazi-rs/flavors:catppuccin-mocha
conf_print_yazi_theme_toml() {
cat <<'EOF'
[flavor]
# dark = "vscode-dark-modern"
dark = "catppuccin-mocha"
[icon]
prepend_rules = [{ name = "*.md", text = "", fg = "#61afef" }]
EOF
}
conf_print_yazi_theme_toml | tee "${YAZI_HOME}"/theme.toml
conf_print_permissions-cheat-sheet() {
cat <<'EOF'
| Octal | Special Bit | Owner | Group | Others | Symbolic | Meaning / Typical Use |
| -----: | ----------- | ----- | ----- | ------ | ------------ | --------------------- |
| `0000` | | --- | --- | --- | `----------` | no access |
| `0644` | | rw- | r-- | r-- | `rw-r--r--` | normal file |
| `0664` | | rw- | rw- | r-- | `rw-rw-r--` | shared group file |
| `0600` | | rw- | --- | --- | `rw-------` | private file |
| `0700` | | rwx | --- | --- | `rwx------` | private executable |
| `0755` | | rwx | r-x | r-x | `rwxr-xr-x` | programs / dirs |
| `0775` | | rwx | rwx | r-x | `rwxrwxr-x` | shared directory |
| `0777` | | rwx | rwx | rwx | `rwxrwxrwx` | ⚠️ world-writable |
| Special | Octal | Effect | Symbol |
| ---------- | ------ | ---------------------------- | ----------------- |
| **setuid** | `4xxx` | run as file owner | `s` in owner `x` |
| **setgid** | `2xxx` | run as group / inherit group | `s` in group `x` |
| **sticky** | `1xxx` | only owner can delete | `t` in others `x` |
| Octal | Symbolic | Applies To | What It Does |
| -----: | ----------- | ---------- | ------------------------------- |
| `4755` | `rwsr-xr-x` | binary | run as **root** (e.g. `passwd`) |
| `2755` | `rwxr-sr-x` | directory | files inherit **group** |
| `1777` | `rwxrwxrwt` | directory | shared, but safe (e.g. `/tmp`) |
| `2775` | `rwxrwsr-x` | directory | group-shared project dir |
| `4711` | `rws--x--x` | binary | restricted privileged exec |
EOF
}
conf_print_permissions-cheat-sheet | tee "${YAZI_HOME}"/permissions-cheat-sheet.md
# https://yazi-rs.github.io/docs/quick-start/#shell-wrapper
# shell wrapper that provides the ability to change the current working directory when exiting Yazi.
conf_print_zsh_shell_wrapper() {
cat <<'EOF'
function y() {
local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" cwd
command yazi "$@" --cwd-file="$tmp"
IFS= read -r -d '' cwd < "$tmp"
[ "$cwd" != "$PWD" ] && [ -d "$cwd" ] && builtin cd -- "$cwd"
rm -f -- "$tmp"
}
EOF
}
conf_print_zsh_shell_wrapper | tee "${DEST}"/.zshrc.d/005_yazi_shell.zsh