diff options
| author | Anton Bobov <anton@bobov.name> | 2026-08-20 15:13:47 +0500 |
|---|---|---|
| committer | Anton Bobov <anton@bobov.name> | 2026-08-20 15:13:47 +0500 |
| commit | 153c9344e93662984b1a5368a2722c10117db830 (patch) | |
| tree | 46b44af16387c815ab6c783415ee7dc1b8287a5c /files/.config/nnn/plugins/preview-tui | |
| parent | ccbc3e18f711c39482e9ed6045ed99b4da889a59 (diff) | |
nnn: update plugins
Diffstat (limited to 'files/.config/nnn/plugins/preview-tui')
| -rwxr-xr-x | files/.config/nnn/plugins/preview-tui | 150 |
1 files changed, 106 insertions, 44 deletions
diff --git a/files/.config/nnn/plugins/preview-tui b/files/.config/nnn/plugins/preview-tui index e78b110..7fc48e7 100755 --- a/files/.config/nnn/plugins/preview-tui +++ b/files/.config/nnn/plugins/preview-tui @@ -5,15 +5,16 @@ # Note: This plugin needs a "NNN_FIFO" to work. See man. # # Dependencies: -# - Supports 6 independent methods to preview with: +# - Supports 7 independent methods to preview with: # - tmux (>=3.0), or # - kitty with allow_remote_control and listen_on set in kitty.conf, or # - wezterm (https://wezfurlong.org/wezterm), or # - QuickLook on WSL (https://github.com/QL-Win/QuickLook), or # - Windows Terminal (https://github.com/Microsoft/Terminal | https://aka.ms/terminal) with WSL, or +# - zellij (https://github.com/zellij-org/zellij) or # - $NNN_TERMINAL set to a terminal (it's xterm by default). # - less or $NNN_PAGER -# - tree or exa or (GNU) ls +# - tree or exa/eza or (GNU) ls # - mediainfo or file # - mktemp # - unzip @@ -21,8 +22,12 @@ # - man # - optional: bsdtar or atool for additional archive preview # - optional: bat for code syntax highlighting -# - optional: ueberzug, kitty terminal, wezterm terminal, viu, catimg or chafa for images -# - optional: convert(ImageMagick) for playing gif preview (required for kitty image previews) +# - optional: ueberzug, kitty terminal, wezterm terminal, img2sixel, viu, catimg, timg or chafa for images +# - optional: convert(ImageMagick) for playing gif preview (mandatory for kitty image previews) +# - optional: mpv for gif and video +# Also requires a terminal supporting the sixel (https://www.arewesixelyet.com/) +# or kitty (https://sw.kovidgoyal.net/kitty/graphics-protocol) video_output backends. +# Requires tmux compiled with `./configure --enable-sixel` if used. # - optional: ffmpegthumbnailer for video thumbnails (https://github.com/dirkvdb/ffmpegthumbnailer) # - optional: ffmpeg for audio thumbnails # - optional: libreoffce for opendocument/officedocument preview @@ -40,6 +45,7 @@ # - optional: pistol file viewer (https://github.com/doronbehar/pistol). # 1. install pistol # 2. set/export $NNN_PISTOL as 1 +# - optional: librsvg for rsvg-convert # # Usage: # You need to set a NNN_FIFO path and a key for the plugin with NNN_PLUG, @@ -68,6 +74,12 @@ # With ImageMagick installed, this terminal can use the icat kitten to display images. # Refer to kitty documentation for further details. # +# Users with both tmux and kitty can leverage image previews inside tmux with kitty's icat kitten +# - setup kitty as stated above +# - tmux >= v3.3a required +# - add the following to your tmux.conf: +# - `set -g allow-passthrough on` +# # Wezterm should work out of the box. If `NNN_PREVIEWIMGPROG` is not specified it will use # built in iTerm2 image protocol. # @@ -84,28 +96,33 @@ # 'no_focus [title="preview-tui"]' to your i3 config file. # # Shell: Bash (for environment manipulation through arrays) -# Authors: Todd Yamakawa, Léo Villeveygoux, @Recidiviste, Mario Ortiz Manero, Luuk van Baal, @WanderLanz +# Authors: Todd Yamakawa, Léo Villeveygoux, @Recidiviste, Mario Ortiz Manero, Luuk van Baal, @WanderLanz, @flipflop133 -NNN_SPLIT=${NNN_SPLIT:-} # Set permanent split direction -NNN_TERMINAL=${NNN_TERMINAL:-} # Set external terminal to be used -NNN_SPLITSIZE=${NNN_SPLITSIZE:-50} # Set previewer split size percentage -TMPDIR=${TMPDIR:-/tmp} +# Configurable environment variables: +NNN_SPLIT=${NNN_SPLIT:-} # permanent split direction +NNN_TERMINAL=${NNN_TERMINAL:-} # external terminal to be used +NNN_SPLITSIZE=${NNN_SPLITSIZE:-50} # previewer split size percentage +TMPDIR=${TMPDIR:-/tmp} # location of temporary files +ENVVARS=( + "NNN_SCOPE=${NNN_SCOPE:-0}" # use scope + "NNN_PISTOL=${NNN_PISTOL:-0}" # use pistol + "NNN_ICONLOOKUP=${NNN_ICONLOOKUP:-0}" # use .iconlookup + "NNN_PAGER=${NNN_PAGER:-less -P?n -R -C}" # pager options + "NNN_BATTHEME=${NNN_BATTHEME:-ansi}" # bat theme + "NNN_BATSTYLE=${NNN_BATSTYLE:-numbers}" # bat style + "NNN_PREVIEWWIDTH=${NNN_PREVIEWWIDTH:-1920}" # width of generated preview images + "NNN_PREVIEWHEIGHT=${NNN_PREVIEWHEIGHT:-1080}" # height of generated preview images + "NNN_PREVIEWDIR=${NNN_PREVIEWDIR:-$TMPDIR/nnn/previews}" # location of generated preview images + "NNN_PREVIEWIMGPROG=${NNN_PREVIEWIMGPROG:-}" # command used to preview images + "NNN_PREVIEWVIDEO=${NNN_PREVIEWVIDEO:-}" # mpv backend used to preview video +) +# Non-configurable environment variables NNN_PARENT=${NNN_FIFO#*.} [ "$NNN_PARENT" -eq "$NNN_PARENT" ] 2>/dev/null || NNN_PARENT="" # Make empty if non-numeric -ENVVARS=( +ENVVARS+=( "PWD=$PWD" "PATH=$PATH" "NNN_FIFO=$NNN_FIFO" - "NNN_SCOPE=${NNN_SCOPE:-0}" - "NNN_PISTOL=${NNN_PISTOL:-0}" - "NNN_ICONLOOKUP=${NNN_ICONLOOKUP:-0}" - "NNN_PAGER=${NNN_PAGER:-less -P?n -R -C}" - "NNN_BATTHEME=${NNN_BATTHEME:-ansi}" - "NNN_BATSTYLE=${NNN_BATSTYLE:-numbers}" - "NNN_PREVIEWWIDTH=${NNN_PREVIEWWIDTH:-1920}" - "NNN_PREVIEWHEIGHT=${NNN_PREVIEWHEIGHT:-1080}" - "NNN_PREVIEWDIR=${NNN_PREVIEWDIR:-$TMPDIR/nnn/previews}" - "NNN_PREVIEWIMGPROG=${NNN_PREVIEWIMGPROG:-}" "FIFOPID=$TMPDIR/nnn-preview-tui-fifopid.$NNN_PARENT" "FIFOPATH=$TMPDIR/nnn-preview-tui-fifo.$NNN_PARENT" "PREVIEWPID=$TMPDIR/nnn-preview-tui-previewpid.$NNN_PARENT" @@ -132,14 +149,20 @@ pidkill() { start_preview() { if [ -e "${TMUX%%,*}" ] && tmux -V | grep -q '[ -][3456789]\.'; then NNN_TERMINAL=tmux + exists mpv && tmux display -p '#{client_termfeatures}' | grep -q 'sixel' && ENVVARS+=("NNN_PREVIEWVIDEO=sixel") elif [ -n "$KITTY_LISTEN_ON" ]; then NNN_TERMINAL=kitty + exists mpv && ENVVARS+=("NNN_PREVIEWVIDEO=kitty") elif [ -n "$WEZTERM_PANE" ]; then NNN_TERMINAL=wezterm + exists mpv && ENVVARS+=("NNN_PREVIEWVIDEO=kitty") elif [ -z "$NNN_TERMINAL" ] && [ "$TERM_PROGRAM" = "iTerm.app" ]; then NNN_TERMINAL=iterm + exists mpv && ENVVARS+=("NNN_PREVIEWVIDEO=sixel") elif [ -n "$WT_SESSION" ]; then NNN_TERMINAL=winterm + elif [ -n "$ZELLIJ" ]; then + NNN_TERMINAL=zellij else NNN_TERMINAL="${NNN_TERMINAL:-xterm}" fi @@ -152,7 +175,7 @@ start_preview() { ENVVARS+=("NNN_TERMINAL=$NNN_TERMINAL" "NNN_SPLIT=$NNN_SPLIT" "QLPATH=$2" "PREVIEW_MODE=1") case "$NNN_TERMINAL" in - iterm|winterm) # need run in separate shell command: escape + iterm|winterm) # has to run in separate shell command: escape ENVVARS=("${ENVVARS[@]/#/\\\"}") ENVVARS=("${ENVVARS[@]/%/\\\"}") command="$SHELL -c 'env ${ENVVARS[*]} \\\"$0\\\" \\\"$1\\\"'" ;; @@ -162,7 +185,7 @@ start_preview() { tmux) # tmux splits are inverted ENVVARS=("${ENVVARS[@]/#/-e}") if [ "$NNN_SPLIT" = "v" ]; then split="h"; else split="v"; fi - tmux split-window "${ENVVARS[@]}" -d"$split" -p"$NNN_SPLITSIZE" "$0" "$1" ;; + tmux split-window -l"$NNN_SPLITSIZE"% "${ENVVARS[@]}" -d"$split" -p"$NNN_SPLITSIZE" "$0" "$1" ;; kitty) # Setting the layout for the new window. It will be restored after the script ends. ENVVARS=("${ENVVARS[@]/#/--env=}") kitty @ goto-layout splits @@ -187,6 +210,17 @@ EOF winterm) if [ "$NNN_SPLIT" = "h" ]; then split="H"; else split="V"; fi wt -w 0 sp -$split -s"0.$NNN_SPLITSIZE" "$command" \; -w 0 mf previous 2>/dev/null ;; + zellij) + case "$NNN_SPLIT" in + h) + direction="down" ;; + *) + direction=right ;; + esac + zellij run --name "nnn preview" --close-on-exit \ + --direction "$direction" -- env "${ENVVARS[@]}" "$0" "$1" & + (sleep 0.2 && zellij action focus-previous-pane) & + ;; *) if [ -n "$2" ]; then env "${ENVVARS[@]}" QUICKLOOK=1 "$0" "$1" & else @@ -240,7 +274,7 @@ fifo_pager() { fi ) - rm "$FIFOPATH" + rm -- "$FIFOPATH" } # Binary file: show file info inside the pager @@ -282,7 +316,7 @@ handle_ext() { md) if exists glow; then fifo_pager glow -s dark "$1" elif exists lowdown; then - fifo_pager lowdown -Tterm "$1" + fifo_pager lowdown -Tterm --term-width="$cols" --term-column="$cols" "$1" else fifo_pager pager "$1" fi ;; @@ -303,6 +337,12 @@ handle_ext() { elif exists bsdtar; then fifo_pager bsdtar -tvf "$1" fi ;; + json) + if exists jq; then + fifo_pager jq --color-output '.' "$1" + else + fifo_pager pager "$1" + fi ;; *) if [ "$3" = "bin" ]; then fifo_pager print_bin_info "$1" else @@ -349,7 +389,9 @@ preview_file() { elif exists tree; then fifo_pager tree --filelimit "$(find . -maxdepth 1 | wc -l)" -L 3 -C -F --dirsfirst --noreport elif exists exa; then - exa -G --group-directories-first --colour=always + fifo_pager exa -T --group-directories-first --colour=always -L 3 . + elif exists eza; then # eza is a community fork of exa (exa is unmaintained) + fifo_pager eza -T --group-directories-first --colour=always -L 3 . else fifo_pager ls -F --group-directories-first --color=always fi @@ -364,6 +406,9 @@ preview_file() { generate_preview() { if [ -n "$QLPATH" ] && stat "$3"; then f="$(wslpath -w "$3")" && "$QLPATH" "$f" & + elif [ -n "$NNN_PREVIEWVIDEO" ] && [[ "$4" == +(gif|video) ]]; then + [ "$4" = "video" ] && args=(--start=10% --length=4) || args=() + video_preview "$1" "$2" "$3" "${args[@]}" && return elif [ ! -f "$NNN_PREVIEWDIR/$3.jpg" ] || [ -n "$(find -L "$3" -newer "$NNN_PREVIEWDIR/$3.jpg")" ]; then mkdir -p "$NNN_PREVIEWDIR/${3%/*}" case $4 in @@ -387,25 +432,30 @@ generate_preview() { done & printf "%s" "$!" > "$PREVIEWPID" return + elif [ -n "$NNN_PREVIEWVIDEO" ]; then + video_preview "$1" "$2" "$3" && return else - image_preview "$1" "$2" "$3" - return + image_preview "$1" "$2" "$3" && return fi ;; - image) if exists convert; then + image) if exists rsvg-convert && [[ "${3##*.}" == "svg" ]]; then + rsvg-convert -a -w "$NNN_PREVIEWWIDTH" -h "$NNN_PREVIEWHEIGHT" -f png -o "$NNN_PREVIEWDIR/$3.png" "$3" + elif exists convert; then convert "$3" -flatten -resize "$NNN_PREVIEWWIDTH"x"$NNN_PREVIEWHEIGHT"\> "$NNN_PREVIEWDIR/$3.jpg" else image_preview "$1" "$2" "$3" && return fi ;; office) libreoffice --convert-to jpg "$3" --outdir "$NNN_PREVIEWDIR/${3%/*}" filename="$(printf "%s" "${3##*/}" | cut -d. -f1)" - mv "$NNN_PREVIEWDIR/${3%/*}/$filename.jpg" "$NNN_PREVIEWDIR/$3.jpg" ;; + mv -- "$NNN_PREVIEWDIR/${3%/*}/$filename.jpg" "$NNN_PREVIEWDIR/$3.jpg" ;; pdf) pdftoppm -jpeg -f 1 -singlefile "$3" "$NNN_PREVIEWDIR/$3" ;; djvu) ddjvu -format=ppm -page=1 "$3" "$NNN_PREVIEWDIR/$3.jpg" ;; - video) ffmpegthumbnailer -m -s0 -i "$3" -o "$NNN_PREVIEWDIR/$3.jpg" || rm "$NNN_PREVIEWDIR/$3.jpg" ;; + video) video_preview "$1" "$2" "$3" && return ;; esac fi if [ -f "$NNN_PREVIEWDIR/$3.jpg" ]; then image_preview "$1" "$2" "$NNN_PREVIEWDIR/$3.jpg" + elif [[ "${3##*.}" == "svg" ]] && [ -f "$NNN_PREVIEWDIR/$3.png" ]; then + image_preview "$1" "$2" "$NNN_PREVIEWDIR/$3.png" else fifo_pager print_bin_info "$3" fi @@ -414,24 +464,33 @@ generate_preview() { image_preview() { clear exec >/dev/tty - if [ "$NNN_TERMINAL" = "kitty" ] && [ -z "$NNN_PREVIEWIMGPROG" ]; then + if [ "$NNN_TERMINAL" = "kitty" ] && [[ "$NNN_PREVIEWIMGPROG" == +(|icat) ]]; then kitty +kitten icat --silent --scale-up --place "$1"x"$2"@0x0 --transfer-mode=stream --stdin=no "$3" & - elif [ "$NNN_TERMINAL" = "wezterm" ] && [ -z "$NNN_PREVIEWIMGPROG" ]; then + elif [ "$NNN_TERMINAL" = "tmux" ] && [[ -n "$KITTY_LISTEN_ON" ]] && [[ "$NNN_PREVIEWIMGPROG" == +(|icat) ]]; then + kitty +kitten icat --silent --scale-up --place "$(($1 - 1))x$(($2 - 1))"@0x0 --transfer-mode=memory --stdin=no "$3" & + elif [ "$NNN_TERMINAL" = "wezterm" ] && [[ "$NNN_PREVIEWIMGPROG" == +(|imgcat) ]]; then wezterm imgcat "$3" & - elif exists ueberzug && { [ -z "$NNN_PREVIEWIMGPROG" ] || [ "$NNN_PREVIEWIMGPROG" = "ueberzug" ] ;}; then + elif exists ueberzug && [[ "$NNN_PREVIEWIMGPROG" == +(|ueberzug) ]]; then ueberzug_layer "$1" "$2" "$3" && return - elif exists catimg && { [ -z "$NNN_PREVIEWIMGPROG" ] || [ "$NNN_PREVIEWIMGPROG" = "catimg" ] ;}; then - catimg "$3" & - elif exists viu && { [ -z "$NNN_PREVIEWIMGPROG" ] || [ "$NNN_PREVIEWIMGPROG" = "viu" ] ;}; then - viu -t "$3" & - elif exists chafa && { [ -z "$NNN_PREVIEWIMGPROG" ] || [ "$NNN_PREVIEWIMGPROG" = "chafa" ] ;}; then - chafa "$3" & + elif exists "${NNN_PREVIEWIMGPROG%% *}"; then # can include command flags; only check first word + $NNN_PREVIEWIMGPROG "$3" & else fifo_pager print_bin_info "$3" && return fi printf "%s" "$!" > "$PREVIEWPID" } +video_preview() { + clear + exec >/dev/tty + if [ -n "$NNN_PREVIEWVIDEO" ]; then + mpv --no-config --really-quiet --vo="$NNN_PREVIEWVIDEO" --profile=sw-fast --loop-file --no-audio "$4" "$3" & + else + ffmpegthumbnailer -m -s0 -i "$3" -o "$NNN_PREVIEWDIR/$3.jpg" || rm -- "$NNN_PREVIEWDIR/$3.jpg" & + fi + printf "%s" "$!" > "$PREVIEWPID" +} + ueberzug_layer() { [ -f "$POSOFFSET" ] && read -r x y < "$POSOFFSET" printf '{"action": "add", "identifier": "nnn_ueberzug", "x": %d, "y": %d, "width": "%d", "height": "%d", "scaler": "fit_contain", "path": "%s"}\n'\ @@ -457,6 +516,7 @@ preview_fifo() { if [ -n "$selection" ]; then pidkill "$PREVIEWPID" [ -p "$FIFO_UEBERZUG" ] && ueberzug_remove + [ -n "$KITTY_LISTEN_ON" ] && kitty +kitten icat --clear --stdin=no >/dev/tty 2>/dev/null [ "$selection" = "close" ] && break preview_file "$selection" printf "%s" "$selection" > "$CURSEL" @@ -467,18 +527,20 @@ preview_fifo() { } if [ "$PREVIEW_MODE" -eq 1 ] 2>/dev/null; then - if [ "$NNN_TERMINAL" != "kitty" ] && exists ueberzug; then + if exists ueberzug && [ "$NNN_TERMINAL" != "kitty" ] && [[ "$NNN_PREVIEWIMGPROG" == +(|ueberzug) ]]; then mkfifo "$FIFO_UEBERZUG" tail --follow "$FIFO_UEBERZUG" | ueberzug layer --silent --parser json & fi preview_file "$PWD/$1" - preview_fifo & + preview_fifo & WAITPID=$! printf "%s" "$!" > "$FIFOPID" printf "%s" "$PWD/$1" > "$CURSEL" - trap 'winch_handler; wait' WINCH - trap 'rm "$PREVIEWPID" "$CURSEL" "$FIFO_UEBERZUG" "$FIFOPID" "$POSOFFSET" 2>/dev/null' INT HUP EXIT - wait "$!" 2>/dev/null + trap 'winch_handler' WINCH + trap 'rm -- "$PREVIEWPID" "$CURSEL" "$FIFO_UEBERZUG" "$FIFOPID" "$POSOFFSET" 2>/dev/null' INT HUP EXIT + while kill -s 0 $WAITPID; do + wait $WAITPID 2>/dev/null + done exit 0 else if [ ! -r "$NNN_FIFO" ]; then |
