182 lines
4.6 KiB
Bash
182 lines
4.6 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
: <<!
|
|
# ------------------------------------------------------------------------------
|
|
# Yazi zdbstat previewer — pure Lua (preview pane, toggleable)
|
|
# Shows zdb -dddddddddd output in preview when toggled on
|
|
# Requires: zfs, zdb, stat, realpath, sudo/doas/pkexec
|
|
# ------------------------------------------------------------------------------
|
|
!
|
|
set -euo pipefail
|
|
|
|
DEST=${1:-/etc/skel/}
|
|
|
|
YAZI_HOME="${DEST}/.config/yazi"
|
|
YAZI_PLUGIN_HOME="${YAZI_HOME}/plugins"
|
|
ZDBSTAT_PLUGIN_HOME="${YAZI_PLUGIN_HOME}/httm-zdbstat.yazi"
|
|
|
|
mkdir -p "$PLUGIN_HOME"
|
|
|
|
cat >"${ZDBSTAT_PLUGIN_HOME}/main.lua" <<'EOF'
|
|
-- zdbstat.yazi/init.lua
|
|
-- Custom previewer: dump zdb -dddddddddd metadata when mode enabled
|
|
|
|
local M = {}
|
|
|
|
-- Global toggle state (persists across calls via _G)
|
|
local mode_get = ya.sync(function() return _G.ZDBSTAT_MODE or "none" end)
|
|
|
|
function M:peek(job)
|
|
local mode = mode_get()
|
|
if mode == "none" then
|
|
return -- Let default previewer handle it
|
|
end
|
|
|
|
local path = tostring(job.url)
|
|
|
|
-- Resolve realpath
|
|
local rp = ""
|
|
local rp_child = Command("realpath"):arg(path):stdout(Command.PIPED):spawn()
|
|
if rp_child then
|
|
rp_child:wait()
|
|
rp = rp_child:read_line() or path
|
|
rp = rp:gsub("\n$", "")
|
|
end
|
|
if rp == "" then rp = path end
|
|
|
|
-- Get dataset via zfs list
|
|
local dataset = ""
|
|
local ds_child = Command("zfs"):arg("list"):arg("-H"):arg("-o"):arg("name"):arg(rp)
|
|
:stdout(Command.PIPED):stderr(Command.PIPED):spawn()
|
|
if ds_child then
|
|
ds_child:wait()
|
|
dataset = ds_child:read_line() or ""
|
|
dataset = dataset:gsub("\n$", "")
|
|
end
|
|
|
|
if dataset == "" then
|
|
ya.preview_widget(job, ui.Text("Not a ZFS path or dataset not found"):area(job.area))
|
|
return
|
|
end
|
|
|
|
-- Get inode
|
|
local inode = ""
|
|
local st_child = Command("stat"):arg("-c"):arg("%i"):arg(rp)
|
|
:stdout(Command.PIPED):spawn()
|
|
if st_child then
|
|
st_child:wait()
|
|
inode = st_child:read_line() or ""
|
|
inode = inode:gsub("\n$", "")
|
|
end
|
|
|
|
if inode == "" then
|
|
ya.preview_widget(job, ui.Text("Could not get inode"):area(job.area))
|
|
return
|
|
end
|
|
|
|
-- Find sudo-like
|
|
local elevator = nil
|
|
for _, e in ipairs({"sudo", "doas", "pkexec"}) do
|
|
local test = Command(e):arg("--version"):stdout(Command.PIPED):stderr(Command.PIPED):spawn()
|
|
if test then
|
|
test:wait()
|
|
if test.status and test.status.success then
|
|
elevator = e
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Build zdb command
|
|
local zdb_cmd = Command("zdb"):arg("-dddddddddd"):arg(dataset):arg(inode)
|
|
if elevator then
|
|
zdb_cmd = Command(elevator):arg(zdb_cmd._program):args(zdb_cmd._args or {})
|
|
end
|
|
|
|
-- Capture output (PIPED so we can show in preview)
|
|
zdb_cmd:stdout(Command.PIPED):stderr(Command.PIPED)
|
|
local child, err = zdb_cmd:spawn()
|
|
if not child then
|
|
ya.preview_widget(job, ui.Text("Failed to run zdb: " .. tostring(err)):area(job.area))
|
|
return
|
|
end
|
|
|
|
child:wait()
|
|
local output = ""
|
|
for line in child:read_lines() do
|
|
output = output .. line .. "\n"
|
|
end
|
|
|
|
if output == "" then
|
|
output = "zdb returned no output (check permissions?)"
|
|
end
|
|
|
|
-- Show in preview with log-like highlighting
|
|
ya.preview_code({
|
|
area = job.area,
|
|
content = output,
|
|
filetype = "log", -- or "text" if no bat-like highlighting desired
|
|
})
|
|
end
|
|
|
|
function M:seek(job)
|
|
self:peek(job) -- No advanced seeking needed
|
|
end
|
|
|
|
return M
|
|
EOF
|
|
|
|
cat >"${ZDBSTAT_PLUGIN_HOME}/toggle.lua" <<'EOF'
|
|
-- zdbstat.yazi/toggle.lua (separate entry plugin to cycle mode)
|
|
|
|
return {
|
|
entry = function()
|
|
local modes = { "none", "zdb" }
|
|
local current = _G.ZDBSTAT_MODE or "none"
|
|
local next_mode = "none"
|
|
for i, m in ipairs(modes) do
|
|
if m == current then
|
|
next_mode = modes[(i % #modes) + 1]
|
|
break
|
|
end
|
|
end
|
|
_G.ZDBSTAT_MODE = next_mode
|
|
|
|
ya.notify({
|
|
title = "zdbstat",
|
|
content = "Preview mode: " .. next_mode,
|
|
timeout = 2,
|
|
})
|
|
|
|
-- Refresh current preview
|
|
if cx.active.current.hovered then
|
|
ya.manager_emit("peek", { cx.active.preview.skip or 0, force = true })
|
|
end
|
|
end,
|
|
}
|
|
EOF
|
|
|
|
cat <<'EOF'
|
|
|
|
Add to your yazi.toml (or yazi.toml.d/):
|
|
|
|
[plugin.preview]
|
|
prepend_previewers = [
|
|
{ name = "*", run = "zdbstat", sync = true },
|
|
]
|
|
|
|
Add to keymap.toml:
|
|
|
|
[[manager.prepend_keymap]]
|
|
on = [ "g", "z" ]
|
|
run = "plugin zdbstat --args='toggle'"
|
|
desc = "Toggle zdbstat preview (zdb metadata / default)"
|
|
|
|
EOF
|
|
|
|
echo "zdbstat previewer installed at: ${PLUGIN_HOME}/init.lua"
|
|
echo "Toggle entry at: ${PLUGIN_HOME}/toggle.lua"
|
|
echo "Restart yazi or :plugin --reload zdbstat"
|
|
echo "Press 'gz' to cycle: default preview ↔ zdb metadata preview"
|
|
echo "Note: First zdb run may prompt for sudo/doas password (terminal popup)."
|