sistema_progs

Programas para customizar o meu entorno de traballo nos meus equipos persoais
Log | Files | Refs

preview-tabbed (6056B)


      1 #!/usr/bin/env bash
      2 
      3 # Description: tabbed/xembed based file previewer
      4 #
      5 # Dependencies:
      6 #   - tabbed (https://tools.suckless.org/tabbed): xembed host
      7 #   - xterm (or urxvt or st) : xembed client for text-based preview
      8 #   - mpv (https://mpv.io): xembed client for video/audio
      9 #   - sxiv (https://github.com/muennich/sxiv) or,
     10 #   - nsxiv (https://github.com/nsxiv/nsxiv) : xembed client for images
     11 #   - zathura (https://pwmt.org/projects/zathura): xembed client for PDF
     12 #   - nnn's nuke plugin for text preview and fallback
     13 #     nuke is a fallback for 'mpv', 'sxiv'/'nsxiv', and 'zathura', but has its
     14 #     own dependencies, see the script for more information
     15 #   - vim (or any editor/pager really)
     16 #   - file
     17 #   - mktemp
     18 #   - xdotool (optional, to keep main window focused)
     19 #
     20 # Usage:
     21 #   - Install the dependencies. Then set a NNN_FIFO
     22 #     and set a key for the plugin, then start `nnn`:
     23 #       $ NNN_FIFO=/tmp/nnn.fifo nnn
     24 #   - Launch the plugin with the designated key from nnn
     25 #
     26 # Notes:
     27 #   1. This plugin needs a "NNN_FIFO" to work. See man.
     28 #   2. If the same NNN_FIFO is used in multiple nnn instances, there will be one
     29 #      common preview window. With different FIFO paths, they will be independent.
     30 #
     31 # How it works:
     32 #   We use `tabbed` [1] as a xembed [2] host, to have a single window
     33 #   owning each previewer window. So each previewer must be a xembed client.
     34 #   For text previewers, this is not an issue, as there are a lot of
     35 #   xembed-able terminal emulator (we default to `xterm`, but examples are
     36 #   provided for `urxvt` and `st`). For graphic preview this can be trickier,
     37 #   but a few popular viewers are xembed-able, we use:
     38 #     - `mpv`: multimedia player, for video/audio preview
     39 #     - `sxiv`/`nsxiv`: image viewer
     40 #     - `zathura`: PDF viewer
     41 #     - but we always fallback to `nuke` plugin
     42 #
     43 # [1]: https://tools.suckless.org/tabbed/
     44 # [2]: https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html
     45 #
     46 # Shell: Bash (job control is weakly specified in POSIX)
     47 # Author: Léo Villeveygoux
     48 
     49 
     50 XDOTOOL_TIMEOUT=2
     51 PAGER=${PAGER:-"vim -R"}
     52 NUKE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins/nuke"
     53 
     54 
     55 if type xterm >/dev/null 2>&1 ; then
     56     TERMINAL="xterm -into"
     57 elif type urxvt >/dev/null 2>&1 ; then
     58     TERMINAL="urxvt -embed"
     59 elif type st >/dev/null 2>&1 ; then
     60     TERMINAL="st -w"
     61 else
     62     echo "No xembed term found" >&2
     63 fi
     64 
     65 
     66 term_nuke () {
     67     # $1 -> $XID, $2 -> $FILE
     68     $TERMINAL "$1" -e "$NUKE" "$2" &
     69 }
     70 
     71 start_tabbed () {
     72     FIFO="$(mktemp -u)"
     73     mkfifo "$FIFO"
     74 
     75     tabbed > "$FIFO" &
     76 
     77     jobs # Get rid of the "Completed" entries
     78 
     79     TABBEDPID="$(jobs -p %%)"
     80 
     81     if [ -z "$TABBEDPID" ] ; then
     82         echo "Can't start tabbed"
     83         exit 1
     84     fi
     85 
     86     read -r XID < "$FIFO"
     87 
     88     rm "$FIFO"
     89 }
     90 
     91 get_viewer_pid () {
     92         VIEWERPID="$(jobs -p %%)"
     93 }
     94 
     95 kill_viewer () {
     96         if [ -n "$VIEWERPID" ] && jobs -p | grep "$VIEWERPID" ; then
     97             kill "$VIEWERPID"
     98         fi
     99 }
    100 
    101 sigint_kill () {
    102 	kill_viewer
    103 	kill "$TABBEDPID"
    104 	exit 0
    105 }
    106 
    107 previewer_loop () {
    108     unset -v NNN_FIFO
    109     # mute from now
    110     exec >/dev/null 2>&1
    111 
    112     MAINWINDOW="$(xdotool getactivewindow)"
    113 
    114     start_tabbed
    115     trap sigint_kill SIGINT
    116 
    117     xdotool windowactivate "$MAINWINDOW"
    118 
    119     # Bruteforce focus stealing prevention method,
    120     # works well in floating window managers like XFCE
    121     # but make interaction with the preview window harder
    122     # (uncomment to use):
    123     #xdotool behave "$XID" focus windowactivate "$MAINWINDOW" &
    124 
    125     while read -r FILE ; do
    126 
    127         jobs # Get rid of the "Completed" entries
    128 
    129         if ! jobs | grep tabbed ; then
    130             break
    131         fi
    132 
    133         if [ ! -e "$FILE" ] ; then
    134             continue
    135         fi
    136 
    137         kill_viewer
    138 
    139         MIME="$(file -bL --mime-type "$FILE")"
    140 
    141         case "$MIME" in
    142             video/*)
    143                 if type mpv >/dev/null 2>&1 ; then
    144                     mpv --force-window=immediate --loop-file --wid="$XID" "$FILE" &
    145                 else
    146                     term_nuke "$XID" "$FILE"
    147                 fi
    148                 ;;
    149             audio/*)
    150                 if type mpv >/dev/null 2>&1 ; then
    151                     mpv --force-window=immediate --loop-file --wid="$XID" "$FILE" &
    152                 else
    153                     term_nuke "$XID" "$FILE"
    154                 fi
    155                 ;;
    156             image/*)
    157                 if type sxiv >/dev/null 2>&1 ; then
    158                     sxiv -ae "$XID" "$FILE" &
    159                 elif type nsxiv >/dev/null 2>&1 ; then
    160                     nsxiv -ae "$XID" "$FILE" &
    161                 else
    162                     term_nuke "$XID" "$FILE"
    163                 fi
    164                 ;;
    165             application/pdf)
    166                 if type zathura >/dev/null 2>&1 ; then
    167                     zathura -e "$XID" "$FILE" &
    168                 else
    169                     term_nuke "$XID" "$FILE"
    170                 fi
    171                 ;;
    172             inode/directory)
    173                 $TERMINAL "$XID" -e nnn "$FILE" &
    174                 ;;
    175             text/*)
    176                 if [ -x "$NUKE" ] ; then
    177                     term_nuke "$XID" "$FILE"
    178                 else
    179                     # shellcheck disable=SC2086
    180                     $TERMINAL "$XID" -e $PAGER "$FILE" &
    181                 fi
    182                 ;;
    183             *)
    184                 if [ -x "$NUKE" ] ; then
    185                     term_nuke "$XID" "$FILE"
    186                 else
    187                     $TERMINAL "$XID" -e sh -c "file '$FILE' | $PAGER -" &
    188                 fi
    189                 ;;
    190         esac
    191         get_viewer_pid
    192 
    193         # following lines are not needed with the bruteforce xdotool method
    194         ACTIVE_XID="$(xdotool getactivewindow)"
    195         if [ $((ACTIVE_XID == XID)) -ne 0 ] ; then
    196             xdotool windowactivate "$MAINWINDOW"
    197         else
    198             timeout "$XDOTOOL_TIMEOUT" xdotool behave "$XID" focus windowactivate "$MAINWINDOW" &
    199         fi
    200     done
    201     kill "$TABBEDPID"
    202     kill_viewer
    203 }
    204 
    205 if [ ! -r "$NNN_FIFO" ] ; then
    206     echo "Can't read \$NNN_FIFO ('$NNN_FIFO')"
    207     exit 1
    208 fi
    209 
    210 previewer_loop < "$NNN_FIFO" &
    211 disown