preview: zen mode, native images, glow rendering
- 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>
This commit is contained in:
200
home/.config/glow/preview.json
Normal file
200
home/.config/glow/preview.json
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
{
|
||||||
|
"document": {
|
||||||
|
"block_prefix": "\n",
|
||||||
|
"block_suffix": "\n",
|
||||||
|
"color": "#CCE0D0",
|
||||||
|
"margin": 2
|
||||||
|
},
|
||||||
|
"block_quote": {
|
||||||
|
"indent": 1,
|
||||||
|
"indent_token": "│ ",
|
||||||
|
"color": "#808080"
|
||||||
|
},
|
||||||
|
"paragraph": {},
|
||||||
|
"list": {
|
||||||
|
"level_indent": 2
|
||||||
|
},
|
||||||
|
"heading": {
|
||||||
|
"block_suffix": "\n",
|
||||||
|
"bold": true
|
||||||
|
},
|
||||||
|
"h1": {
|
||||||
|
"prefix": " ",
|
||||||
|
"suffix": " ",
|
||||||
|
"color": "#CCE0D0",
|
||||||
|
"background_color": "#4068D4",
|
||||||
|
"bold": true
|
||||||
|
},
|
||||||
|
"h2": {
|
||||||
|
"prefix": "",
|
||||||
|
"color": "#7290B8",
|
||||||
|
"bold": true
|
||||||
|
},
|
||||||
|
"h3": {
|
||||||
|
"prefix": "",
|
||||||
|
"color": "#2CB494",
|
||||||
|
"bold": true
|
||||||
|
},
|
||||||
|
"h4": {
|
||||||
|
"prefix": "",
|
||||||
|
"color": "#F88C14",
|
||||||
|
"bold": true
|
||||||
|
},
|
||||||
|
"h5": {
|
||||||
|
"prefix": "",
|
||||||
|
"color": "#808080"
|
||||||
|
},
|
||||||
|
"h6": {
|
||||||
|
"prefix": "",
|
||||||
|
"color": "#808080",
|
||||||
|
"bold": false
|
||||||
|
},
|
||||||
|
"text": {},
|
||||||
|
"strikethrough": {
|
||||||
|
"crossed_out": true
|
||||||
|
},
|
||||||
|
"emph": {
|
||||||
|
"italic": true
|
||||||
|
},
|
||||||
|
"strong": {
|
||||||
|
"bold": true
|
||||||
|
},
|
||||||
|
"hr": {
|
||||||
|
"color": "#3C3C3C",
|
||||||
|
"format": "\n--------\n"
|
||||||
|
},
|
||||||
|
"item": {
|
||||||
|
"block_prefix": "• "
|
||||||
|
},
|
||||||
|
"enumeration": {
|
||||||
|
"block_prefix": ". "
|
||||||
|
},
|
||||||
|
"task": {
|
||||||
|
"ticked": "[✓] ",
|
||||||
|
"unticked": "[ ] "
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"color": "#4068D4",
|
||||||
|
"underline": true
|
||||||
|
},
|
||||||
|
"link_text": {
|
||||||
|
"color": "#2CB494",
|
||||||
|
"bold": true
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"color": "#4068D4",
|
||||||
|
"underline": true
|
||||||
|
},
|
||||||
|
"image_text": {
|
||||||
|
"color": "#808080",
|
||||||
|
"format": "Image: {{.text}} →"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"prefix": " ",
|
||||||
|
"suffix": " ",
|
||||||
|
"color": "#F88C14",
|
||||||
|
"background_color": "#0A0A0A"
|
||||||
|
},
|
||||||
|
"code_block": {
|
||||||
|
"color": "#CCE0D0",
|
||||||
|
"margin": 2,
|
||||||
|
"chroma": {
|
||||||
|
"text": {
|
||||||
|
"color": "#CCE0D0"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"color": "#CCE0D0",
|
||||||
|
"background_color": "#F05B5B"
|
||||||
|
},
|
||||||
|
"comment": {
|
||||||
|
"color": "#808080"
|
||||||
|
},
|
||||||
|
"comment_preproc": {
|
||||||
|
"color": "#F88C14"
|
||||||
|
},
|
||||||
|
"keyword": {
|
||||||
|
"color": "#4068D4"
|
||||||
|
},
|
||||||
|
"keyword_reserved": {
|
||||||
|
"color": "#88409C"
|
||||||
|
},
|
||||||
|
"keyword_namespace": {
|
||||||
|
"color": "#4068D4"
|
||||||
|
},
|
||||||
|
"keyword_type": {
|
||||||
|
"color": "#2CB494"
|
||||||
|
},
|
||||||
|
"operator": {
|
||||||
|
"color": "#F88C14"
|
||||||
|
},
|
||||||
|
"punctuation": {
|
||||||
|
"color": "#CCE0D0"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"color": "#CCE0D0"
|
||||||
|
},
|
||||||
|
"name_builtin": {
|
||||||
|
"color": "#2CB494"
|
||||||
|
},
|
||||||
|
"name_tag": {
|
||||||
|
"color": "#88409C"
|
||||||
|
},
|
||||||
|
"name_attribute": {
|
||||||
|
"color": "#4068D4"
|
||||||
|
},
|
||||||
|
"name_class": {
|
||||||
|
"color": "#7290B8",
|
||||||
|
"underline": true,
|
||||||
|
"bold": true
|
||||||
|
},
|
||||||
|
"name_constant": {
|
||||||
|
"color": "#F88C14"
|
||||||
|
},
|
||||||
|
"name_decorator": {
|
||||||
|
"color": "#FCFC38"
|
||||||
|
},
|
||||||
|
"name_exception": {},
|
||||||
|
"name_function": {
|
||||||
|
"color": "#7290B8"
|
||||||
|
},
|
||||||
|
"name_other": {},
|
||||||
|
"literal": {},
|
||||||
|
"literal_number": {
|
||||||
|
"color": "#F88C14"
|
||||||
|
},
|
||||||
|
"literal_date": {},
|
||||||
|
"literal_string": {
|
||||||
|
"color": "#2CB494"
|
||||||
|
},
|
||||||
|
"literal_string_escape": {
|
||||||
|
"color": "#2CB494"
|
||||||
|
},
|
||||||
|
"generic_deleted": {
|
||||||
|
"color": "#F88C14"
|
||||||
|
},
|
||||||
|
"generic_emph": {
|
||||||
|
"italic": true
|
||||||
|
},
|
||||||
|
"generic_inserted": {
|
||||||
|
"color": "#2CB494"
|
||||||
|
},
|
||||||
|
"generic_strong": {
|
||||||
|
"bold": true
|
||||||
|
},
|
||||||
|
"generic_subheading": {
|
||||||
|
"color": "#808080"
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"background_color": "#1A1A1A"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"table": {},
|
||||||
|
"definition_list": {},
|
||||||
|
"definition_term": {},
|
||||||
|
"definition_description": {
|
||||||
|
"block_prefix": "\n🠶 "
|
||||||
|
},
|
||||||
|
"html_block": {},
|
||||||
|
"html_span": {}
|
||||||
|
}
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Universal file preview — used by fzf widgets and as a standalone command.
|
# Universal file preview — used by fzf widgets and as a standalone command.
|
||||||
# Usage: preview <file> [line]
|
# Usage: preview [--zen] <file> [line]
|
||||||
|
|
||||||
file="${1:?usage: preview <file> [line]}"
|
zen=false
|
||||||
|
if [[ "$1" == "--zen" ]]; then
|
||||||
|
zen=true
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
file="${1:?usage: preview [--zen] <file> [line]}"
|
||||||
line="${2:-}"
|
line="${2:-}"
|
||||||
|
|
||||||
if [[ ! -e "$file" ]]; then
|
if [[ ! -e "$file" ]]; then
|
||||||
@@ -22,21 +28,47 @@ fi
|
|||||||
|
|
||||||
# Standalone mode: full terminal, can page output
|
# Standalone mode: full terminal, can page output
|
||||||
# fzf mode: constrained to preview pane dimensions
|
# fzf mode: constrained to preview pane dimensions
|
||||||
is_fzf() { [[ -n "${FZF_PREVIEW_COLUMNS:-}" ]]; }
|
# 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() {
|
preview_image() {
|
||||||
local w h
|
local w h
|
||||||
if is_fzf; then
|
if is_fzf; then
|
||||||
w="$FZF_PREVIEW_COLUMNS"
|
w="$FZF_PREVIEW_COLUMNS"
|
||||||
h="$FZF_PREVIEW_LINES"
|
h="$FZF_PREVIEW_LINES"
|
||||||
chafa --size="${w}x${h}" "$file"
|
|
||||||
else
|
else
|
||||||
w="$(tput cols)"
|
w="$(tput cols)"
|
||||||
h="$(tput lines)"
|
h="$(tput lines)"
|
||||||
printf '\033[?1049h'
|
fi
|
||||||
chafa --size="${w}x${h}" "$file"
|
# iTerm2/WezTerm: use native inline image protocol (works through tmux passthrough)
|
||||||
read -rsn1
|
if [[ "${LC_TERMINAL:-}${TERM_PROGRAM:-}" == *iTerm* || "${LC_TERMINAL:-}${TERM_PROGRAM:-}" == *WezTerm* ]]; then
|
||||||
printf '\033[?1049l'
|
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
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,10 +81,51 @@ preview_pdf() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preview_markdown() {
|
preview_markdown() {
|
||||||
if is_fzf; then
|
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"
|
bat --color=always --style=numbers ${line:+--highlight-line="$line"} "$file"
|
||||||
elif command -v glow &>/dev/null; then
|
|
||||||
glow -p "$file"
|
|
||||||
else
|
else
|
||||||
bat --paging=always --color=always --style=numbers "$file"
|
bat --paging=always --color=always --style=numbers "$file"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ set -g history-limit 100000
|
|||||||
set -sg escape-time 10
|
set -sg escape-time 10
|
||||||
set -g focus-events on
|
set -g focus-events on
|
||||||
set -g display-time 4000
|
set -g display-time 4000
|
||||||
|
set -g allow-passthrough on
|
||||||
|
|
||||||
# Mouse
|
# Mouse
|
||||||
set -g mouse on
|
set -g mouse on
|
||||||
|
|||||||
Reference in New Issue
Block a user