My build of nnn with minor changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

199 line
5.6 KiB

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