mirror of
https://github.com/jarun/nnn.git
synced 2024-11-28 05:41:31 +00:00
Add a tabbed/xembed based file previewer plugin (#552)
* Add a tabbed/xembed based file previewer plugin This plugin is written in bash, because job control is not well specified in POSIX sh (`jobs` can return anything). We use `tabbed` [1] as a xembed [2] host, to have a single window owning each previewer window. Uses mpv, sxiv, zathura, and the nuke plugin. [1]: http://tools.suckless.org/tabbed/ [2]: https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html * tabbed-preview: prevent focus steal with xdotool * preview-tabbed: tabs->4 spaces * preview-tabbed: add focus prevention timeout
This commit is contained in:
parent
4c18f22587
commit
f47700a609
|
@ -60,6 +60,7 @@ Plugins are installed to `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins`.
|
|||
| pdfread | Read a PDF or text file aloud | sh | pdftotext, mpv,<br>pico2wave |
|
||||
| pdfview | View PDF file in `$PAGER` | sh | pdftotext/<br>mupdf-tools |
|
||||
| picker | Pick files and list one per line (to pipe) | sh | nnn |
|
||||
| preview-tabbed | `tabbed`/xembed based file previewer | bash | _see in-file docs_ |
|
||||
| pskill | Fuzzy list by name and kill process or zombie | sh | fzf/fzy, ps,<br>sudo/doas |
|
||||
| renamer | Batch rename selection or files in dir | sh | [qmv](https://www.nongnu.org/renameutils/)/[vidir](https://joeyh.name/code/moreutils/) |
|
||||
| ringtone | Create a variable bitrate mp3 ringtone from file | sh | date, ffmpeg |
|
||||
|
|
197
plugins/preview-tabbed
Executable file
197
plugins/preview-tabbed
Executable file
|
@ -0,0 +1,197 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Description: tabbed/xembed based file previewer
|
||||
#
|
||||
# Note: This plugin needs a "NNN_FIFO" to work. See man.
|
||||
#
|
||||
# Shell: Bash (job control is weakly specified in POSIX)
|
||||
#
|
||||
# Dependencies:
|
||||
# - tabbed (https://tools.suckless.org/tabbed): xembed host
|
||||
# - xterm (or urxvt or st) : xembed client for text-based preview
|
||||
# - mpv (https://mpv.io): xembed client for video/audio
|
||||
# - sxiv (https://github.com/muennich/sxiv): xembed client for images
|
||||
# - zathura (https://pwmt.org/projects/zathura): xembed client for PDF documents
|
||||
# - nnn's nuke plugin for text preview and fallback (should be in plugins directory)
|
||||
# nuke is a fallback for 'mpv', 'sxiv', and 'zathura', but it has has its own
|
||||
# dependencies, see the script itself
|
||||
# - vim (or any editor/pager really)
|
||||
# - file
|
||||
# - xdotool (optional, to keep main window focused)
|
||||
#
|
||||
# How to use:
|
||||
# First, install the dependencies. Then you need to set a NNN_FIFO path
|
||||
# and set a key for the plugin, then start `nnn`:
|
||||
#
|
||||
# $ NNN_FIFO=/tmp/nnn.fifo nnn
|
||||
#
|
||||
# Then in `nnn`, launch the `preview-tabbed` plugin.
|
||||
#
|
||||
# If you provide the same NNN_FIFO to all nnn instances, there will be a
|
||||
# single common preview window. I you provide different FIFO path, they
|
||||
# will be independent.
|
||||
#
|
||||
# How it works:
|
||||
# We use `tabbed` [1] as a xembed [2] host, to have a single window
|
||||
# owning each previewer window. So each previewer must be a xembed client.
|
||||
# For text previewers, this is not an issue, as there are a lot of
|
||||
# xembed-able terminal emulator (we default to `xterm`, but examples are
|
||||
# provided for `urxvt` and `st`). For graphic preview this can be trickier,
|
||||
# but a few popular viewers are xembed-able, we use:
|
||||
# - `mpv`: multimedia player, for video/audio preview
|
||||
# - `sxiv`: image viewer
|
||||
# - `zathura`: PDF viewer
|
||||
# - but we allways fallback to `nuke` plugin
|
||||
#
|
||||
# [1]: http://tools.suckless.org/tabbed/
|
||||
# [2]: https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html
|
||||
|
||||
|
||||
XDOTOOL_TIMEOUT=2
|
||||
PAGER=${PAGER:-"vim -R"}
|
||||
NUKE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins/nuke"
|
||||
|
||||
|
||||
if which xterm ; then
|
||||
TERMINAL="xterm -into"
|
||||
elif which urxvt ; then
|
||||
TERMINAL="urxvt -embed"
|
||||
elif which st ; then
|
||||
TERMINAL="st -w"
|
||||
else
|
||||
echo "No xembed term found" >&2
|
||||
fi
|
||||
|
||||
|
||||
term_nuke () {
|
||||
# $1 -> $XID, $2 -> $FILE
|
||||
$TERMINAL "$1" -e "$NUKE" "$2" &
|
||||
}
|
||||
|
||||
start_tabbed () {
|
||||
FIFO="$(mktemp -u)"
|
||||
mkfifo "$FIFO"
|
||||
|
||||
tabbed > "$FIFO" &
|
||||
|
||||
jobs # Get rid of the "Completed" entries
|
||||
|
||||
TABBEDPID="$(jobs -p %%)"
|
||||
|
||||
if [ -z "$TABBEDPID" ] ; then
|
||||
echo "Can't start tabbed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
read -r XID < "$FIFO"
|
||||
|
||||
rm "$FIFO"
|
||||
}
|
||||
|
||||
get_viewer_pid () {
|
||||
VIEWERPID="$(jobs -p %%)"
|
||||
}
|
||||
|
||||
previewer_loop () {
|
||||
unset -v NNN_FIFO
|
||||
# mute from now
|
||||
exec >/dev/null 2>&1
|
||||
|
||||
MAINWINDOW="$(xdotool getactivewindow)"
|
||||
|
||||
start_tabbed
|
||||
|
||||
xdotool windowactivate "$MAINWINDOW"
|
||||
|
||||
# Bruteforce focus stealing prevention method,
|
||||
# works well in floating window managers like XFCE
|
||||
# but make interaction with the preview window harder
|
||||
# (uncomment to use):
|
||||
#xdotool behave "$XID" focus windowactivate "$MAINWINDOW" &
|
||||
|
||||
while read -r FILE ; do
|
||||
|
||||
jobs # Get rid of the "Completed" entries
|
||||
|
||||
if ! jobs | grep tabbed ; then
|
||||
break
|
||||
fi
|
||||
|
||||
if [ ! -e "$FILE" ] ; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ -n "$VIEWERPID" ] && jobs -p | grep "$VIEWERPID" ; then
|
||||
kill "$VIEWERPID"
|
||||
fi
|
||||
|
||||
MIME="$(file -b --mime-type "$FILE")"
|
||||
|
||||
case "$MIME" in
|
||||
video/*)
|
||||
if which mpv ; then
|
||||
mpv --force-window=immediate --loop-file --wid="$XID" "$FILE" &
|
||||
else
|
||||
term_nuke "$XID" "$FILE"
|
||||
fi
|
||||
;;
|
||||
audio/*)
|
||||
if which mpv ; then
|
||||
mpv --force-window=immediate --loop-file --wid="$XID" "$FILE" &
|
||||
else
|
||||
term_nuke "$XID" "$FILE"
|
||||
fi
|
||||
;;
|
||||
image/*)
|
||||
if which sxiv ; then
|
||||
sxiv -e "$XID" "$FILE" &
|
||||
else
|
||||
term_nuke "$XID" "$FILE"
|
||||
fi
|
||||
;;
|
||||
application/pdf)
|
||||
if which zathura ; then
|
||||
zathura -e "$XID" "$FILE" &
|
||||
else
|
||||
term_nuke "$XID" "$FILE"
|
||||
fi
|
||||
;;
|
||||
inode/directory)
|
||||
$TERMINAL "$XID" -e nnn "$FILE" &
|
||||
;;
|
||||
text/*)
|
||||
if [ -x "$NUKE" ] ; then
|
||||
term_nuke "$XID" "$FILE"
|
||||
else
|
||||
# shellcheck disable=SC2086
|
||||
$TERMINAL "$XID" -e $PAGER "$FILE" &
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if [ -x "$NUKE" ] ; then
|
||||
term_nuke "$XID" "$FILE"
|
||||
else
|
||||
$TERMINAL "$XID" -e sh -c "file '$FILE' | $PAGER -" &
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
get_viewer_pid
|
||||
|
||||
# following lines are not needed with the bruteforce xdotool method
|
||||
ACTIVE_XID="$(xdotool getactivewindow)"
|
||||
if [ $((ACTIVE_XID == XID)) -ne 0 ] ; then
|
||||
xdotool windowactivate "$MAINWINDOW"
|
||||
else
|
||||
timeout "$XDOTOOL_TIMEOUT" xdotool behave "$XID" focus windowactivate "$MAINWINDOW" &
|
||||
fi
|
||||
done
|
||||
kill "$TABBEDPID"
|
||||
}
|
||||
|
||||
if [ ! -r "$NNN_FIFO" ] ; then
|
||||
echo "Can't read \$NNN_FIFO ('$NNN_FIFO')"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
previewer_loop < "$NNN_FIFO" &
|
||||
disown
|
Loading…
Reference in a new issue