My build of nnn with minor changes
 
 
 
 
 
 

198 lines
5.5 KiB

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