- Add --zen flag for distraction-free markdown viewing - iTerm2/WezTerm native inline image protocol with tmux passthrough - Improved chafa fallback with format detection - Glow-based markdown rendering with custom theme - Fix is_fzf() to check stdout TTY - Enable tmux allow-passthrough for image protocol Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
234 lines
7.1 KiB
Bash
Executable File
234 lines
7.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Universal file preview — used by fzf widgets and as a standalone command.
|
|
# Usage: preview [--zen] <file> [line]
|
|
|
|
zen=false
|
|
if [[ "$1" == "--zen" ]]; then
|
|
zen=true
|
|
shift
|
|
fi
|
|
|
|
file="${1:?usage: preview [--zen] <file> [line]}"
|
|
line="${2:-}"
|
|
|
|
if [[ ! -e "$file" ]]; then
|
|
echo "not found: $file"
|
|
exit 1
|
|
fi
|
|
|
|
# Directory preview
|
|
if [[ -d "$file" ]]; then
|
|
if command -v eza &>/dev/null; then
|
|
eza --tree --level=2 --icons --color=always "$file"
|
|
else
|
|
ls -1A "$file"
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
# Standalone mode: full terminal, can page output
|
|
# fzf mode: constrained to preview pane dimensions
|
|
# Check both the env var AND that stdout is not a TTY — execute() inherits
|
|
# FZF_PREVIEW_COLUMNS but redirects stdout to /dev/tty.
|
|
is_fzf() { [[ -n "${FZF_PREVIEW_COLUMNS:-}" && ! -t 1 ]]; }
|
|
|
|
preview_image() {
|
|
local w h
|
|
if is_fzf; then
|
|
w="$FZF_PREVIEW_COLUMNS"
|
|
h="$FZF_PREVIEW_LINES"
|
|
else
|
|
w="$(tput cols)"
|
|
h="$(tput lines)"
|
|
fi
|
|
# iTerm2/WezTerm: use native inline image protocol (works through tmux passthrough)
|
|
if [[ "${LC_TERMINAL:-}${TERM_PROGRAM:-}" == *iTerm* || "${LC_TERMINAL:-}${TERM_PROGRAM:-}" == *WezTerm* ]]; then
|
|
local data
|
|
data="$(base64 < "$file")"
|
|
if [[ -n "${TMUX:-}" ]]; then
|
|
printf '\033Ptmux;\033\033]1337;File=inline=1;width=%s;height=%s;preserveAspectRatio=1:%s\a\033\\' \
|
|
"$w" "$h" "$data"
|
|
else
|
|
printf '\033]1337;File=inline=1;width=%s;height=%s;preserveAspectRatio=1:%s\a' \
|
|
"$w" "$h" "$data"
|
|
fi
|
|
if ! is_fzf; then
|
|
printf '\n[press any key]'
|
|
read -rsn1 </dev/tty
|
|
fi
|
|
else
|
|
# Fallback: chafa symbols
|
|
local fmt=symbols
|
|
if [[ -z "${TMUX:-}" ]]; then
|
|
case "${TERM_PROGRAM:-}" in
|
|
*kitty*) fmt=kitty ;;
|
|
esac
|
|
fi
|
|
chafa --format="$fmt" --work=9 --polite=off --symbols block+braille+half+quad --size="${w}x${h}" "$file"
|
|
if ! is_fzf; then
|
|
printf '\n[press any key]'
|
|
read -rsn1 </dev/tty
|
|
fi
|
|
fi
|
|
}
|
|
|
|
preview_pdf() {
|
|
if is_fzf; then
|
|
pdftotext -l 3 "$file" -
|
|
else
|
|
pdftotext "$file" - | bat --paging=always --style=plain --language=txt
|
|
fi
|
|
}
|
|
|
|
preview_markdown() {
|
|
local glow_style="${XDG_CONFIG_HOME:-$HOME/.config}/glow/preview.json"
|
|
if command -v glow &>/dev/null; then
|
|
local style_args=(-s dark)
|
|
[[ -f "$glow_style" ]] && style_args=(-s "$glow_style")
|
|
if is_fzf; then
|
|
script -q /dev/null bash -c \
|
|
'COLORTERM=truecolor glow "$@"' _ "${style_args[@]}" -w "${FZF_PREVIEW_COLUMNS:-80}" "$file" \
|
|
2>/dev/null | tr -d '\r'
|
|
else
|
|
local tmp term_w render_w
|
|
tmp=$(mktemp)
|
|
# Hide tmux chrome in zen mode
|
|
if [[ "$zen" == true && -n "${TMUX:-}" ]]; then
|
|
tmux set status off
|
|
tmux set pane-border-status off 2>/dev/null
|
|
trap 'tmux set status on; tmux set pane-border-status off 2>/dev/null; rm -f "$tmp"' EXIT
|
|
else
|
|
trap 'rm -f "$tmp"' EXIT
|
|
fi
|
|
term_w="$(tput cols)"
|
|
render_w="$term_w"
|
|
if [[ "$zen" == true ]] && (( term_w > 104 )); then
|
|
render_w=100
|
|
fi
|
|
local pad=$(( (term_w - render_w) / 2 ))
|
|
local glow_input="$file"
|
|
if [[ "$zen" == true ]]; then
|
|
# Pre-process: replace link URLs with dummy anchors (keeps link styling)
|
|
# and strip bare URLs
|
|
glow_input=$(mktemp).md
|
|
perl -pe '
|
|
s/\[([^\]]+)\]\([^\)]+\)/[$1](#)/g;
|
|
s/\s*<?https?:\/\/\S+>?//g;
|
|
' "$file" > "$glow_input"
|
|
fi
|
|
script -q /dev/null bash -c \
|
|
'COLORTERM=truecolor glow "$@"' _ "${style_args[@]}" -w "$render_w" "$glow_input" 2>/dev/null \
|
|
| tr -d '\r' \
|
|
| if (( pad > 0 )); then sed "s/^/$(printf '%*s' "$pad" '')/"; else cat; fi \
|
|
> "$tmp"
|
|
[[ "$glow_input" != "$file" ]] && rm -f "$glow_input"
|
|
LESS='-R --mouse' less < "$tmp"
|
|
fi
|
|
elif is_fzf; then
|
|
bat --color=always --style=numbers ${line:+--highlight-line="$line"} "$file"
|
|
else
|
|
bat --paging=always --color=always --style=numbers "$file"
|
|
fi
|
|
}
|
|
|
|
preview_archive() {
|
|
local lower_file
|
|
lower_file="$(printf '%s' "$file" | tr '[:upper:]' '[:lower:]')"
|
|
local output
|
|
case "$lower_file" in
|
|
*.tar|*.tar.gz|*.tgz|*.tar.bz2|*.tbz2|*.tar.xz|*.txz)
|
|
output="$(tar -tf "$file" | head -80)" ;;
|
|
*.zip|*.jar|*.war)
|
|
output="$(unzip -l "$file" | head -80)" ;;
|
|
*.gz)
|
|
output="$(gzip -l "$file")" ;;
|
|
*)
|
|
output="$(file "$file")" ;;
|
|
esac
|
|
if is_fzf; then
|
|
printf '%s\n' "$output"
|
|
else
|
|
printf '%s\n' "$output" | bat --paging=always --style=plain --language=txt
|
|
fi
|
|
}
|
|
|
|
preview_text() {
|
|
local bat_args=(--color=always --style=numbers)
|
|
if [[ -n "$line" ]]; then
|
|
bat_args+=(--highlight-line="$line")
|
|
if is_fzf; then
|
|
local start=$((line > 30 ? line - 30 : 1))
|
|
bat_args+=(--line-range="$start:$((line + 30))")
|
|
fi
|
|
elif is_fzf; then
|
|
bat_args+=(--line-range=:100)
|
|
fi
|
|
if ! is_fzf; then
|
|
bat_args+=(--paging=always)
|
|
fi
|
|
bat "${bat_args[@]}" "$file" 2>/dev/null || head -100 "$file"
|
|
}
|
|
|
|
preview_binary() {
|
|
local output
|
|
output="$(file "$file"; echo ""; hexdump -C "$file" | head -40)"
|
|
if is_fzf; then
|
|
printf '%s\n' "$output"
|
|
else
|
|
printf '%s\n' "$output" | bat --paging=always --style=plain --language=txt
|
|
fi
|
|
}
|
|
|
|
# Route by extension
|
|
ext="${file##*.}"
|
|
ext="$(printf '%s' "$ext" | tr '[:upper:]' '[:lower:]')"
|
|
|
|
case "$ext" in
|
|
png|jpg|jpeg|gif|webp|bmp|svg|ico|tiff|tif|avif)
|
|
if command -v chafa &>/dev/null; then
|
|
preview_image
|
|
else
|
|
file "$file"
|
|
fi
|
|
;;
|
|
pdf)
|
|
if command -v pdftotext &>/dev/null; then
|
|
preview_pdf
|
|
else
|
|
file "$file"
|
|
fi
|
|
;;
|
|
md|markdown|mdx)
|
|
preview_markdown
|
|
;;
|
|
tar|gz|tgz|bz2|tbz2|xz|txz|zip|jar|war)
|
|
preview_archive
|
|
;;
|
|
*)
|
|
# MIME fallback for extensionless or ambiguous files
|
|
mime="$(file --mime-type -b "$file" 2>/dev/null || echo "unknown")"
|
|
case "$mime" in
|
|
image/*)
|
|
if command -v chafa &>/dev/null; then
|
|
preview_image
|
|
else
|
|
file "$file"
|
|
fi
|
|
;;
|
|
application/pdf)
|
|
if command -v pdftotext &>/dev/null; then
|
|
preview_pdf
|
|
else
|
|
file "$file"
|
|
fi
|
|
;;
|
|
text/*|application/json|application/xml|application/javascript|*/x-shellscript)
|
|
preview_text
|
|
;;
|
|
*)
|
|
preview_binary
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|