aboutsummaryrefslogtreecommitdiff
path: root/files/.config
diff options
context:
space:
mode:
authorAnton Bobov <anton@bobov.name>2023-10-25 19:17:11 +0500
committerAnton Bobov <anton@bobov.name>2023-10-27 14:26:55 +0500
commit62c95ef2f3a2374ddda52302d54801cfe442484d (patch)
tree8b74bb0bee41cf62bc9149429dac7b0f81123919 /files/.config
parent748cafebaf85b9827c8d3df4535a1a34ddbe82fd (diff)
[nnn] Add getplugs plugin and update all plugins
Diffstat (limited to 'files/.config')
-rwxr-xr-xfiles/.config/nnn/plugins/.cbcp51
-rwxr-xr-xfiles/.config/nnn/plugins/.iconlookup441
-rwxr-xr-xfiles/.config/nnn/plugins/.nmv174
-rwxr-xr-xfiles/.config/nnn/plugins/.ntfy22
-rwxr-xr-xfiles/.config/nnn/plugins/boom50
-rwxr-xr-xfiles/.config/nnn/plugins/bulknew32
-rwxr-xr-xfiles/.config/nnn/plugins/cdpath56
-rwxr-xr-xfiles/.config/nnn/plugins/chksum75
-rwxr-xr-xfiles/.config/nnn/plugins/cmusq80
-rwxr-xr-xfiles/.config/nnn/plugins/diffs62
-rwxr-xr-xfiles/.config/nnn/plugins/dragdrop77
-rwxr-xr-xfiles/.config/nnn/plugins/dups70
-rwxr-xr-xfiles/.config/nnn/plugins/finder89
-rwxr-xr-xfiles/.config/nnn/plugins/fixname75
-rwxr-xr-xfiles/.config/nnn/plugins/fzcd89
-rwxr-xr-xfiles/.config/nnn/plugins/fzhist40
-rwxr-xr-xfiles/.config/nnn/plugins/fzplug59
-rwxr-xr-xfiles/.config/nnn/plugins/getplugs70
-rwxr-xr-xfiles/.config/nnn/plugins/gitroot15
-rwxr-xr-xfiles/.config/nnn/plugins/gpgd28
-rwxr-xr-xfiles/.config/nnn/plugins/gpge45
-rwxr-xr-xfiles/.config/nnn/plugins/gsconnect21
-rwxr-xr-xfiles/.config/nnn/plugins/gutenread49
-rwxr-xr-xfiles/.config/nnn/plugins/imgresize31
-rwxr-xr-xfiles/.config/nnn/plugins/imgur597
-rwxr-xr-xfiles/.config/nnn/plugins/imgview113
-rwxr-xr-xfiles/.config/nnn/plugins/ipinfo13
-rwxr-xr-xfiles/.config/nnn/plugins/kdeconnect66
-rwxr-xr-xfiles/.config/nnn/plugins/launch42
-rwxr-xr-xfiles/.config/nnn/plugins/mimelist15
-rwxr-xr-xfiles/.config/nnn/plugins/moclyrics40
-rwxr-xr-xfiles/.config/nnn/plugins/mocq89
-rwxr-xr-xfiles/.config/nnn/plugins/mp3conv41
-rwxr-xr-xfiles/.config/nnn/plugins/mtpmount76
-rwxr-xr-xfiles/.config/nnn/plugins/nbak75
-rwxr-xr-xfiles/.config/nnn/plugins/nmount88
-rwxr-xr-xfiles/.config/nnn/plugins/nuke555
-rwxr-xr-xfiles/.config/nnn/plugins/oldbigfile16
-rwxr-xr-xfiles/.config/nnn/plugins/openall49
-rwxr-xr-xfiles/.config/nnn/plugins/organize62
-rwxr-xr-xfiles/.config/nnn/plugins/pdfread30
-rwxr-xr-xfiles/.config/nnn/plugins/preview-tabbed216
-rwxr-xr-xfiles/.config/nnn/plugins/pskill35
-rwxr-xr-xfiles/.config/nnn/plugins/renamer45
-rwxr-xr-xfiles/.config/nnn/plugins/ringtone36
-rwxr-xr-xfiles/.config/nnn/plugins/rsynccp26
-rwxr-xr-xfiles/.config/nnn/plugins/splitjoin52
-rwxr-xr-xfiles/.config/nnn/plugins/suedit16
-rwxr-xr-xfiles/.config/nnn/plugins/togglex21
-rwxr-xr-xfiles/.config/nnn/plugins/umounttree52
-rwxr-xr-xfiles/.config/nnn/plugins/upload45
-rwxr-xr-xfiles/.config/nnn/plugins/wallpaper37
-rwxr-xr-xfiles/.config/nnn/plugins/x2sel62
-rwxr-xr-xfiles/.config/nnn/plugins/xdgdefault53
54 files changed, 4464 insertions, 0 deletions
diff --git a/files/.config/nnn/plugins/.cbcp b/files/.config/nnn/plugins/.cbcp
new file mode 100755
index 0000000..d2ac944
--- /dev/null
+++ b/files/.config/nnn/plugins/.cbcp
@@ -0,0 +1,51 @@
+#!/usr/bin/env sh
+
+# Description: Copy selection to system clipboard as newline-separated entries
+# Dependencies:
+# - tr
+# - xclip/xsel (Linux)
+# - pbcopy (macOS)
+# - termux-clipboard-set (Termux)
+# - clip.exe (WSL)
+# - clip (Cygwin)
+# - wl-copy (Wayland)
+# - clipboard (Haiku)
+#
+# Limitation: breaks if a filename has newline in it
+#
+# Note: For a space-separated list:
+# xargs -0 < "$SELECTION"
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+IFS="$(printf '%b_' '\n')"; IFS="${IFS%_}" # protect trailing \n
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+[ -s "$selection" ] || { echo "plugin .cbcp error: empty selection" >&2 ; exit 1; }
+
+if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
+ # Wayland
+ tr '\0' '\n' < "$selection" | wl-copy
+elif type xsel >/dev/null 2>&1; then
+ # Linux
+ tr '\0' '\n' < "$selection" | xsel -bi
+elif type xclip >/dev/null 2>&1; then
+ # Linux
+ tr '\0' '\n' < "$selection" | xclip -sel clip
+elif type pbcopy >/dev/null 2>&1; then
+ # macOS
+ tr '\0' '\n' < "$selection" | pbcopy
+elif type termux-clipboard-set >/dev/null 2>&1; then
+ # Termux
+ tr '\0' '\n' < "$selection" | termux-clipboard-set
+elif type clip.exe >/dev/null 2>&1; then
+ # WSL
+ tr '\0' '\n' < "$selection" | clip.exe
+elif type clip >/dev/null 2>&1; then
+ # Cygwin
+ tr '\0' '\n' < "$selection" | clip
+elif type clipboard >/dev/null 2>&1; then
+ # Haiku
+ tr '\0' '\n' < "$selection" | clipboard --stdin
+fi
diff --git a/files/.config/nnn/plugins/.iconlookup b/files/.config/nnn/plugins/.iconlookup
new file mode 100755
index 0000000..49b4764
--- /dev/null
+++ b/files/.config/nnn/plugins/.iconlookup
@@ -0,0 +1,441 @@
+#!/usr/bin/env sh
+
+# Description: Print icons in front of list of directories/files
+
+# Dependencies: awk
+
+# Usage
+# 1. Set colors and/or icons to your liking
+# 2. Pipe any directory listing to iconlookup and it will output prepended icons
+# 3. preview-tui uses the script to prepend icon to directory listings
+# 4. Aditionally you can consider adding it to your PATH and/or FZF_DEFAULT_COMMAND to
+# make it work with various fzf plugins (make sure you also add --ansi to your FZF_DEFAULT_OPTS)
+
+# Shell: POSIX compliant
+
+# Author: Luuk van Baal (https://github.com/luukvbaal/iconlookup)
+
+icon_lookup() {
+awk 'BEGIN {
+# Set your ANSI colorscheme below (https://en.wikipedia.org/wiki/ANSI_escape_code#Colors).
+# Default uses standard nnn icon colors, 8 and 24-bit nord themes are commented out.
+ colordepth=8 #colordepth=8 #colordepth=24
+ color_dirtxt=39 #color_dirtxt=111 #color_dirtxt="129;161;193"
+ color_filetxt=15 #color_filetxt=111 #color_filetxt="129;161;193"
+ color_default=39 #color_default=111 #color_default="129;161;193"
+ color_video=93 #color_video=110 #color_video="136;192;208"
+ color_audio=220 #color_audio=150 #color_audio="163;190;140"
+ color_image=82 #color_image=150 #color_image="163;190;140"
+ color_docs=202 #color_docs=173 #color_docs="208;135;112"
+ color_archive=209 #color_archive=179 #color_archive="235;203;139"
+ color_c=81 #color_c=150 #color_c="163;190;140"
+ color_elixir=104 #color_elixir=109 #color_elixir="143;188;187"
+ color_java=32 #color_java=139 #color_java="180;142;173"
+ color_js=47 #color_js=109 #color_js="143;188;187"
+ color_react=39 #color_react=111 #color_react="129;161;193"
+ color_css=199 #color_css=110 #color_css="136;192;208"
+ color_python=227 #color_python=68 #color_python="94;129;172"
+ color_lua=19 #color_lua=167 #color_lua="191;97;106"
+ color_document=15 #color_document=173 #color_document="208;135;112"
+ color_fsharp=31 #color_fsharp=179 #color_fsharp="180;142;173"
+ color_ruby=160 #color_ruby=150 #color_ruby="163;190;140"
+ color_scala=196 #color_scala=139 #color_scala="143;188;187"
+ color_shell=47 #color_shell=109 #color_shell="143;188;187"
+ color_vim=28 #color_vim=109 #color_vim="143;188;187"
+
+# icons[][1] contains icon and icons[][2] contains color
+ icons["directory"][1] = ""; icons["directory"][2] = color_default
+ icons["file"][1] = "󰈔"; icons["file"][2] = color_default
+ icons["exec"][1] = ""; icons["exec"][2] = color_default
+ icons["manual"][1] = "󱓷"; icons["manual"][2] = color_docs
+ icons["pipe"][1] = "󰟥"; icons["pipe"][2] = color_default
+ icons["socket"][1] = "󰟩"; icons["socket"][2] = color_default
+ icons["door"][1] = "➡"; icons["door"][2] = color_default
+
+# top level and common icons
+ icons[".git"][1] = ""; icons[".git"][2] = color_default
+ icons["desktop"][1] = "󰟀"; icons["desktop"][2] = color_default
+ icons["briefcase"][1] = "󰃖"; icons["briefcase"][2] = color_default
+ icons["document"][1] = "󰃖"; icons["document"][2] = color_default
+ icons["downloads"][1] = "󰃘"; icons["downloads"][2] = color_default
+ icons["music"][1] = "󱍙"; icons["music"][2] = color_default
+ icons["musicfile"][1] = "󰎈"; icons["musicfile"][2] = color_audio
+ icons["pictures"][1] = "󰉔"; icons["pictures"][2] = color_default
+ icons["picturefile"][1] = "󰈟"; icons["picturefile"][2] = color_image
+ icons["public"][1] = ""; icons["public"][2] = color_default
+ icons["templates"][1] = "󰗇"; icons["templates"][2] = color_default
+ icons["videos"][1] = "󰈰"; icons["videos"][2] = color_default
+ icons["videofile"][1] = "󰈫"; icons["videofile"][2] = color_video
+ icons["changelog"][1] = "󰋚"; icons["changelog"][2] = color_docs
+ icons["configure"][1] = ""; icons["configure"][2] = color_default
+ icons["license"][1] = "󰈙"; icons["license"][2] = color_docs
+ icons["makefile"][1] = "󰆍"; icons["makefile"][2] = color_default
+ icons["archive"][1] = "󰀼"; icons["archive"][2] = color_archive
+ icons["rust"][1] = ""; icons["rust"][2] = color_default
+ icons["script"][1] = ""; icons["script"][2] = color_shell
+ icons["subtitle"][1] = "󰅺"; icons["subtitle"][2] = color_default
+ icons["cplusplus"][1] = ""; icons["cplusplus"][2] = color_c
+ icons["java"][1] = ""; icons["java"][2] = color_java
+ icons["clojure"][1] = ""; icons["clojure"][2] = color_default
+ icons["js"][1] = "󰌞"; icons["js"][2] = color_js
+ icons["linux"][1] = "󰌽"; icons["linux"][2] = color_default
+ icons["elixir"][1] = ""; icons["elixir"][2] = color_fsharp
+ icons["fsharp"][1] = ""; icons["fsharp"][2] = color_fsharp
+ icons["ruby"][1] = ""; icons["ruby"][2] = color_ruby
+ icons["c"][1] = ""; icons["c"][2] = color_c
+ icons["chess"][1] = "󰄺"; icons["chess"][2] = color_default
+ icons["haskell"][1] = ""; icons["haskell"][2] = color_vim
+ icons["font"][1] = ""; icons["font"][2] = color_default
+ icons["html"][1] = "󰌝"; icons["html"][2] = color_default
+ icons["react"][1] = ""; icons["react"][2] = color_react
+ icons["python"][1] = ""; icons["python"][2] = color_python
+ icons["database"][1] = "󰆼"; icons["database"][2] = color_default
+ icons["worddoc"][1] = "󰈬"; icons["worddoc"][2] = color_document
+ icons["playlist"][1] = "󱍙"; icons["playlist"][2] = color_audio
+ icons["opticaldisk"][1] = ""; icons["opticaldisk"][2] = color_archive
+
+# numbers
+ icons["1"][1] = icons["manual"][1]; icons["1"][2] = icons["manual"][2]
+ icons["7z"][1] = icons["archive"][1]; icons["7z"][2] = icons["archive"][2]
+
+# a
+ icons["a"][1] = icons["manual"][1]; icons["a"][2] = icons["manual"][2]
+ icons["apk"][1] = icons["archive"][1]; icons["apk"][2] = icons["archive"][2]
+ icons["asm"][1] = icons["file"][1]; icons["asm"][2] = icons["file"][2]
+ icons["aup"][1] = icons["musicfile"][1]; icons["aup"][2] = icons["musicfile"][2]
+ icons["avi"][1] = icons["videofile"][1]; icons["avi"][2] = icons["videofile"][2]
+
+# b
+ icons["bat"][1] = icons["script"][1]; icons["bat"][2] = icons["script"][2]
+ icons["bin"][1] = ""; icons["bin"][2] = color_default
+ icons["bmp"][1] = icons["picturefile"][1]; icons["bmp"][2] = icons["picturefile"][2]
+ icons["bz2"][1] = icons["archive"][1]; icons["bz2"][2] = icons["archive"][2]
+
+# c
+ icons["cplusplus"][1] = icons["cplusplus"][1]; icons["cplusplus"][2] = icons["cplusplus"][2]
+ icons["cabal"][1] = icons["haskell"][1]; icons["cab"][2] = icons["haskell"][2]
+ icons["cab"][1] = icons["archive"][1]; icons["cab"][2] = icons["archive"][2]
+ icons["cbr"][1] = icons["archive"][1]; icons["cbr"][2] = icons["archive"][2]
+ icons["cbz"][1] = icons["archive"][1]; icons["cbz"][2] = icons["archive"][2]
+ icons["cc"][1] = icons["cplusplus"][1]; icons["cc"][2] = icons["cplusplus"][2]
+ icons["class"][1] = icons["java"][1]; icons["class"][2] = icons["java"][2]
+ icons["clj"][1] = icons["clojure"][1]; icons["clj"][2] = icons["clojure"][2]
+ icons["cljc"][1] = icons["clojure"][1]; icons["cljc"][2] = icons["clojure"][2]
+ icons["cljs"][1] = icons["clojure"][1]; icons["cljs"][2] = icons["clojure"][2]
+ icons["cmake"][1] = icons["makefile"][1]; icons["cmake"][2] = icons["makefile"][2]
+ icons["coffee"][1] = ""; icons["coffee"][2] = color_default
+ icons["conf"][1] = icons["configure"][1]; icons["conf"][2] = icons["configure"][2]
+ icons["cpio"][1] = icons["archive"][1]; icons["cpio"][2] = icons["archive"][2]
+ icons["cpp"][1] = icons["cplusplus"][1]; icons["cpp"][2] = icons["cplusplus"][2]
+ icons["css"][1] = ""; icons["css"][2] = color_css
+ icons["cue"][1] = icons["playlist"][1]; icons["cue"][2] = icons["playlist"][2]
+ icons["cvs"][1] = icons["configure"][1]; icons["cvs"][2] = icons["configure"][2]
+ icons["cxx"][1] = icons["cplusplus"][1]; icons["cxx"][2] = icons["cplusplus"][2]
+
+# d
+ icons["db"][1] = icons["database"][1]; icons["db"][2] = icons["database"][2]
+ icons["deb"][1] = ""; icons["deb"][2] = color_archive
+ icons["diff"][1] = ""; icons["diff"][2] = color_default
+ icons["dll"][1] = icons["script"][1]; icons["dll"][2] = icons["script"][2]
+ icons["doc"][1] = icons["worddoc"][1]; icons["doc"][2] = icons["worddoc"][2]
+ icons["docx"][1] = icons["worddoc"][1]; icons["docx"][2] = icons["worddoc"][2]
+
+# e
+ icons["ejs"][1] = icons["js"][1]; icons["ejs"][2] = icons["js"][2]
+ icons["elf"][1] = icons["linux"][1]; icons["elf"][2] = icons["linux"][2]
+ icons["epub"][1] = icons["manual"][1]; icons["epub"][2] = icons["manual"][2]
+ icons["exe"][1] = icons["exec"][1]; icons["exe"][2] = icons["exec"][2]
+ icons["ex"][1] = icons["elixir"][1]; icons["ex"][2] = icons["elixir"][2]
+ icons["eex"][1] = icons["elixir"][1]; icons["eex"][2] = icons["elixir"][2]
+ icons["exs"][1] = icons["elixir"][1]; icons["exs"][2] = icons["elixir"][2]
+
+# f
+ icons["fsharp"][1] = icons["fsharp"][1]; icons["fsharp"][2] = icons["fsharp"][2]
+ icons["flac"][1] = icons["musicfile"][1]; icons["flac"][2] = icons["musicfile"][2]
+ icons["fen"][1] = icons["chess"][1]; icons["fen"][2] = icons["chess"][2]
+ icons["flv"][1] = icons["videofile"][1]; icons["flv"][2] = icons["videofile"][2]
+ icons["fs"][1] = icons["fsharp"][1]; icons["fs"][2] = icons["fsharp"][2]
+ icons["fsi"][1] = icons["fsharp"][1]; icons["fsi"][2] = icons["fsharp"][2]
+ icons["fsscript"][1] = icons["fsharp"][1]; icons["fsscript"][2] = icons["fsharp"][2]
+ icons["fsx"][1] = icons["fsharp"][1]; icons["fsx"][2] = icons["fsharp"][2]
+
+# g
+ icons["gem"][1] = icons["ruby"][1]; icons["gem"][2] = icons["ruby"][2]
+ icons["gif"][1] = icons["picturefile"][1]; icons["gif"][2] = icons["picturefile"][2]
+ icons["go"][1] = "󰟓"; icons["go"][2] = color_default
+ icons["gz"][1] = icons["archive"][1]; icons["gz"][2] = icons["archive"][2]
+ icons["gzip"][1] = icons["archive"][1]; icons["gzip"][2] = icons["archive"][2]
+
+# h
+ icons["h"][1] = icons["c"][1]; icons["h"][2] = icons["c"][2]
+ icons["hh"][1] = icons["cplusplus"][1]; icons["hh"][2] = icons["cplusplus"][2]
+ icons["hpp"][1] = icons["cplusplus"][1]; icons["hpp"][2] = icons["cplusplus"][2]
+ icons["hs"][1] = icons["haskell"][1]; icons["hs"][2] = icons["haskell"][2]
+ icons["htaccess"][1] = icons["configure"][1]; icons["htaccess"][2] = icons["configure"][2]
+ icons["htpasswd"][1] = icons["configure"][1]; icons["htpasswd"][2] = icons["configure"][2]
+ icons["htm"][1] = icons["html"][1]; icons["htm"][2] = icons["html"][2]
+ icons["hxx"][1] = icons["cplusplus"][1]; icons["hxx"][2] = icons["cplusplus"][2]
+ icons["heex"][1] = icons["elixir"][1]; icons["heex"][2] = icons["elixir"][2]
+
+# i
+ icons["ico"][1] = icons["picturefile"][1]; icons["ico"][2] = icons["picturefile"][2]
+ icons["img"][1] = icons["opticaldisk"][1]; icons["img"][2] = icons["opticaldisk"][2]
+ icons["ini"][1] = icons["configure"][1]; icons["ini"][2] = icons["configure"][2]
+ icons["iso"][1] = icons["opticaldisk"][1]; icons["iso"][2] = icons["opticaldisk"][2]
+ icons["isub"][1] = icons["subtitle"][1]; icons["isub"][2] = icons["subtitle"][2]
+
+# j
+ icons["jar"][1] = icons["java"][1]; icons["jar"][2] = icons["java"][2]
+ icons["java"][1] = icons["java"][1]; icons["java"][2] = icons["java"][2]
+ icons["jl"][1] = icons["configure"][1]; icons["jl"][2] = icons["configure"][2]
+ icons["jpeg"][1] = icons["picturefile"][1]; icons["jpeg"][2] = icons["picturefile"][2]
+ icons["jpg"][1] = icons["picturefile"][1]; icons["jpg"][2] = icons["picturefile"][2]
+ icons["json"][1] = ""; icons["json"][2] = color_js
+ icons["jsx"][1] = icons["react"][1]; icons["jsx"][2] = icons["react"][2]
+ icons["jxl"][1] = icons["picturefile"][1]; icons["jxl"][2] = icons["picturefile"][2]
+
+# k
+ icons["ksh"][1] = icons["font"][1]; icons["ksf"][2] = icons["font"][2]
+
+# l
+ icons["lha"][1] = icons["archive"][1]; icons["lha"][2] = icons["archive"][2]
+ icons["lhs"][1] = icons["haskell"][1]; icons["lhs"][2] = icons["haskell"][2]
+ icons["ilog"][1] = icons["document"][1]; icons["ilog"][2] = icons["document"][2]
+ icons["lua"][1] = ""; icons["lua"][2] = color_lua
+ icons["lzh"][1] = icons["archive"][1]; icons["lzh"][2] = icons["archive"][2]
+ icons["lzma"][1] = icons["archive"][1]; icons["lzma"][2] = icons["archive"][2]
+
+# m
+ icons["m"][1] = "󰠞"; icons["mat"][2] = color_c
+ icons["m4a"][1] = icons["musicfile"][1]; icons["m4a"][2] = icons["musicfile"][2]
+ icons["m4v"][1] = icons["videofile"][1]; icons["m4v"][2] = icons["videofile"][2]
+ icons["mat"][1] = ""; icons["mat"][2] = color_c
+ icons["markdown"][1] = ""; icons["markdown"][2] = color_docs
+ icons["md"][1] = ""; icons["md"][2] = color_docs
+ icons["mk"][1] = icons["makefile"][1]; icons["mk"][2] = icons["makefile"][2]
+ icons["mkv"][1] = icons["videofile"][1]; icons["mkv"][2] = icons["videofile"][2]
+ icons["mov"][1] = icons["videofile"][1]; icons["mov"][2] = icons["videofile"][2]
+ icons["mp3"][1] = icons["musicfile"][1]; icons["mp3"][2] = icons["musicfile"][2]
+ icons["mp4"][1] = icons["videofile"][1]; icons["mp4"][2] = icons["videofile"][2]
+ icons["mpeg"][1] = icons["videofile"][1]; icons["mpeg"][2] = icons["videofile"][2]
+ icons["mpg"][1] = icons["videofile"][1]; icons["mpg"][2] = icons["videofile"][2]
+ icons["msi"][1] = "󰍲"; icons["msi"][2] = color_default
+
+# n
+ icons["nix"][1] = ""; icons["nix"][2] = color_fsharp
+
+# o
+ icons["o"][1] = icons["manual"][1]; icons["o"][2] = icons["manual"][2]
+ icons["ogg"][1] = icons["musicfile"][1]; icons["ogg"][2] = icons["musicfile"][2]
+ icons["odownload"][1] = icons["download"][1]; icons["odownload"][2] = icons["download"][2]
+ icons["otf"][1] = icons["font"][1]; icons["otf"][2] = icons["font"][2]
+ icons["out"][1] = icons["linux"][1]; icons["out"][2] = icons["linux"][2]
+
+# p
+ icons["part"][1] = icons["download"][1]; icons["part"][2] = icons["download"][2]
+ icons["patch"][1] = icons["diff"][1]; icons["patch"][2] = icons["diff"][2]
+ icons["pdf"][1] = "󰈦"; icons["pdf"][2] = color_docs
+ icons["pgn"][1] = icons["chess"][1]; icons["pgn"][2] = icons["chess"][2]
+ icons["php"][1] = ""; icons["php"][2] = color_default
+ icons["png"][1] = icons["picturefile"][1]; icons["png"][2] = icons["picturefile"][2]
+ icons["ppt"][1] = "󰈧"; icons["ppt"][2] = color_default
+ icons["pptx"][1] = "󰈧"; icons["pptx"][2] = color_default
+ icons["psb"][1] = ""; icons["psb"][2] = color_default
+ icons["psd"][1] = ""; icons["psd"][2] = color_default
+ icons["py"][1] = icons["python"][1]; icons["py"][2] = icons["python"][2]
+ icons["pyc"][1] = icons["python"][1]; icons["pyc"][2] = icons["python"][2]
+ icons["pyd"][1] = icons["python"][1]; icons["pyd"][2] = icons["python"][2]
+ icons["pyo"][1] = icons["python"][1]; icons["pyo"][2] = icons["python"][2]
+
+# q
+
+# r
+ icons["rar"][1] = icons["archive"][1]; icons["rar"][2] = icons["archive"][2]
+ icons["rc"][1] = icons["configure"][1]; icons["rc"][2] = icons["configure"][2]
+ icons["rom"][1] = "󰊖"; icons["rom"][2] = color_default
+ icons["rpm"][1] = icons["archive"][1]; icons["rpm"][2] = icons["archive"][2]
+ icons["rss"][1] = ""; icons["rss"][2] = color_default
+ icons["rtf"][1] = "󰈦"; icons["rtf"][2] = color_default
+
+# s
+ icons["sass"][1] = ""; icons["sass"][2] = color_css
+ icons["scss"][1] = ""; icons["scss"][2] = color_css
+ icons["so"][1] = icons["manual"][1]; icons["so"][2] = icons["manual"][2]
+ icons["scala"][1] = ""; icons["scala"][2] = color_scala
+ icons["sh"][1] = icons["script"][1]; icons["sh"][2] = icons["script"][2]
+ icons["slim"][1] = icons["script"][1]; icons["slim"][2] = icons["script"][2]
+ icons["sln"][1] = ""; icons["sln"][2] = color_default
+ icons["sql"][1] = icons["database"][1]; icons["sql"][2] = icons["database"][2]
+ icons["srt"][1] = icons["subtitle"][1]; icons["srt"][2] = icons["subtitle"][2]
+ icons["svg"][1] = icons["picturefile"][1]; icons["svg"][2] = icons["picturefile"][2]
+
+# t
+ icons["tar"][1] = icons["archive"][1]; icons["tar"][2] = icons["archive"][2]
+ icons["tex"][1] = "󰙩"; icons["tex"][2] = color_default
+ icons["tgz"][1] = icons["archive"][1]; icons["tgz"][2] = icons["archive"][2]
+ icons["ts"][1] = ""; icons["ts"][2] = color_js
+ icons["tsx"][1] = icons["react"][1]; icons["tsx"][2] = icons["react"][2]
+ icons["txt"][1] = icons["document"][1]; icons["txt"][2] = icons["document"][2]
+ icons["txz"][1] = icons["archive"][1]; icons["txz"][2] = icons["archive"][2]
+ icons["ttf"][1] = icons["font"][1]; icons["ttf"][2] = icons["font"][2]
+
+# u
+
+# v
+ icons["vid"][1] = icons["videofile"][1]; icons["vid"][2] = icons["videofile"][2]
+ icons["vim"][1] = ""; icons["vim"][2] = color_vim
+ icons["vimrc"][1] = ""; icons["vimrc"][2] = color_vim
+ icons["vtt"][1] = icons["subtitle"][1]; icons["vtt"][2] = icons["subtitle"][2]
+# w
+ icons["wav"][1] = icons["musicfile"][1]; icons["wav"][2] = icons["musicfile"][2]
+ icons["webm"][1] = icons["videofile"][1]; icons["webm"][2] = icons["videofile"][2]
+ icons["wma"][1] = icons["videofile"][1]; icons["wma"][2] = icons["videofile"][2]
+ icons["wmv"][1] = icons["videofile"][1]; icons["wmv"][2] = icons["videofile"][2]
+
+# x
+ icons["xbps"][1] = icons["archive"][1]; icons["xbps"][2] = color_archive
+ icons["xcf"][1] = icons["picturefile"][1]; icons["xcf"][2] = color_image
+ icons["xhtml"][1] = icons["html"][1]; icons["xhtml"][2] = icons["html"][2]
+ icons["xls"][1] = "󰈛"; icons["xls"][2] = color_default
+ icons["xlsx"][1] = "󰈛"; icons["xlsx"][2] = color_default
+ icons["xml"][1] = icons["html"][1]; icons["xml"][2] = icons["html"][2]
+ icons["xz"][1] = icons["archive"][1]; icons["xz"][2] = icons["archive"][2]
+
+# y
+ icons["yaml"][1] = icons["configure"][1]; icons["yaml"][2] = icons["configure"][2]
+ icons["yml"][1] = icons["configure"][1]; icons["yml"][2] = icons["configure"][2]
+# z
+ icons["zip"][1] = icons["archive"][1]; icons["zip"][2] = icons["archive"][2]
+ icons["zsh"][1] = icons["script"][1]; icons["zsh"][2] = icons["script"][2]
+ icons["zst"][1] = icons["archive"][1]; icons["zst"][2] = icons["archive"][2]
+
+ FS = "."
+ limit = ENVIRON["limit"]
+ switch (colordepth) {
+ case "4":
+ escape="\033["
+ break;
+ case "8":
+ escape="\033[38;5;"
+ break;
+ case "24":
+ escape="\033[38;2;"
+ break;
+ }
+ bstr = ENVIRON["beforestr"]
+}
+{
+ # dont print cwd . and leading ./ from tree -f
+ if ($0 ~/^\.$/)
+ next
+ ent = ($0 ~/^\.\//) ? substr($0, 3, length($0) - 2) : $0
+ ext = $NF
+
+ # Print icons, set color and bold directories by using ansi escape codes
+ if (ext in icons)
+ printcolor(icons[ext][1], icons[ext][2], color_filetxt, ent, "10")
+ else
+ switch (substr(ent, length(ent), 1)) {
+ case "/":
+ printcolor(icons["directory"][1], color_default, color_dirtxt, ent, "1")
+ break;
+ case "*":
+ printcolor(icons["exe"][1], color_default, color_filetxt, ent, "10")
+ break;
+ case "|":
+ printcolor(icons["pipe"][1], color_default, color_filetxt, ent, "10")
+ break;
+ case "=":
+ printcolor(icons["socket"][1], color_default, color_filetxt, ent, "10")
+ break;
+ case ">":
+ printcolor(icons["door"][1], color_default, color_filetxt, ent, "10")
+ break;
+ default:
+ printcolor(icons["file"][1], color_default, color_filetxt, ent, "10")
+ }
+}
+function printcolor(i, c, d, n, b) {
+ if (limit != "" && length(n) + 2 > limit)
+ n = substr(n, 1, limit - 2)
+ printf "\033[0m"
+ printf "%s%s%s;%sm%s %s%sm%s\n", bstr, escape, c, b, i, escape, d, n
+}'
+printf '\033[0m'
+}
+
+print_begin() {
+ printf '%s\n' "$1" | sed 's/\\n/\n/g'
+}
+
+print_end() {
+ printf '%s\n' "$1" | sed 's/\\n/\n/g'
+}
+
+print_help() {
+ printf 'Icon Lookup\n
+Usage:
+ iconlookup [options]
+ iconlookup [-bBe] [string]
+ iconlookup -l [number]
+ iconlookup (-h | --help)
+
+ Prepend icons to list of files based on extension or appended indicator by ls/tree "-F" flag ("/" for directory, "*" for executable etc.)
+
+Options:
+ -h --help -? Show this screen.
+ -b --before Prepend str before icon.
+ -B --begin Prepend str before output.
+ -e --end Append str after output.
+ -l --limit Limit line length to [number] characters.'
+}
+
+while :; do
+ case $1 in
+ -h|-\?|--help)
+ print_help
+ exit ;;
+ -B|--begin)
+ if [ -n "$2" ]; then
+ print_begin "$2"
+ fi
+ shift ;;
+ -e|--end)
+ if [ -n "$2" ]; then
+ end=1
+ endstr="$2"
+ fi
+ shift ;;
+ -b|--before)
+ if [ -n "$2" ]; then
+ export beforestr="$2"
+ fi
+ shift ;;
+ -l|--limit)
+ if [ -n "$2" ]; then
+ export limit="$2"
+ shift
+ else
+ printf 'ERROR: "--limit" requires a non-empty option argument.\n'
+ exit
+ fi ;;
+ --)
+ shift
+ break ;;
+ -?*)
+ printf 'WARNING: Unknown option ignored: %s\n' "$1" ;;
+ *) break ;;
+ esac
+ shift
+done
+
+if [ ! -t 0 ]; then
+ [ -n "$beforestr" ] && limit="$((limit - ${#beforestr}))"
+ icon_lookup
+else
+ printf 'ERROR: no data provided...\nExpecting a directory listing in stdin\n'
+fi
+
+if [ -n "$end" ]; then
+ print_end "$endstr"
+fi
diff --git a/files/.config/nnn/plugins/.nmv b/files/.config/nnn/plugins/.nmv
new file mode 100755
index 0000000..eaebda6
--- /dev/null
+++ b/files/.config/nnn/plugins/.nmv
@@ -0,0 +1,174 @@
+#!/usr/bin/env bash
+
+# Description: An almost fully POSIX compliant batch file renamer
+#
+# Note: nnn auto-detects and invokes this plugin if available
+# Whitespace is used as delimiter for read.
+# The plugin doesn't support filenames with leading or trailing whitespace
+# To use NNN_LIST your shell must support readlink(1)
+#
+# Capabilities:
+# 1. Basic file rename
+# 2. Detects order change
+# 3. Can move files
+# 4. Can remove files
+# 5. Switch number pairs to swap filenames
+#
+# Shell: bash
+# Author: KlzXS
+
+# shellcheck disable=SC1090,SC1091
+. "$(dirname "$0")"/.nnn-plugin-helper
+
+EDITOR="${EDITOR:-vi}"
+TMPDIR="${TMPDIR:-/tmp}"
+NNN_INCLUDE_HIDDEN="${NNN_INCLUDE_HIDDEN:-0}"
+VERBOSE="${VERBOSE:-0}"
+RECURSIVE="${RECURSIVE:-0}"
+
+case "$NNN_TRASH" in
+ 1)
+ RM_UTIL="trash-put" ;;
+ 2)
+ RM_UTIL="gio trash" ;;
+ *)
+ RM_UTIL="rm -ri" ;;
+esac
+
+exit_status=0
+
+if nnn_use_selection "Rename"; then
+ # shellcheck disable=SC2154
+ arr=$(tr '\0' '\n' < "$selection")
+else
+ findcmd="find . ! -name ."
+
+ if [ "$RECURSIVE" -eq 0 ]; then
+ findcmd="$findcmd -prune"
+ fi
+
+ if [ "$NNN_INCLUDE_HIDDEN" -eq 0 ]; then
+ findcmd="$findcmd ! -name \".*\""
+ fi
+
+ if [ -z "$NNN_LIST" ]; then
+ findcmd="$findcmd -print"
+ else
+ findcmd="$findcmd -printf "'"'"$NNN_LIST/%P\n"'"'
+ fi
+
+ arr=$(eval "$findcmd" | sort)
+fi
+
+lines=$(printf "%s\n" "$arr" | wc -l)
+width=${#lines}
+
+dst_file=$(mktemp "$TMPDIR/.nnnXXXXXX")
+trap 'rm -f "$dst_file"' EXIT
+
+printf "%s" "$arr" | awk '{printf("%'"${width}"'d %s\n", NR, $0)}' > "$dst_file"
+
+items=("~")
+while IFS='' read -r line; do
+ if [ -n "$NNN_LIST" ]; then
+ line=$(readlink "$line" || printf "%s" "$line")
+ fi
+
+ items+=("$line");
+done < <(printf "%s\n" "$arr")
+
+$EDITOR "$dst_file"
+
+while read -r num name; do
+ if [ -z "$name" ]; then
+ if [ -z "$num" ]; then
+ continue
+ fi
+
+ printf "%s: unable to parse line, aborting\n" "$0"
+ exit 1
+ fi
+
+ # check if $num is an integer
+ if [ ! "$num" -eq "$num" ] 2> /dev/null; then
+ printf "%s: unable to parse line, aborting\n" "$0"
+ exit 1
+ fi
+
+ src=${items[$num]}
+
+ if [ -z "$src" ]; then
+ printf "%s: unknown item number %s\n" "$0" "$num" > /dev/stderr
+ continue
+ elif [ "$name" != "$src" ]; then
+ if [ -z "$name" ]; then
+ continue
+ fi
+
+ if [ ! -e "$src" ] && [ ! -L "$src" ]; then
+ printf "%s: %s does not exit\n" "$0" "$src" > /dev/stderr
+
+ unset "items[$num]"
+ continue
+ fi
+
+ # handle swaps
+ if [ -e "$name" ] || [ -L "$name" ]; then
+ tmp="$name~"
+ c=0
+
+ while [ -e "$tmp" ] || [ -L "$tmp" ]; do
+ c=$((c+1))
+ tmp="$tmp~$c"
+ done
+
+ if mv "$name" "$tmp"; then
+ if [ "$VERBOSE" -ne 0 ]; then
+ printf "'%s' -> '%s'\n" "$name" "$tmp"
+ fi
+ else
+ printf "%s: failed to rename %s to %s: %s\n" "$0" "$name" "$tmp" "$!" > /dev/stderr
+ exit_status=1
+ fi
+
+ for key in "${!items[@]}"; do
+ if [ "${items[$key]}" = "$name" ]; then
+ items[$key]="$tmp"
+ fi
+ done
+ fi
+
+ dir=$(dirname "$name")
+ if [ ! -d "$dir" ] && ! mkdir -p "$dir"; then
+ printf "%s: failed to create directory tree %s\n" "$0" "$dir" > /dev/stderr
+ exit_status=1
+ elif ! mv -i "$src" "$name"; then
+ printf "%s: failed to rename %s to %s: %s\n" "$0" "$name" "$tmp" "$!" > /dev/stderr
+ exit_status=1
+ else
+ if [ -d "$name" ]; then
+ for key in "${!items[@]}"; do
+ items[$key]=$(printf "%s" "${items[$key]}" | sed "s|^$src\(\$\|\/\)|$name\1|")
+ done
+
+ if [ "$VERBOSE" -ne 0 ]; then
+ printf "'%s' => '%s'\n" "$src" "$name"
+ fi
+ else
+ true
+ if [ "$VERBOSE" -ne 0 ]; then
+ printf "'%s' -> '%s'\n" "$src" "$name"
+ fi
+ fi
+ fi
+ fi
+
+ unset "items[$num]"
+done <"$dst_file"
+
+unset "items[0]"
+for item in "${items[@]}"; do
+ $RM_UTIL "$item"
+done
+
+exit $exit_status
diff --git a/files/.config/nnn/plugins/.ntfy b/files/.config/nnn/plugins/.ntfy
new file mode 100755
index 0000000..2a61478
--- /dev/null
+++ b/files/.config/nnn/plugins/.ntfy
@@ -0,0 +1,22 @@
+#!/usr/bin/env sh
+
+# Description: Show a notification
+#
+# Details: nnn invokes this plugin to show notification when a cp/mv/rm operation is complete.
+#
+# Dependencies: notify-send (Ubuntu)/ntfy (https://github.com/dschep/ntfy)/osascript (macOS)/notify (Haiku)
+#
+# Shell: POSIX compliant
+# Author: Anna Arad
+
+OS="$(uname)"
+
+if type notify-send >/dev/null 2>&1; then
+ notify-send nnn "Done!"
+elif [ "$OS" = "Darwin" ]; then
+ osascript -e 'display notification "Done!" with title "nnn"'
+elif type ntfy >/dev/null 2>&1; then
+ ntfy -t nnn send "Done!"
+elif [ "$OS" = "Haiku" ]; then
+ notify --title "nnn" "Done!"
+fi
diff --git a/files/.config/nnn/plugins/boom b/files/.config/nnn/plugins/boom
new file mode 100755
index 0000000..aab466f
--- /dev/null
+++ b/files/.config/nnn/plugins/boom
@@ -0,0 +1,50 @@
+#!/usr/bin/env sh
+
+# Description: Play random music (MP3, FLAC, M4A, WEBM, WMA) from current dir.
+#
+# Dependencies: mocp (or custom)
+#
+# Note: You may want to set GUIPLAYER.
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+GUIPLAYER="${GUIPLAYER:-""}"
+NUMTRACKS="${NUMTRACKS:-100}"
+
+if [ -n "$GUIPLAYER" ]; then
+ find . -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.m4a" -o -iname "*.webm" -o -iname "*.wma" \) | shuf -n "$NUMTRACKS" | xargs -d "\n" "$GUIPLAYER" > /dev/null 2>&1 &
+
+ # detach the player
+ sleep 1
+elif type mocp >/dev/null 2>&1; then
+ cmd=$(pgrep -x mocp 2>/dev/null)
+ ret=$cmd
+
+ if [ -z "$ret" ]; then
+ # start MOC server
+ mocp -S
+ mocp -o shuffle
+ else
+ # mocp running, check if it's playing
+ state=$(mocp -i | grep "State:" | cut -d' ' -f2)
+ if [ "$state" = 'PLAY' ]; then
+ # add up to 100 random audio files
+ find . -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.m4a" -o -iname "*.webm" -o -iname "*.wma" \) | head -n "$NUMTRACKS" | xargs -d "\n" mocp -a
+ exit
+ fi
+ fi
+
+ # clear MOC playlist
+ mocp -c
+ mocp -o shuffle
+
+ # add up to 100 random audio files
+ find . -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.m4a" -o -iname "*.webm" -o -iname "*.wma" \) | head -n "$NUMTRACKS" | xargs -d "\n" mocp -a
+
+ # start playing
+ mocp -p
+else
+ printf "moc missing"
+ read -r _
+fi
diff --git a/files/.config/nnn/plugins/bulknew b/files/.config/nnn/plugins/bulknew
new file mode 100755
index 0000000..64331e4
--- /dev/null
+++ b/files/.config/nnn/plugins/bulknew
@@ -0,0 +1,32 @@
+#!/usr/bin/env sh
+
+# Description: Allows for creation of multiple files/dirs simultaneously
+# Creates a tmp file to write each entry in a separate line
+#
+# Note: Only relative paths are supported. Absolute paths are ignored
+# Leading and trailing whitespace in path names is also ignored
+#
+# Shell: POSIX compliant
+# Author: KlzXS
+
+EDITOR="${EDITOR:-vi}"
+TMPDIR="${TMPDIR:-/tmp}"
+
+printf "'f'ile / 'd'ir? "
+read -r resp
+
+if [ "$resp" = "f" ]; then
+ #shellcheck disable=SC2016
+ cmd='mkdir -p "$(dirname "{}")" && touch "{}"'
+elif [ "$resp" = "d" ]; then
+ cmd='mkdir -p {}'
+else
+ exit 1
+fi
+
+tmpfile=$(mktemp "$TMPDIR/.nnnXXXXXX")
+$EDITOR "$tmpfile"
+
+sed "/^\//d" "$tmpfile" | xargs -n1 -I{} sh -c "$cmd"
+
+rm "$tmpfile"
diff --git a/files/.config/nnn/plugins/cdpath b/files/.config/nnn/plugins/cdpath
new file mode 100755
index 0000000..fbc0fb4
--- /dev/null
+++ b/files/.config/nnn/plugins/cdpath
@@ -0,0 +1,56 @@
+#!/usr/bin/env sh
+
+# Description: 'cd' to the directory from CDPATH
+#
+# Details: If the CDPATH environment variable is not set, the default value of
+# ${XDG_CONFIG_HOME:-$HOME/.config}/nnn/bookmarks will be used.
+# You can create this directory and fill it with symbolic links to your
+# favorite directories. It's a good idea to add it to CDPATH so that it
+# could also be used from the command line outside of nnn.
+# The fzf search is done on the directory basename (the first column).
+#
+# This plugin is an extended version of the bookmarks plugin.
+# If you set your CDPATH to ${XDG_CACHE_HOME:-$HOME/.cache}/nnn/bookmarks
+# or to the value of BOOKMARKS_DIR, you can use it as a bookmarks replacement.
+#
+# Shell: POSIX compliant
+# Author: Yuri Kloubakov
+
+# shellcheck disable=SC1090,SC1091
+. "$(dirname "$0")"/.nnn-plugin-helper
+
+# Get a list of (symbolic links to) directories for every element of CDPATH
+get_dirs() {
+ IFS=':'
+ for path in $CDPATH; do
+ for entry in "$path"/*; do
+ if [ -d "$entry" ]; then
+ name=$(basename "$entry" | grep -o '^.\{1,24\}')
+ if [ -h "$entry" ]; then
+ slink=$(ls -dl -- "$entry")
+ entry=${slink#*" $entry -> "}
+ fi
+ printf "%-24s :%s\n" "${name}" "$entry"
+ fi
+ done
+ done
+}
+
+abort() {
+ echo "$1"
+ read -r _
+ exit 1
+}
+
+if [ -z "$CDPATH" ]; then
+ CDPATH="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/bookmarks"
+ [ -d "$CDPATH" ] || abort "CDPATH is not set and there is no \"$CDPATH\" directory"
+fi
+
+dir_list=$(get_dirs)
+[ -n "$dir_list" ] || abort "There are no directories to choose from. Check your \"$CDPATH\"."
+
+dir=$(echo "$dir_list" | fzf --nth=1 --delimiter=':' | awk -F: 'END { print $2 }')
+if [ -n "$dir" ]; then
+ nnn_cd "$dir" 0
+fi
diff --git a/files/.config/nnn/plugins/chksum b/files/.config/nnn/plugins/chksum
new file mode 100755
index 0000000..9441cc1
--- /dev/null
+++ b/files/.config/nnn/plugins/chksum
@@ -0,0 +1,75 @@
+#!/usr/bin/env sh
+
+# Description: Create and verify checksums
+#
+# Note: On macOS, install the relevant checksum packages from Homebrew with:
+# brew install coreutils
+#
+# Details:
+# - selection: it will generate one file with the checksums and filenames
+# (and with paths if they are in another directory)
+# output checksum filename format: checksum_timestamp.checksum_type
+# - file: if the file is a checksum, the plugin does the verification
+# if the file is not a checksum, checksum will be generated for it
+# the output checksum filename will be filename.checksum_type
+# - directory: recursively calculates checksum for all the files in the dir
+# the output checksum filename will be directory.checksum_type
+#
+# Shell: POSIX compliant
+# Authors: ath3, Arun Prakash Jana
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+resp=f
+chsum=md5
+
+checksum_type()
+{
+ echo "possible checksums: md5, sha1, sha224, sha256, sha384, sha512"
+ printf "create md5 (m), sha256 (s), sha512 (S) (or type one of the above checksums) [default=m]: "
+ read -r chsum_resp
+ for chks in md5 sha1 sha224 sha256 sha384 sha512
+ do
+ if [ "$chsum_resp" = "$chks" ]; then
+ chsum=$chsum_resp
+ return
+ fi
+ done
+ if [ "$chsum_resp" = "s" ]; then
+ chsum=sha256
+ elif [ "$chsum_resp" = "S" ]; then
+ chsum=sha512
+ fi
+}
+
+if [ -s "$selection" ]; then
+ printf "work with selection (s) or current file (f) [default=f]: "
+ read -r resp
+fi
+
+if [ "$resp" = "s" ]; then
+ checksum_type
+ sed 's|'"$PWD/"'||g' < "$selection" | xargs -0 -I{} ${chsum}sum {} > "checksum_$(date '+%Y%m%d%H%M').$chsum"
+
+ # Clear selection
+ if [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+ fi
+elif [ -n "$1" ]; then
+ if [ -f "$1" ]; then
+ for chks in md5 sha1 sha224 sha256 sha384 sha512
+ do
+ if echo "$1" | grep -q \.${chks}$; then
+ ${chks}sum -c < "$1"
+ read -r _
+ exit
+ fi
+ done
+ checksum_type
+ file=$(basename "$1").$chsum
+ ${chsum}sum "$1" > "$file"
+ elif [ -d "$1" ]; then
+ checksum_type
+ file=$(basename "$1").$chsum
+ find "$1" -type f -exec ${chsum}sum "{}" + > "$file"
+ fi
+fi
diff --git a/files/.config/nnn/plugins/cmusq b/files/.config/nnn/plugins/cmusq
new file mode 100755
index 0000000..fbaa485
--- /dev/null
+++ b/files/.config/nnn/plugins/cmusq
@@ -0,0 +1,80 @@
+#!/usr/bin/env sh
+
+# Description: Add selection or hovered file/directory to cmus queue
+#
+# Dependencies: cmus, pgrep, xdotool (optional)
+#
+# Notes:
+# 1. If adding selection, files/dirs are added in the same order they were selected in nnn
+# 2. A new window will be opened if cmus is not running already, playback will start immediately
+# 3. If cmus is already running, files will be appended to the queue with no forced playback
+#
+# TODO:
+# 1. Add cava and cmus-lyrics as optional dependencies
+# 2. Start cava and/or cmus-lyrics in tmux or kitty panes next to cmus
+#
+# Shell: POSIX compliant
+# Author: Kabouik
+
+# (Optional) Set preferred terminal emulator for cmus if not set in your env,
+# or leave commented out to use OS default
+#TERMINAL="kitty"
+
+if ! type cmus >/dev/null; then
+ printf "cmus missing"
+ read -r _
+ exit 1
+fi
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+
+start_cmus() {
+ type xdotool >/dev/null && nnnwindow="$(xdotool getactivewindow)"
+ case "$TERMINAL" in
+ kitty | gnome-terminal | st)
+ nohup "$TERMINAL" -- cmus & ;;
+ havoc)
+ nohup "$TERMINAL" cmus & ;;
+ "")
+ nohup x-terminal-emulator -e cmus & ;;
+ *)
+ nohup "$TERMINAL" -e cmus & ;;
+ esac
+ # Give the new terminal some time to open
+ until cmus-remote -C; do sleep 0.1; done
+ [ -n "$nnnwindow" ] && xdotool windowactivate "$nnnwindow"
+} >/dev/null 2>&1
+
+fill_queue() {
+ if [ "$REPLY" = "s" ]; then
+ xargs < "$selection" -0 cmus-remote -q
+ elif [ -n "$1" ]; then
+ cmus-remote -q "$1"
+ fi
+}
+
+# If active selection,then ask what to do
+if [ -s "$selection" ]; then
+ printf "Queue [s]election or [c]urrently hovered? [default=c]: "
+ read -r REPLY
+fi
+
+# If cmus is not running, start and play queue
+if ! pgrep cmus >/dev/null; then
+ printf "cmus is not running, starting it in a new %s window.\n" "$TERMINAL"
+ start_cmus
+ fill_queue "$1"
+ cmus-remote -p
+ printf "Files added to cmus queue.\n"
+else # Append to existing queue if cmus is already running
+ fill_queue "$1"
+ printf "Files appended to current cmus queue.\n"
+fi
+
+# Change view
+cmus-remote -C "view 4"
+
+# Clear selection
+if [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+fi
diff --git a/files/.config/nnn/plugins/diffs b/files/.config/nnn/plugins/diffs
new file mode 100755
index 0000000..0464781
--- /dev/null
+++ b/files/.config/nnn/plugins/diffs
@@ -0,0 +1,62 @@
+#!/usr/bin/env sh
+
+# Description: Show diff of 2 directories or multiple files in vimdiff
+#
+# Notes:
+# 1. vim may show the warning: 'Vim: Warning: Input is not from a terminal'
+# press 'Enter' to ignore and proceed.
+# 2. if only one file is in selection, the hovered file is considered as the
+# second file to diff with
+#
+# Shell: POSIX compliant
+# Authors: Arun Prakash Jana, ath3
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+
+if type nvim >/dev/null 2>&1; then
+ diffcmd="nvim -d"
+else
+ diffcmd="vimdiff +0"
+fi
+
+dirdiff() {
+ dir1=$(mktemp "${TMPDIR:-/tmp}"/nnn-"$(basename "$1")".XXXXXXXX)
+ dir2=$(mktemp "${TMPDIR:-/tmp}"/nnn-"$(basename "$2")".XXXXXXXX)
+ ls -A1 "$1" > "$dir1"
+ ls -A1 "$2" > "$dir2"
+ $diffcmd "$dir1" "$dir2"
+ rm "$dir1" "$dir2"
+}
+
+if [ -s "$selection" ]; then
+ arr=$(tr '\0' '\n' < "$selection")
+ if [ "$(echo "$arr" | wc -l)" -gt 1 ]; then
+ f1="$(echo "$arr" | sed -n '1p')"
+ f2="$(echo "$arr" | sed -n '2p')"
+ if [ -d "$f1" ] && [ -d "$f2" ]; then
+ dirdiff "$f1" "$f2"
+ else
+ # If xargs supports the -o option, use it to get rid of:
+ # Vim: Warning: Input is not from a terminal
+ # xargs -0 -o vimdiff < $selection
+
+ eval xargs -0 "$diffcmd" < "$selection"
+ fi
+ elif [ -n "$1" ]; then
+ f1="$(echo "$arr" | sed -n '1p')"
+ if [ -d "$f1" ] && [ -d "$1" ]; then
+ dirdiff "$f1" "$1"
+ elif [ -f "$f1" ] && [ -f "$1" ]; then
+ $diffcmd "$f1" "$1"
+ else
+ echo "cannot compare file with directory"
+ fi
+ else
+ echo "needs at least 2 files or directories selected for comparison"
+ fi
+fi
+
+# Clear selection
+if [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+fi
diff --git a/files/.config/nnn/plugins/dragdrop b/files/.config/nnn/plugins/dragdrop
new file mode 100755
index 0000000..812f970
--- /dev/null
+++ b/files/.config/nnn/plugins/dragdrop
@@ -0,0 +1,77 @@
+#!/usr/bin/env sh
+
+# Description: Open a Drag and drop window, to drop files onto other programs.
+# Also provides drag and drop window for files.
+#
+# Dependencies: dragon - https://github.com/mwh/dragon
+#
+# Notes:
+# 1. Files that are dropped will be added to nnn's selection
+# Some web-based files will be downloaded to current dir
+# with curl and it may overwrite some existing files
+# 2. The user has to mm to clear nnn's selection first
+#
+# Shell: POSIX compliant
+# Author: 0xACE
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+resp=f
+all=
+if type dragon-drag-and-drop >/dev/null 2>&1; then
+ dnd="dragon-drag-and-drop"
+elif type dragon-drop >/dev/null 2>&1; then
+ dnd="dragon-drop"
+else
+ dnd="dragon"
+fi
+
+add_file ()
+{
+ printf '%s\0' "$@" >> "$selection"
+}
+
+use_all ()
+{
+ printf "mark --all (a) [default=none]: "
+ read -r resp
+ if [ "$resp" = "a" ]; then
+ all="--all"
+ else
+ all=""
+ fi
+}
+
+if [ -s "$selection" ]; then
+ printf "Drop file (r). Drag selection (s), Drag current directory (d) or drag current file (f) [default=f]: "
+ read -r resp
+else
+ printf "Drop file (r). Drag current directory (d) or drag current file (f) [default=f]: "
+ read -r resp
+ if [ "$resp" = "s" ]; then
+ resp=f
+ fi
+fi
+
+if [ "$resp" = "s" ]; then
+ use_all
+ sed -z 's|'"$PWD/"'||g' < "$selection" | xargs -0 "$dnd" "$all" &
+elif [ "$resp" = "d" ]; then
+ use_all
+ "$dnd" "$all" "$PWD/"* &
+elif [ "$resp" = "r" ]; then
+ true > "$selection"
+ "$dnd" --print-path --target | while read -r f
+ do
+ if printf "%s" "$f" | grep '^\(https\?\|ftps\?\|s\?ftp\):\/\/' ; then
+ curl -LJO "$f"
+ add_file "$PWD/$(basename "$f")"
+ elif [ -e "$f" ]; then
+ add_file "$f"
+ fi
+ done &
+else
+ if [ -n "$1" ] && [ -e "$1" ]; then
+ "$dnd" "$1" &
+ fi
+fi
+
diff --git a/files/.config/nnn/plugins/dups b/files/.config/nnn/plugins/dups
new file mode 100755
index 0000000..27c1807
--- /dev/null
+++ b/files/.config/nnn/plugins/dups
@@ -0,0 +1,70 @@
+#!/usr/bin/env sh
+
+# Description: List non-empty duplicates in the current dir (based on size followed by MD5)
+#
+# Source: https://www.commandlinefu.com/commands/view/3555/find-duplicate-files-based-on-size-first-then-md5-hash
+#
+# Dependencies: find md5sum sort uniq xargs gsed
+#
+# Notes:
+# 1. If the file size exceeds $size_digits digits the file will be misplaced
+# 12 digits fit files up to 931GiB
+# 2. Bash compatible required for mktemp
+#
+# Shell: Bash
+# Authors: syssyphus, KlzXS
+
+EDITOR="${EDITOR:-vi}"
+TMPDIR="${TMPDIR:-/tmp}"
+
+size_digits=12
+tmpfile=$(mktemp "$TMPDIR/.nnnXXXXXX")
+
+printf "\
+## This is an overview of all duplicate files found.
+## Comment out the files you wish to remove. You will be given an option to cancel.
+## Lines with double comments (##) are ignored.
+## You will have the option to remove the files with force or interactively.\n
+" > "$tmpfile"
+
+# shellcheck disable=SC2016
+find . -size +0 -type f -printf "%${size_digits}s %p\n" | sort -rn | uniq -w"${size_digits}" -D | sed -e '
+s/^ \{0,12\}\([0-9]\{0,12\}\) \(.*\)$/printf "%s %s\\n" "$(md5sum "\2")" "d\1"/
+' | tr '\n' '\0' | xargs -0 -n1 sh -c | sort | { uniq -w32 --all-repeated=separate; echo; } | sed -ne '
+h
+s/^\(.\{32\}\).* d\([0-9]*\)$/## md5sum: \1 size: \2 bytes/p
+g
+
+:loop
+N
+/.*\n$/!b loop
+p' | sed -e 's/^.\{32\} \(.*\) d[0-9]*$/\1/' >> "$tmpfile"
+
+"$EDITOR" "$tmpfile"
+
+printf "Remove commented files? (yes/no) [default=n]: "
+read -r commented
+
+if [ "$commented" = "y" ]; then
+ sedcmd="/^##.*/d; /^[^#].*/d; /^$/d; s/^# *\(.*\)$/\1/"
+else
+ printf "Press any key to exit"
+ read -r _
+ exit
+fi
+
+printf "Remove with force or interactive? (f/i) [default=i]: "
+read -r force
+
+if [ "$force" = "f" ]; then
+ #shellcheck disable=SC2016
+ sed -e "$sedcmd" "$tmpfile" | tr '\n' '\0' | xargs -0 -r sh -c 'rm -f "$0" "$@" </dev/tty'
+else
+ #shellcheck disable=SC2016
+ sed -e "$sedcmd" "$tmpfile" | tr '\n' '\0' | xargs -0 -r sh -c 'rm -i "$0" "$@" </dev/tty'
+fi
+
+rm "$tmpfile"
+
+printf "Press any key to exit"
+read -r _
diff --git a/files/.config/nnn/plugins/finder b/files/.config/nnn/plugins/finder
new file mode 100755
index 0000000..bdd2e69
--- /dev/null
+++ b/files/.config/nnn/plugins/finder
@@ -0,0 +1,89 @@
+#!/usr/bin/env bash
+
+# Description: Run custom search and list results in smart context
+#
+# Note: This plugin retains search history
+#
+# Usage:
+# Run plugin and enter e.g. "-size +10M" to list files in current
+# directory larger than 10M. By default entered expressions are
+# interpreted as arguments to find. Results have to be NUL
+# terminated which is done by default for find. Alternatively one
+# can prepend a '$' to run a custom search program such as fd or
+# ripgrep. Entered expressions will be saved in history file to
+# be listed as bookmarks and and can be entered by index and edited.
+#
+# Shell: Bash
+# Author: Arun Prakash Jana, Luuk van Baal
+TMPDIR="${TMPDIR:-/tmp}"
+NNN_FINDHIST="${NNN_FINDHIST:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/finderbms}"
+NNN_FINDHISTLEN="${NNN_FINDHISTLEN:-10000}"
+
+printexamples() {
+ printf -- "-maxdepth 1 -name pattern
+-maxdepth 1 -size +100M
+\$fd -0 pattern
+\$fd -0 -d 2 -S +100M
+\$grep -rlZ pattern
+\$rg -l0 pattern
+\$fzf -m | tr '\\\n' '\\\0'\n"
+}
+
+printexprs() {
+ for ((i = "$1"; i < ${#fexprs[@]}; i++)); do
+ printf '%s\t%s\n' "$((i + 1))" "${fexprs[$i]}"
+ done
+}
+
+mapexpr() {
+ if [ "$fexpr" -eq "$fexpr" ] 2>/dev/null; then
+ fexpr=${fexprs[$((fexpr - 1))]}
+ read -r -e -p "Search expression: " -i "$fexpr" fexpr
+ else
+ return 1
+ fi
+}
+
+readexpr() {
+ case "$fexpr" in
+ h) clear
+ printf "Examples:\n"
+ mapfile -t fexprs < <(printexamples)
+ printexprs 0
+ read -r -p "Search expression or index: " fexpr
+ mapexpr
+ [ -n "$fexpr" ] && readexpr ;;
+ \$*) cmd="${fexpr:1}" ;;
+ *) mapexpr && readexpr
+ cmd="find . $fexpr -print0" ;;
+ esac
+}
+
+clear
+[ -f "$NNN_FINDHIST" ] || printexamples > "$NNN_FINDHIST"
+
+mapfile -t fexprs < <(sort "$NNN_FINDHIST" | uniq -c | sort -nr | head -n5 |\
+ awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}')
+printf "Most used search expressions:\n"
+printexprs 0
+
+mapfile -t -O"$i" fexprs < <(tac "$NNN_FINDHIST" | awk '!a[$0]++' | head -n5)
+printf "Most recently used search expressions:\n"
+printexprs "$i"
+read -r -p "Search expression or index (h for help): " fexpr
+
+mapexpr
+
+if [ -n "$fexpr" ]; then
+ printf "+l" > "$NNN_PIPE"
+ while :; do
+ readexpr
+ eval "$cmd" > "$NNN_PIPE" && break
+ read -r -e -p "Search expression: " -i "$fexpr" fexpr
+ done
+ if [ -n "$fexpr" ]; then
+ tail -n"$NNN_FINDHISTLEN" "$NNN_FINDHIST" > "$TMPDIR/finderbms"
+ printf "%s\n" "$fexpr" >> "$TMPDIR/finderbms"
+ mv "$TMPDIR/finderbms" "$NNN_FINDHIST"
+ fi
+fi
diff --git a/files/.config/nnn/plugins/fixname b/files/.config/nnn/plugins/fixname
new file mode 100755
index 0000000..4047152
--- /dev/null
+++ b/files/.config/nnn/plugins/fixname
@@ -0,0 +1,75 @@
+#!/usr/bin/env bash
+
+# Description: Clean filename or dirname (either hovered or selections)
+# to be more shell-friendly. This script cleans
+# non A-Za-z0-9._- characters.
+# and replaces it with underscore (_).
+#
+# It supports cleaning single/double quote, newline,
+# leading, trailing spaces.
+#
+# eg.
+# to be continued (つづく).mp4 -> to_be_continued______.mp4
+# [work] stuff.txt -> _work__stuff.txt
+# home's server -> home_s_server
+# qwe\trty -> __qwe_rty
+#
+# And if there are two almost similar filenames
+# like: 'asd]f' and 'asd f' both will be renamed to 'asd_f',
+# to avoid overwriting, the last file will be prepended by _.
+# So they will be: 'asd_f' and '_asd_f'
+#
+# Dependencies: sed
+#
+# Shell: Bash
+# Author: Benawi Adha
+
+prompt=true
+sel=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+
+cleanup() {
+ # printf "%s" "$1" | sed -e 's/[^A-Za-z0-9._-]/_/g'
+ printf "%s" "$1" | sed 's/[^A-Za-z0-9._-]/_/g' | sed ':a;N;$!ba;s/\n/_/g'
+}
+
+if [ -s "$sel" ]; then
+ targets=()
+ while IFS= read -r -d '' i || [ -n "$i" ]; do
+ targets+=( "$(basename "$i")" )
+ done < "$sel"
+else
+ targets=("$1")
+fi
+
+for i in "${targets[@]}"; do
+ printf "%s -> %s\n" "$i" "$(cleanup "$i")";
+done
+
+if $prompt; then
+ echo
+ printf "Proceed [Yn]? "
+ read -r input
+ case "$input" in
+ y|Y|'')
+ ;;
+ *)
+ echo "Canceled"
+ exit
+ ;;
+ esac
+fi
+
+for i in "${targets[@]}"; do
+ if [ "$i" != "$(cleanup "$i")" ]; then
+ tmp=''
+ if [ -e "$(cleanup "$i")" ]; then
+ tmp='_'
+ fi
+ mv "$i" "$tmp$(cleanup "$i")";
+ fi
+done
+
+# Clear selection
+if [ -s "$sel" ] && [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+fi
diff --git a/files/.config/nnn/plugins/fzcd b/files/.config/nnn/plugins/fzcd
new file mode 100755
index 0000000..125092c
--- /dev/null
+++ b/files/.config/nnn/plugins/fzcd
@@ -0,0 +1,89 @@
+#!/usr/bin/env sh
+
+# Description: Fuzzy search multiple locations read-in from a path-list file
+# (or $PWD) and open the selected file's dir in a smart context.
+# Dependencies: fzf, find (only for multi-location search)
+#
+# Details: Paths in list file should be newline-separated absolute paths.
+# Paths can be file paths; the script will scan the parent dirs.
+#
+# The path-list file precedence is:
+# - "$1" (the hovered file) if it exists, is plain-text and the
+# first line points to an existing file
+# - "$LIST" if set below
+# - "$2" (the current directory) [mimics plugin fzcd behaviour]
+#
+# The path-list file can be generated easily:
+# - pick the (file)paths in picker mode to path-list file
+# - OR, edit selection in nnn and save as path-list file
+#
+# Shell: POSIX compliant
+# Author: Anna Arad, Arun Prakash Jana, KlzXS
+
+IFS="$(printf '\n\r')"
+
+# shellcheck disable=SC1090,SC1091
+. "$(dirname "$0")"/.nnn-plugin-helper
+
+CTX=+
+LIST="${LIST:-""}"
+
+if ! type fzf >/dev/null 2>&1; then
+ printf "fzf missing"
+ read -r _
+ exit 1
+fi
+
+if [ -n "$1" ] && [ "$(file -b --mime-type "$1")" = 'text/plain' ] && [ -e "$(head -1 "$1")" ]; then
+ LIST="$1"
+elif ! [ -s "$LIST" ]; then
+ sel=$(fzf)
+ # Show only the file and parent dir
+ # sel=$(fzf --delimiter / --with-nth=-2,-1 --tiebreak=begin --info=hidden)
+
+ LIST=''
+fi
+
+if [ -n "$LIST" ]; then
+ if type find >/dev/null 2>&1; then
+ tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
+
+ while IFS= read -r path; do
+ if [ -d "$path" ]; then
+ printf "%s\n" "$path" >> "$tmpfile"
+ elif [ -f "$path" ]; then
+ printf "%s\n" "$(dirname "$path")" >> "$tmpfile"
+ fi
+ done < "$LIST"
+
+ sel=$(xargs -d '\n' < "$tmpfile" -I{} find {} -type f -printf "%H//%P\n" | sed '/.*\/\/\(\..*\|.*\/\..*\)/d; s:/\+:/:g' | fzf --delimiter / --tiebreak=begin --info=hidden)
+ # Alternative for 'fd'
+ # sel=$(xargs -d '\n' < "$tmpfile" fd . | fzf --delimiter / --tiebreak=begin --info=hidden)
+
+ rm "$tmpfile"
+ else
+ printf "find missing"
+ read -r _
+ exit 1
+ fi
+fi
+
+if [ -n "$sel" ]; then
+ if [ "$sel" = "." ] || { ! [ -d "$sel" ] && ! [ -f "$sel" ]; }; then
+ exit 0
+ fi
+
+ # Check if the selected path returned by fzf command is absolute
+ case $sel in
+ /*) nnn_cd "$sel" "$CTX" ;;
+ *)
+ # Remove "./" prefix if it exists
+ sel="${sel#./}"
+
+ if [ "$PWD" = "/" ]; then
+ nnn_cd "/$sel" "$CTX"
+ else
+ nnn_cd "$PWD/$sel" "$CTX"
+ fi;;
+ esac
+fi
diff --git a/files/.config/nnn/plugins/fzhist b/files/.config/nnn/plugins/fzhist
new file mode 100755
index 0000000..111bc22
--- /dev/null
+++ b/files/.config/nnn/plugins/fzhist
@@ -0,0 +1,40 @@
+#!/usr/bin/env sh
+
+# Description: Fuzzy find a command from history,
+# edit in $EDITOR and run as a command
+#
+# Note: Supports only bash and fish history
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+if type fzf >/dev/null 2>&1; then
+ fuzzy=fzf
+else
+ exit 1
+fi
+
+shellname="$(basename "$SHELL")"
+
+if [ "$shellname" = "bash" ]; then
+ hist_file="$HOME/.bash_history"
+ entry="$("$fuzzy" < "$hist_file")"
+elif [ "$shellname" = "fish" ]; then
+ hist_file="$HOME/.local/share/fish/fish_history"
+ entry="$(grep "\- cmd: " "$hist_file" | cut -c 8- | "$fuzzy")"
+fi
+
+if [ -n "$entry" ]; then
+ tmpfile=$(mktemp)
+ echo "$entry" >> "$tmpfile"
+ $EDITOR "$tmpfile"
+
+ if [ -s "$tmpfile" ]; then
+ $SHELL -c "$(cat "$tmpfile")"
+ fi
+
+ rm "$tmpfile"
+
+ printf "Press any key to exit"
+ read -r _
+fi
diff --git a/files/.config/nnn/plugins/fzplug b/files/.config/nnn/plugins/fzplug
new file mode 100755
index 0000000..11dcf7f
--- /dev/null
+++ b/files/.config/nnn/plugins/fzplug
@@ -0,0 +1,59 @@
+#!/usr/bin/env sh
+
+# Description: Fuzzy find and execute nnn plugins (and optionally,
+# custom scripts located elsewhere).
+# Description and details of plugins can be previewed
+# from the fzf interface. Use `?` to toggle preview
+# pane on and off, ^Up/^Dn to scroll.
+#
+# Dependencies: find, fzf, cat (or bat, if installed)
+#
+# Note: For better compatibility with as many nnn plugins as possible,
+# fzplug will first execute the chosen script on the file hovered
+# in nnn, and upon failure, try to run it with no target (i.e on
+# an active selection, if present).
+#
+# Shell: POSIX compliant
+# Author: Kabouik
+
+# Optional scripts sources
+
+# Leave blank or fill with the absolute path of a folder containing executable
+# scripts other than nnn plugins (e.g., "$HOME/.local/share/nautilus/scripts",
+# since there are numerous Nautilus script git repositories).
+# Add extra variables if needed, make sure you call them in the find command.
+
+#CUSTOMDIR1="$HOME/.local/share/nautilus/scripts"
+CUSTOMDIR1=""
+CUSTOMDIR2=""
+
+nnnpluginsdir="$HOME/.config/nnn/plugins"
+
+# Preview with bat if installed
+if type bat >/dev/null; then
+ BAT="bat --terminal-width='$(tput cols)' --decorations=always --color=always --style='${BAT_STYLE:-header,numbers}'"
+fi
+
+plugin=$(find "$nnnpluginsdir" "$CUSTOMDIR1" "$CUSTOMDIR2" \
+-maxdepth 3 -perm -111 -type f 2>/dev/null | fzf --ansi --preview \
+ "${BAT:-cat} {}" --preview-window="right:66%:wrap" --delimiter / \
+ --with-nth -1 --bind="?:toggle-preview")
+
+# Try running the script on the hovered file, and abort
+# abort if no plugin was selected (ESC or ^C pressed).
+err=0
+if ! [ "$plugin" = "" ]; then
+ "$plugin" "$1" || err=1
+fi
+
+# If attempt with hovered file fails, try without any target
+# (nnn selections should still be passed to the script in that case)
+if [ "$err" -eq "1" ]; then
+ clear && "$plugin" || err=2
+fi
+
+# Abort and show error if both fail
+if [ "$err" -eq "2" ]; then
+ sep="\n---\n"
+ printf "$sep""Failed to execute '%s'. See error above or try without fzfplug. Press return to continue. " "$plugin" && read -r _ && clear
+fi
diff --git a/files/.config/nnn/plugins/getplugs b/files/.config/nnn/plugins/getplugs
new file mode 100755
index 0000000..361a605
--- /dev/null
+++ b/files/.config/nnn/plugins/getplugs
@@ -0,0 +1,70 @@
+#!/usr/bin/env sh
+
+# Description: Update nnn plugins to installed nnn version
+#
+# Shell: POSIX compliant
+# Authors: Arun Prakash Jana, KlzXS
+
+CONFIG_DIR=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/
+PLUGIN_DIR=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins
+
+merge () {
+ if type nvim >/dev/null 2>&1; then
+ nvim -d "$1" "$2"
+ else
+ vimdiff +0 "$1" "$2"
+ fi
+}
+
+prompt () {
+ printf "%s\n" "Plugin $1 already exists and is different."
+ printf "Keep (k), merge (m), overwrite (o) [default: k]? "
+ read -r operation
+
+ if [ "$operation" = "m" ]; then
+ op="merge"
+ elif [ "$operation" = "o" ]; then
+ op="cp -vRf"
+ else
+ op="true"
+ fi
+}
+
+if [ "$1" = "master" ] ; then
+ VER="master"
+ ARCHIVE_URL=https://github.com/jarun/nnn/archive/master.tar.gz
+elif type nnn >/dev/null 2>&1; then
+ VER=$(nnn -V)
+ ARCHIVE_URL=https://github.com/jarun/nnn/releases/download/v"$VER"/nnn-v"$VER".tar.gz
+else
+ echo "nnn is not installed"
+ exit 1
+fi
+
+# backup any earlier plugins
+if [ -d "$PLUGIN_DIR" ]; then
+ tar -C "$CONFIG_DIR" -czf "$CONFIG_DIR""plugins-$(date '+%Y%m%d%H%M').tar.gz" plugins/
+fi
+
+mkdir -p "$PLUGIN_DIR"
+cd "$CONFIG_DIR" || exit 1
+curl -Ls "$ARCHIVE_URL" -o nnn-"$VER".tar.gz
+tar -zxf nnn-"$VER".tar.gz
+
+cd nnn-"$VER"/plugins || exit 1
+
+# shellcheck disable=SC2044
+# We do not use obnoxious names for plugins
+for f in $(find . -maxdepth 1 \( ! -iname "." ! -iname "*.md" \)); do
+ if [ -f ../../plugins/"$f" ]; then
+ if [ "$(diff --brief "$f" ../../plugins/"$f")" ]; then
+ prompt "$f"
+ $op "$f" ../../plugins/
+ fi
+ else
+ cp -vRf "$f" ../../plugins/
+ fi
+done
+cd ../.. || exit 1
+
+rm -rf nnn-"$VER"/ nnn-"$VER".tar.gz
diff --git a/files/.config/nnn/plugins/gitroot b/files/.config/nnn/plugins/gitroot
new file mode 100755
index 0000000..4428d1e
--- /dev/null
+++ b/files/.config/nnn/plugins/gitroot
@@ -0,0 +1,15 @@
+#!/usr/bin/env sh
+
+# Description: cd to the top level of the current git repository in the current context
+# Dependencies: git
+# Shell: sh
+# Author: https://github.com/PatrickF1
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)"
+if [ -n "$root" ]; then
+ printf "%s" "0c$root" > "$NNN_PIPE"
+else
+ printf "Not in a git repository"
+ read -r _
+ exit 1
+fi
diff --git a/files/.config/nnn/plugins/gpgd b/files/.config/nnn/plugins/gpgd
new file mode 100755
index 0000000..44d5c0f
--- /dev/null
+++ b/files/.config/nnn/plugins/gpgd
@@ -0,0 +1,28 @@
+#!/usr/bin/env sh
+
+# Description: Decrypts selected files using gpg. The contents of the
+# decrypted file are stored in a file with extension .dec
+#
+# Note: If an appropriate private key cannot be found gpg silently
+# prints a message in the background and no files are written.
+#
+# Shell: POSIX compliant
+# Author: KlzXS
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+
+printf "(s)election/(c)urrent? [default=c] "
+read -r resp
+
+if [ "$resp" = "s" ]; then
+ files=$(tr '\0' '\n' < "$selection")
+else
+ files=$1
+fi
+
+printf "%s" "$files" | xargs -n1 -I{} gpg --decrypt --output "{}.dec" {}
+
+# Clear selection
+if [ "$resp" = "s" ] && [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+fi
diff --git a/files/.config/nnn/plugins/gpge b/files/.config/nnn/plugins/gpge
new file mode 100755
index 0000000..7664cda
--- /dev/null
+++ b/files/.config/nnn/plugins/gpge
@@ -0,0 +1,45 @@
+#!/usr/bin/env sh
+
+# Description: Encrypts selected files using gpg. Can encrypt
+# asymmetrically (key) or symmetrically (passphrase).
+# If asymmetric encryption is chosen a key can be
+# chosen from the list of capable public keys using fzf.
+#
+# Note: Symmetric encryption only works for a single (current) file as per gpg limitations
+#
+# Shell: POSIX compliant
+# Author: KlzXS
+
+# shellcheck disable=SC1090,SC1091
+. "$(dirname "$0")"/.nnn-plugin-helper
+
+printf "(s)ymmetric, (a)symmetric? [default=a] "
+read -r symmetry
+
+if [ "$symmetry" = "s" ]; then
+ gpg --symmetric "$1"
+else
+ if nnn_use_selection; then
+ clear_sel=1
+ # shellcheck disable=SC2154
+ files=$(tr '\0' '\n' < "$selection")
+ else
+ clear_sel=0
+ files=$1
+ fi
+
+ keyids=$(gpg --list-public-keys --with-colons | grep -E "pub:(.*:){10}.*[eE].*:" | awk -F ":" '{print $5}')
+
+ #awk needs literal $10
+ #shellcheck disable=SC2016
+ keyuids=$(printf "%s" "$keyids" | xargs -n1 -I{} sh -c 'gpg --list-key --with-colons "{}" | grep "uid" | awk -F ":" '\''{printf "%s %s\n", "{}", $10}'\''')
+
+ recipient=$(printf "%s" "$keyuids" | fzf | awk '{print $1}')
+
+ printf "%s" "$files" | xargs -n1 gpg --encrypt --recipient "$recipient"
+
+ # Clear selection
+ if [ "$clear_sel" -eq 1 ] && [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+ fi
+fi
diff --git a/files/.config/nnn/plugins/gsconnect b/files/.config/nnn/plugins/gsconnect
new file mode 100755
index 0000000..f45f3d3
--- /dev/null
+++ b/files/.config/nnn/plugins/gsconnect
@@ -0,0 +1,21 @@
+#!/usr/bin/env sh
+
+#set -x
+# Description: Send the selected (or hovered) files to your Android device using gsconnect daemon.js.
+# GSConnect must be configured on the Android device and the PC.
+#
+# Shell: POSIX compliant
+# Author: Darukutsu
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+gsconnect=$HOME/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/daemon.js
+ids=$($gsconnect -l)
+
+for id in $ids; do
+ if [ -s "$selection" ]; then
+ xargs -0 < "$selection" -I{} "$gsconnect" -d "$id" --share-file="{}"
+ # Clear selection
+ printf "-" > "$NNN_PIPE"
+ else
+ "$gsconnect" -d "$id" --share-file="$2/$1"
+ fi
+done
diff --git a/files/.config/nnn/plugins/gutenread b/files/.config/nnn/plugins/gutenread
new file mode 100755
index 0000000..036ff35
--- /dev/null
+++ b/files/.config/nnn/plugins/gutenread
@@ -0,0 +1,49 @@
+#!/usr/bin/env sh
+
+# Description: Browse Project Gutenberg catalogue by popularity, then download
+# and read a book of your choice.
+#
+# Details: Set the variable EBOOK_ID to download in html format and read in w3m.
+# Clear EBOOK_ID to browse available ebooks by popularity and set it to
+# the ID once you find an interesting one.
+# To download and read in epub format set READER to an epub reader like
+# epr: https://github.com/wustho/epr
+#
+# More on EBOOK_ID:
+# Wuthering Heights by Emily Brontë is at https://www.gutenberg.org/ebooks/768
+# So EBOOK_ID would be 768
+#
+# Downloaded ebooks are at ${XDG_CACHE_HOME:-$HOME/.cache}/nnn/gutenbooks/
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+EBOOK_ID="${EBOOK_ID:-""}"
+DIR="${XDG_CACHE_HOME:-$HOME/.cache}/nnn/gutenbooks/$EBOOK_ID"
+BROWSE_LINK="https://www.gutenberg.org/ebooks/search/?sort_order=downloads"
+BROWSER="${BROWSER:-w3m}"
+READER="${READER:-""}"
+
+if [ -n "$EBOOK_ID" ]; then
+ if [ ! -e "$DIR" ]; then
+ mkdir -p "$DIR"
+ cd "$DIR" || exit 1
+
+ if [ -z "$READER" ]; then
+ curl -L -O "https://www.gutenberg.org/files/$EBOOK_ID/$EBOOK_ID-h.zip"
+ unzip "$EBOOK_ID"-h.zip
+ else
+ curl -L -o "$EBOOK_ID".epub "https://www.gutenberg.org/ebooks/$EBOOK_ID.epub.noimages"
+ fi
+ fi
+
+ if [ -d "$DIR" ]; then
+ if [ -z "$READER" ]; then
+ "$BROWSER" "$DIR/$EBOOK_ID-h/$EBOOK_ID-h.htm"
+ else
+ "$READER" "$DIR/$EBOOK_ID.epub"
+ fi
+ fi
+else
+ "$BROWSER" "$BROWSE_LINK"
+fi
diff --git a/files/.config/nnn/plugins/imgresize b/files/.config/nnn/plugins/imgresize
new file mode 100755
index 0000000..351fe71
--- /dev/null
+++ b/files/.config/nnn/plugins/imgresize
@@ -0,0 +1,31 @@
+#!/usr/bin/env sh
+
+# Description: Resize images in a directory to screen resolution with imgp
+#
+# Dependencipes: imgp - https://github.com/jarun/imgp
+#
+# Notes:
+# 1. Set res to avoid the desktop resolution prompt each time
+# 2. MINSIZE is set to 1MB by default, adjust it if you want
+# 3. imgp options used:
+# a - adaptive mode
+# c - convert PNG to JPG
+# k - skip images matching specified hres/vres
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+# set resolution (e.g. 1920x1080)
+res="${RESOLUTION}"
+
+# set minimum image size (in bytes) to resize (default: 1MB)
+MINSIZE="${MINSIZE:-1048576}"
+
+if [ -z "$res" ]; then
+ printf "desktop resolution (hxv): "
+ read -r res
+fi
+
+if [ -n "$res" ] && [ -n "$MINSIZE" ]; then
+ imgp -ackx "$res" -s "$MINSIZE"
+fi
diff --git a/files/.config/nnn/plugins/imgur b/files/.config/nnn/plugins/imgur
new file mode 100755
index 0000000..16d21bc
--- /dev/null
+++ b/files/.config/nnn/plugins/imgur
@@ -0,0 +1,597 @@
+#!/usr/bin/env bash
+
+##########################################################################
+# The MIT License
+#
+# Copyright (c) jomo
+#
+# Permission is hereby granted, free of charge,
+# to any person obtaining a copy of this software and
+# associated documentation files (the "Software"), to
+# deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify,
+# merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom
+# the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice
+# shall be included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+##########################################################################
+
+# https://github.com/jomo/imgur-screenshot
+# https://help.imgur.com/hc/en-us/articles/209592766-Tools-for-Imgur
+#
+# Slightly modified for `nnn` integration
+#
+# Shell: Bash
+# Description: Upload an image file to imgur
+
+if [ "${1}" = "--debug" ]; then
+ echo "########################################"
+ echo "Enabling debug mode"
+ echo "Please remove credentials before pasting"
+ echo "########################################"
+ echo ""
+ uname -a
+ for arg in ${0} "${@}"; do
+ echo -n "'${arg}' "
+ done
+ echo -e "\n"
+ shift
+ set -x
+fi
+
+current_version="v1.7.4"
+
+function is_mac() {
+ uname | grep -q "Darwin"
+}
+
+### IMGUR-SCREENSHOT DEFAULT CONFIG ####
+
+# You can override the config in ~/.config/imgur-screenshot/settings.conf
+
+imgur_anon_id="ea6c0ef2987808e"
+imgur_icon_path="${HOME}/Pictures/imgur.png"
+
+imgur_acct_key=""
+imgur_secret=""
+login="false"
+album_title=""
+album_id=""
+credentials_file="${HOME}/.config/imgur-screenshot/credentials.conf"
+
+file_name_format="imgur-%Y_%m_%d-%H:%M:%S.png" # when using scrot, must end with .png!
+file_dir="${HOME}/Pictures"
+
+upload_connect_timeout="5"
+upload_timeout="120"
+upload_retries="1"
+
+# shellcheck disable=SC2034
+if is_mac; then
+ screenshot_select_command="screencapture -i %img"
+ screenshot_window_command="screencapture -iWa %img"
+ screenshot_full_command="screencapture %img"
+ open_command="open %url"
+else
+ screenshot_select_command="scrot -s %img"
+ screenshot_window_command="scrot %img"
+ screenshot_full_command="scrot %img"
+ open_command="xdg-open %url"
+fi
+open="true"
+
+mode="select"
+edit_command="gimp %img"
+edit="false"
+exit_on_album_creation_fail="true"
+
+log_file="${HOME}/.imgur-screenshot.log"
+
+auto_delete=""
+copy_url="true"
+keep_file="true"
+check_update="true"
+
+# NOTICE: if you make changes here, also edit the docs at
+# https://github.com/jomo/imgur-screenshot/wiki/Config
+
+# You can override the config in ~/.config/imgur-screenshot/settings.conf
+
+############## END CONFIG ##############
+
+settings_path="${HOME}/.config/imgur-screenshot/settings.conf"
+if [ -f "${settings_path}" ]; then
+ # shellcheck disable=SC1090
+ source "${settings_path}"
+fi
+
+# dependency check
+if [ "${1}" = "--check" ]; then
+ (type grep &>/dev/null && echo "OK: found grep") || echo "ERROR: grep not found"
+ if is_mac; then
+ if type growlnotify &>/dev/null; then
+ echo "OK: found growlnotify"
+ elif type terminal-notifier &>/dev/null; then
+ echo "OK: found terminal-notifier"
+ else
+ echo "ERROR: growlnotify nor terminal-notifier found"
+ fi
+ (type screencapture &>/dev/null && echo "OK: found screencapture") || echo "ERROR: screencapture not found"
+ (type pbcopy &>/dev/null && echo "OK: found pbcopy") || echo "ERROR: pbcopy not found"
+ else
+ (type notify-send &>/dev/null && echo "OK: found notify-send") || echo "ERROR: notify-send (from libnotify-bin) not found"
+ (type scrot &>/dev/null && echo "OK: found scrot") || echo "ERROR: scrot not found"
+ (type xclip &>/dev/null && echo "OK: found xclip") || echo "ERROR: xclip not found"
+ fi
+ (type curl &>/dev/null && echo "OK: found curl") || echo "ERROR: curl not found"
+ exit 0
+fi
+
+
+# notify <'ok'|'error'> <title> <text>
+function notify() {
+ if is_mac; then
+ if type growlnotify &>/dev/null; then
+ growlnotify --icon "${imgur_icon_path}" --iconpath "${imgur_icon_path}" --title "${2}" --message "${3}"
+ else
+ terminal-notifier -appIcon "${imgur_icon_path}" -contentImage "${imgur_icon_path}" -title "imgur: ${2}" -message "${3}"
+ fi
+ else
+ if [ "${1}" = "error" ]; then
+ notify-send -a ImgurScreenshot -u critical -c "im.error" -i "${imgur_icon_path}" -t 500 "imgur: ${2}" "${3}"
+ else
+ notify-send -a ImgurScreenshot -u low -c "transfer.complete" -i "${imgur_icon_path}" -t 500 "imgur: ${2}" "${3}"
+ fi
+ fi
+}
+
+function take_screenshot() {
+ echo "Please select area"
+ is_mac || sleep 0.1 # https://bbs.archlinux.org/viewtopic.php?pid=1246173#p1246173
+
+ cmd="screenshot_${mode}_command"
+ cmd=${!cmd//\%img/${1}}
+
+ if ! shot_err="$(${cmd} &>/dev/null)"; then #takes a screenshot with selection
+ echo "Failed to take screenshot '${1}': '${shot_err}'. For more information visit https://github.com/jomo/imgur-screenshot/wiki/Troubleshooting" | tee -a "${log_file}"
+ notify error "Something went wrong :(" "Information has been logged"
+ exit 1
+ fi
+}
+
+function check_for_update() {
+ # exit non-zero on HTTP error, output only the body (no stats) but output errors, follow redirects, output everything to stdout
+ remote_version="$(curl --compressed -fsSL --stderr - "https://api.github.com/repos/jomo/imgur-screenshot/releases" | grep -Em 1 --color 'tag_name":\s*".*"' | cut -d '"' -f 4)"
+ if [ -n "$remote_version" ]; then
+ if [ ! "${current_version}" = "${remote_version}" ] && [ -n "${current_version}" ] && [ -n "${remote_version}" ]; then
+ echo "Update found!"
+ echo "Version ${remote_version} is available (You have ${current_version})"
+ notify ok "Update found" "Version ${remote_version} is available (You have ${current_version}). https://github.com/jomo/imgur-screenshot"
+ echo "Check https://github.com/jomo/imgur-screenshot/releases/${remote_version} for more info."
+ elif [ -z "${current_version}" ] || [ -z "${remote_version}" ]; then
+ echo "Invalid empty version string"
+ echo "Current (local) version: '${current_version}'"
+ echo "Latest (remote) version: '${remote_version}'"
+ else
+ echo "Version ${current_version} is up to date."
+ fi
+ else
+ echo "Failed to check for latest version: ${remote_version}"
+ fi
+}
+
+function check_oauth2_client_secrets() {
+ if [ -z "${imgur_acct_key}" ] || [ -z "${imgur_secret}" ]; then
+ echo "In order to upload to your account, register a new application at:"
+ echo "https://api.imgur.com/oauth2/addclient"
+ echo "Select 'OAuth 2 authorization without a callback URL'"
+ echo "Then, set the imgur_acct_key (Client ID) and imgur_secret in your config."
+ exit 1
+ fi
+}
+
+function load_access_token() {
+ token_expire_time=0
+ # check for saved access_token and its expiration date
+ if [ -f "${credentials_file}" ]; then
+ # shellcheck disable=SC1090
+ source "${credentials_file}"
+ fi
+ current_time="$(date +%s)"
+ preemptive_refresh_time="$((10*60))"
+ expired="$((current_time > (token_expire_time - preemptive_refresh_time)))"
+ if [ -n "${refresh_token}" ]; then
+ # token already set
+ if [ "${expired}" -eq "0" ]; then
+ # token expired
+ refresh_access_token "${credentials_file}"
+ fi
+ else
+ acquire_access_token "${credentials_file}"
+ fi
+}
+
+function acquire_access_token() {
+ check_oauth2_client_secrets
+ # prompt for a PIN
+ authorize_url="https://api.imgur.com/oauth2/authorize?client_id=${imgur_acct_key}&response_type=pin"
+ echo "Go to"
+ echo "${authorize_url}"
+ echo "and grant access to this application."
+ read -rp "Enter the PIN: " imgur_pin
+
+ if [ -z "${imgur_pin}" ]; then
+ echo "PIN not entered, exiting"
+ exit 1
+ fi
+
+ # exchange the PIN for access token and refresh token
+ response="$(curl --compressed -fsSL --stderr - \
+ -F "client_id=${imgur_acct_key}" \
+ -F "client_secret=${imgur_secret}" \
+ -F "grant_type=pin" \
+ -F "pin=${imgur_pin}" \
+ https://api.imgur.com/oauth2/token)"
+ save_access_token "${response}" "${1}"
+}
+
+function refresh_access_token() {
+ check_oauth2_client_secrets
+ token_url="https://api.imgur.com/oauth2/token"
+ # exchange the refresh token for access_token and refresh_token
+ if ! response="$(curl --compressed -fsSL --stderr - \
+ -F "client_id=${imgur_acct_key}" \
+ -F "client_secret=${imgur_secret}" \
+ -F "grant_type=refresh_token" \
+ -F "refresh_token=${refresh_token}" \
+ "${token_url}"
+ )"; then
+ # curl failed
+ handle_upload_error "${response}" "${token_url}"
+ exit 1
+ fi
+ save_access_token "${response}" "${1}"
+}
+
+function save_access_token() {
+ if ! grep -q "access_token" <<<"${1}"; then
+ # server did not send access_token
+ echo "Error: Something is wrong with your credentials:"
+ echo "${1}"
+ exit 1
+ fi
+
+ access_token="$(grep -Eo 'access_token":".*"' <<<"${1}" | cut -d '"' -f 3)"
+ refresh_token="$(grep -Eo 'refresh_token":".*"' <<<"${1}" | cut -d '"' -f 3)"
+ expires_in="$(grep -Eo 'expires_in":[0-9]*' <<<"${1}" | cut -d ':' -f 2)"
+ token_expire_time="$(( $(date +%s) + expires_in ))"
+
+ # create dir if not exist
+ mkdir -p "$(dirname "${2}")" 2>/dev/null
+ touch "${2}" && chmod 600 "${2}"
+ cat <<EOF > "${2}"
+access_token="${access_token}"
+refresh_token="${refresh_token}"
+token_expire_time="${token_expire_time}"
+EOF
+}
+
+function fetch_account_info() {
+ response="$(curl --compressed --connect-timeout "${upload_connect_timeout}" -m "${upload_timeout}" --retry "${upload_retries}" -fsSL --stderr - -H "Authorization: Bearer ${access_token}" https://api.imgur.com/3/account/me)"
+ if grep -Eq '"success":\s*true' <<<"${response}"; then
+ username="$(grep -Eo '"url":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
+ echo "Logged in as ${username}."
+ echo "https://${username}.imgur.com"
+ else
+ echo "Failed to fetch info: ${response}"
+ fi
+}
+
+function delete_image() {
+ response="$(curl --compressed -X DELETE -fsSL --stderr - -H "Authorization: Client-ID ${1}" "https://api.imgur.com/3/image/${2}")"
+ if grep -Eq '"success":\s*true' <<<"${response}"; then
+ echo "Image successfully deleted (delete hash: ${2})." >> "${3}"
+ else
+ echo "The Image could not be deleted: ${response}." >> "${3}"
+ fi
+}
+
+function upload_authenticated_image() {
+ echo "Uploading '${1}'..."
+ title="$(echo "${1}" | rev | cut -d "/" -f 1 | cut -d "." -f 2- | rev)"
+ if [ -n "${album_id}" ]; then
+ response="$(curl --compressed --connect-timeout "${upload_connect_timeout}" -m "${upload_timeout}" --retry "${upload_retries}" -fsSL --stderr - -F "title=${title}" -F "image=@\"${1}\"" -F "album=${album_id}" -H "Authorization: Bearer ${access_token}" https://api.imgur.com/3/image)"
+ else
+ response="$(curl --compressed --connect-timeout "${upload_connect_timeout}" -m "${upload_timeout}" --retry "${upload_retries}" -fsSL --stderr - -F "title=${title}" -F "image=@\"${1}\"" -H "Authorization: Bearer ${access_token}" https://api.imgur.com/3/image)"
+ fi
+
+ # JSON parser premium edition (not really)
+ if grep -Eq '"success":\s*true' <<<"${response}"; then
+ img_id="$(grep -Eo '"id":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
+ img_ext="$(grep -Eo '"link":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4 | rev | cut -d "." -f 1 | rev)" # "link" itself has ugly '\/' escaping and no https!
+ del_id="$(grep -Eo '"deletehash":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
+
+ if [ -n "${auto_delete}" ]; then
+ export -f delete_image
+ echo "Deleting image in ${auto_delete} seconds."
+ nohup /bin/bash -c "sleep ${auto_delete} && delete_image ${imgur_anon_id} ${del_id} ${log_file}" &
+ fi
+
+ handle_upload_success "https://i.imgur.com/${img_id}.${img_ext}" "https://imgur.com/delete/${del_id}" "${1}"
+ else # upload failed
+ err_msg="$(grep -Eo '"error":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
+ test -z "${err_msg}" && err_msg="${response}"
+ handle_upload_error "${err_msg}" "${1}"
+ fi
+}
+
+function upload_anonymous_image() {
+ echo "Uploading '${1}'..."
+ title="$(echo "${1}" | rev | cut -d "/" -f 1 | cut -d "." -f 2- | rev)"
+ if [ -n "${album_id}" ]; then
+ response="$(curl --compressed --connect-timeout "${upload_connect_timeout}" -m "${upload_timeout}" --retry "${upload_retries}" -fsSL --stderr - -H "Authorization: Client-ID ${imgur_anon_id}" -F "title=${title}" -F "image=@\"${1}\"" -F "album=${album_id}" https://api.imgur.com/3/image)"
+ else
+ response="$(curl --compressed --connect-timeout "${upload_connect_timeout}" -m "${upload_timeout}" --retry "${upload_retries}" -fsSL --stderr - -H "Authorization: Client-ID ${imgur_anon_id}" -F "title=${title}" -F "image=@\"${1}\"" https://api.imgur.com/3/image)"
+ fi
+ # JSON parser premium edition (not really)
+ if grep -Eq '"success":\s*true' <<<"${response}"; then
+ img_id="$(grep -Eo '"id":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
+ img_ext="$(grep -Eo '"link":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4 | rev | cut -d "." -f 1 | rev)" # "link" itself has ugly '\/' escaping and no https!
+ del_id="$(grep -Eo '"deletehash":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
+
+ if [ -n "${auto_delete}" ]; then
+ export -f delete_image
+ echo "Deleting image in ${auto_delete} seconds."
+ nohup /bin/bash -c "sleep ${auto_delete} && delete_image ${imgur_anon_id} ${del_id} ${log_file}" &
+ fi
+
+ handle_upload_success "https://i.imgur.com/${img_id}.${img_ext}" "https://imgur.com/delete/${del_id}" "${1}"
+ else # upload failed
+ err_msg="$(grep -Eo '"error":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
+ test -z "${err_msg}" && err_msg="${response}"
+ handle_upload_error "${err_msg}" "${1}"
+ fi
+}
+
+function handle_upload_success() {
+ echo ""
+ echo "image link: ${1}"
+ echo "delete link: ${2}"
+
+ if [ "${copy_url}" = "true" ] && [ -z "${album_title}" ]; then
+ if is_mac; then
+ echo -n "${1}" | pbcopy
+ else
+ echo -n "${1}" | xclip -selection clipboard
+ fi
+ echo "URL copied to clipboard"
+ fi
+
+ # print to log file: image link, image location, delete link
+ echo -e "${1}\t${3}\t${2}" >> "${log_file}"
+
+ notify ok "Upload done!" "${1}"
+
+# if [ ! -z "${open_command}" ] && [ "${open}" = "true" ]; then
+# open_cmd=${open_command//\%url/${1}}
+# open_cmd=${open_cmd//\%img/${2}}
+# echo "Opening '${open_cmd}'"
+# eval "${open_cmd}"
+# fi
+}
+
+function handle_upload_error() {
+ error="Upload failed: \"${1}\""
+ echo "${error}"
+ echo -e "Error\t${2}\t${error}" >> "${log_file}"
+ notify error "Upload failed :(" "${1}"
+}
+
+function handle_album_creation_success() {
+ echo ""
+ echo "Album link: ${1}"
+ echo "Delete hash: ${2}"
+ echo ""
+
+ notify ok "Album created!" "${1}"
+
+ if [ "${copy_url}" = "true" ]; then
+ if is_mac; then
+ echo -n "${1}" | pbcopy
+ else
+ echo -n "${1}" | xclip -selection clipboard
+ fi
+ echo "URL copied to clipboard"
+ fi
+
+ # print to log file: album link, album title, delete hash
+ echo -e "${1}\t\"${3}\"\t${2}" >> "${log_file}"
+}
+
+function handle_album_creation_error() {
+ error="Album creation failed: \"${1}\""
+ echo -e "Error\t${2}\t${error}" >> "${log_file}"
+ notify error "Album creation failed :(" "${1}"
+ if [ ${exit_on_album_creation_fail} ]; then
+ exit 1
+ fi
+}
+
+while [ ${#} != 0 ]; do
+ case "${1}" in
+ -h | --help)
+ echo "usage: ${0} [--debug] [-c | --check | -v | -h | -u]"
+ echo " ${0} [--debug] [option]... [file]..."
+ echo ""
+ echo " --debug Enable debugging, must be first option"
+ echo " -h, --help Show this help, exit"
+ echo " -v, --version Show current version, exit"
+ echo " --check Check if all dependencies are installed, exit"
+ echo " -c, --connect Show connected imgur account, exit"
+ echo " -o, --open <true|false> Override 'open' config"
+ echo " -e, --edit <true|false> Override 'edit' config"
+ echo " -i, --edit-command <command> Override 'edit_command' config (include '%img'), sets --edit 'true'"
+ echo " -l, --login <true|false> Override 'login' config"
+ echo " -a, --album <album_title> Create new album and upload there"
+ echo " -A, --album-id <album_id> Override 'album_id' config"
+ echo " -k, --keep-file <true|false> Override 'keep_file' config"
+ echo " -d, --auto-delete <s> Automatically delete image after <s> seconds"
+ echo " -u, --update Check for updates, exit"
+ echo " file Upload file instead of taking a screenshot"
+ exit 0;;
+ -v | --version)
+ echo "${current_version}"
+ exit 0;;
+ -s | --select)
+ mode="select"
+ shift;;
+ -w | --window)
+ mode="window"
+ shift;;
+ -f | --full)
+ mode="full"
+ shift;;
+ -o | --open)
+ # shellcheck disable=SC2034
+ open="${2}"
+ shift 2;;
+ -e | --edit)
+ edit="${2}"
+ shift 2;;
+ -i | --edit-command)
+ edit_command="${2}"
+ edit="true"
+ shift 2;;
+ -l | --login)
+ login="${2}"
+ shift 2;;
+ -c | --connect)
+ load_access_token
+ fetch_account_info
+ exit 0;;
+ -a | --album)
+ album_title="${2}"
+ shift 2;;
+ -A | --album-id)
+ album_id="${2}"
+ shift 2;;
+ -k | --keep-file)
+ keep_file="${2}"
+ shift 2;;
+ -d | --auto-delete)
+ auto_delete="${2}"
+ shift 2;;
+ -u | --update)
+ check_for_update
+ exit 0;;
+ *)
+ upload_files=("${@}")
+ break;;
+ esac
+done
+
+if [ "${login}" = "true" ]; then
+ # load before changing directory
+ load_access_token
+fi
+
+
+if [ -n "${album_title}" ]; then
+ if [ "${login}" = "true" ]; then
+ response="$(curl -fsSL --stderr - \
+ -F "title=${album_title}" \
+ -H "Authorization: Bearer ${access_token}" \
+ https://api.imgur.com/3/album)"
+ else
+ response="$(curl -fsSL --stderr - \
+ -F "title=${album_title}" \
+ -H "Authorization: Client-ID ${imgur_anon_id}" \
+ https://api.imgur.com/3/album)"
+ fi
+ if grep -Eq '"success":\s*true' <<<"${response}"; then # Album creation successful
+ echo "Album '${album_title}' successfully created"
+ album_id="$(grep -Eo '"id":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
+ del_id="$(grep -Eo '"deletehash":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
+ handle_album_creation_success "https://imgur.com/a/${album_id}" "${del_id}" "${album_title}"
+
+ if [ "${login}" = "false" ]; then
+ album_id="${del_id}"
+ fi
+ else # Album creation failed
+ err_msg="$(grep -Eo '"error":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
+ test -z "${err_msg}" && err_msg="${response}"
+ handle_album_creation_error "${err_msg}" "${album_title}"
+ fi
+fi
+
+if [ -z "${upload_files[*]}" ]; then
+ upload_files[0]=""
+fi
+
+for upload_file in "${upload_files[@]}"; do
+
+ if [ -z "${upload_file}" ]; then
+ cd "${file_dir}" || exit 1
+
+ # new filename with date
+ img_file="$(date +"${file_name_format}")"
+ take_screenshot "${img_file}"
+ else
+ # upload file instead of screenshot
+ img_file="${upload_file}"
+ fi
+
+ # get full path
+ #cd "$(dirname "$(realpath "${img_file}")")"
+ #img_file="$(realpath "${img_file}")"
+
+ # check if file exists
+ if ! [ -f "${img_file}" ]; then
+ echo "file '${img_file}' doesn't exist !"
+ read -r _
+ exit 1
+ fi
+
+ # open image in editor if configured
+ if [ "${edit}" = "true" ]; then
+ edit_cmd=${edit_command//\%img/${img_file}}
+ echo "Opening editor '${edit_cmd}'"
+ if ! (eval "${edit_cmd}"); then
+ echo "Error for image '${img_file}': command '${edit_cmd}' failed, not uploading. For more information visit https://github.com/jomo/imgur-screenshot/wiki/Troubleshooting" | tee -a "${log_file}"
+ notify error "Something went wrong :(" "Information has been logged"
+ exit 1
+ fi
+ fi
+
+ if [ "${login}" = "true" ]; then
+ upload_authenticated_image "${img_file}"
+ else
+ upload_anonymous_image "${img_file}"
+ fi
+
+ # delete file if configured
+ if [ "${keep_file}" = "false" ] && [ -z "${1}" ]; then
+ echo "Deleting temp file ${file_dir}/${img_file}"
+ rm -rf "${img_file}"
+ fi
+
+ echo ""
+done
+
+
+if [ "${check_update}" = "true" ]; then
+ check_for_update
+fi
+
+read -r _
diff --git a/files/.config/nnn/plugins/imgview b/files/.config/nnn/plugins/imgview
new file mode 100755
index 0000000..d8cc247
--- /dev/null
+++ b/files/.config/nnn/plugins/imgview
@@ -0,0 +1,113 @@
+#!/usr/bin/env sh
+
+# Description: Open hovered or current directory in image viewer.
+# Generates media thumbnails with optional dependencies.
+#
+# Dependencies:
+# - imv (https://github.com/eXeC64/imv) or,
+# - sxiv (https://github.com/muennich/sxiv) or,
+# - nsxiv (https://codeberg.org/nsxiv/nsxiv) or,
+# - ucollage (https://github.com/ckardaris/ucollage) or,
+# - lsix (https://github.com/hackerb9/lsix), or
+# - viu (https://github.com/atanunq/viu), or
+# - catimg (https://github.com/posva/catimg), or
+# - optional: ffmpeg for audio thumbnails (album art)
+# - optional: ffmpegthumbnailer for video thumbnails
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana, Luuk van Baal
+#
+# Consider setting NNN_PREVIEWDIR to $XDG_CACHE_HOME/nnn/previews
+# if you want to keep media thumbnails on disk between reboots.
+NNN_PREVIEWDIR="${NNN_PREVIEWDIR:-${TMPDIR:-/tmp}/nnn/previews}"
+
+exit_prompt() {
+ [ -n "$1" ] && printf "%s\n" "$1"
+ printf "%s" "Press any key to exit..."
+ cfg=$(stty -g); stty raw -echo; head -c 1; stty "$cfg"
+ clear
+ exit
+}
+
+make_thumbs() {
+ mkdir -p "$NNN_PREVIEWDIR$dir" || return
+ if [ "$1" = "viu" ] || [ "$1" = "catimg" ]; then
+ [ -d "$target" ] && exit_prompt "$1 can only display a single image"
+ mime="$(file -bL --mime-type -- "$target")"
+ case "$mime" in
+ audio/*) ffmpeg -i "$target" "$NNN_PREVIEWDIR$target.jpg" -y >/dev/null 2>&1
+ ret="$NNN_PREVIEWDIR/$target.jpg" ;;
+ video/*) ffmpegthumbnailer -i "$target" -o "$NNN_PREVIEWDIR$target.jpg" 2> /dev/null
+ ret="$NNN_PREVIEWDIR/$target.jpg" ;;
+ *) ret="$target" ;;
+ esac
+ fi
+ for file in "$dir"/*; do
+ if [ ! -f "$NNN_PREVIEWDIR$file.jpg" ]; then
+ case "$(file -bL --mime-type -- "$file")" in
+ audio/*) [ "$1" != "sxiv" ] &&
+ ffmpeg -i "$file" "$NNN_PREVIEWDIR$file.jpg" -y >/dev/null 2>&1 ;;
+ video/*) [ "$1" != "ucollage" ] &&
+ ffmpegthumbnailer -i "$file" -o "$NNN_PREVIEWDIR$file.jpg" 2> /dev/null ;;
+ esac
+ fi
+ done
+ for file in "$NNN_PREVIEWDIR$dir"/*; do
+ filename="$(basename "$file" .jpg)"
+ [ ! -e "$dir/$filename" ] && rm "$file" 2>/dev/null
+ done
+}
+
+listimages() {
+ find -L "$dir" "$NNN_PREVIEWDIR$dir" -maxdepth 1 -type f -print0 2>/dev/null | sort -z
+}
+
+view_files() {
+ [ -f "$target" ] && count="-n $(listimages | grep -a -m 1 -ZznF "$target" | cut -d: -f1)"
+ case "$1" in
+ nsxiv) listimages | xargs -0 nsxiv -a "${count:--t}" -- ;;
+ sxiv) listimages | xargs -0 sxiv -a "${count:--t}" -- ;;
+ imv*) listimages | xargs -0 "$1" "${count:-}" -- ;;
+ esac
+}
+
+target="$(readlink -f "$1")"
+[ -d "$target" ] && dir="$target" || dir="${target%/*}"
+if uname | grep -q "Darwin"; then
+ [ -f "$1" ] && open "$1" >/dev/null 2>&1 &
+elif type lsix >/dev/null 2>&1; then
+ if [ -d "$target" ]; then
+ cd "$target" || exit_prompt
+ fi
+ make_thumbs lsix
+ clear
+ lsix
+ cd "$NNN_PREVIEWDIR$dir" && lsix
+ exit_prompt
+elif type ucollage >/dev/null 2>&1; then
+ type ffmpeg >/dev/null 2>&1 && make_thumbs ucollage
+ UCOLLAGE_EXPAND_DIRS=1 ucollage "$dir" "$NNN_PREVIEWDIR$dir" || exit_prompt
+elif type sxiv >/dev/null 2>&1; then
+ type ffmpegthumbnailer >/dev/null 2>&1 && make_thumbs sxiv
+ view_files sxiv >/dev/null 2>&1 &
+elif type nsxiv >/dev/null 2>&1; then
+ type ffmpegthumbnailer >/dev/null 2>&1 && make_thumbs sxiv
+ view_files nsxiv >/dev/null 2>&1 &
+elif type imv >/dev/null 2>&1; then
+ make_thumbs imv
+ view_files imv >/dev/null 2>&1 &
+elif type imvr >/dev/null 2>&1; then
+ make_thumbs imv
+ view_files imvr >/dev/null 2>&1 &
+elif type viu >/dev/null 2>&1; then
+ clear
+ make_thumbs viu
+ viu -n "$ret"
+ exit_prompt
+elif type catimg >/dev/null 2>&1; then
+ make_thumbs catimg
+ catimg "$ret"
+ exit_prompt
+else
+ exit_prompt "Please install sxiv/nsxiv/imv/viu/catimg/lsix."
+fi
diff --git a/files/.config/nnn/plugins/ipinfo b/files/.config/nnn/plugins/ipinfo
new file mode 100755
index 0000000..4ff6f41
--- /dev/null
+++ b/files/.config/nnn/plugins/ipinfo
@@ -0,0 +1,13 @@
+#!/usr/bin/env sh
+
+# Description: Shows the external IP address and whois information. Useful over VPNs.
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+IP=$(curl -s ifconfig.me)
+
+whois "$IP"
+echo your external IP address is "$IP"
+
+read -r _
diff --git a/files/.config/nnn/plugins/kdeconnect b/files/.config/nnn/plugins/kdeconnect
new file mode 100755
index 0000000..dea3c2d
--- /dev/null
+++ b/files/.config/nnn/plugins/kdeconnect
@@ -0,0 +1,66 @@
+#!/usr/bin/env sh
+
+# Description: Send files or folders to your Android device using kdeconnect-cli.
+# kdeconnect must be configured on the Android device and the PC.
+#
+# Usage:
+# - Hover over a file or a folder and call the plugin.
+# - Alternatively, select the files and folders you would like to send, and activate the plugin.
+#
+# Shell: POSIX compliant
+# Author: juacq97, raffaem, N-R-K
+
+# If you want system notification, put this equal to 1
+notify=0
+
+note() {
+ if [ $notify = 1 ]; then
+ notify-send -a "Kdeconnect" "$1"
+ else
+ echo "[Kdeconnect] $1"
+ fi
+}
+
+# kdeconnect doesn't cope with non-files
+filter_files() {
+ xargs -0 -I{} sh -c '
+ if [ -f "{}" ]; then
+ printf "%s\0" "{}";
+ else
+ printf "Error: not a regular file: %s\n" "{}" >&2;
+ fi;'
+}
+
+send() {
+ filter_files | xargs -0 -I{} kdeconnect-cli --name "$devname" --share {}
+ note "Files sent"
+}
+
+# Select paired device
+names=$(kdeconnect-cli --list-available --name-only 2>/dev/null)
+if [ -z "$names" ]; then
+ note "No devices paired and available"
+ exit
+fi
+
+ndevs=$(printf "%s" "$names" | awk 'END{print NR}')
+if [ "$ndevs" -eq 1 ]; then
+ devname="$names"
+else
+ printf "%s" "$names" | awk '{ print NR ". " $0 }'
+ printf "Pick a device: "
+ read -r pick
+ if [ -n "$pick" ] && [ "$pick" -eq "$pick" ]; then
+ devname=$(printf '%s' "$names" | awk "NR==$pick")
+ fi
+fi
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+if [ -s "$selection" ]; then
+ send < "$selection"
+ [ -p "$NNN_PIPE" ] && printf "-" > "$NNN_PIPE" # clear selection
+elif [ -n "$1" ]; then
+ printf "%s" "$1" | send
+else
+ note "No selection and no hovered file"
+fi
diff --git a/files/.config/nnn/plugins/launch b/files/.config/nnn/plugins/launch
new file mode 100755
index 0000000..d666cc5
--- /dev/null
+++ b/files/.config/nnn/plugins/launch
@@ -0,0 +1,42 @@
+#!/usr/bin/env sh
+
+# Description: Independent POSIX-compliant GUI application launcher.
+# Fuzzy find executables in $PATH and launch an application.
+# stdin, stdout, stderr are suppressed so CLI tools exit silently.
+#
+# To configure launch as an independent app launcher add a keybind
+# to open launch in a terminal e.g.,
+#
+# xfce4-terminal -e "${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins/launch
+#
+# Dependencies: fzf
+#
+# Usage: launch [delay]
+# delay is in seconds, if omitted launch waits for 1 sec
+#
+# Integration with nnn: launch is installed with other plugins, nnn picks it up.
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+# shellcheck disable=SC2086
+
+IFS=':'
+
+get_selection() {
+ if type fzf >/dev/null 2>&1; then
+ { IFS=':'; ls -H $PATH; } | sort | fzf
+ else
+ exit 1
+ fi
+}
+
+if selection=$( get_selection ); then
+ setsid "$selection" 2>/dev/null 1>/dev/null &
+
+ if [ -n "$1" ]; then
+ sleep "$1"
+ else
+ sleep 1
+ fi
+fi
diff --git a/files/.config/nnn/plugins/mimelist b/files/.config/nnn/plugins/mimelist
new file mode 100755
index 0000000..ccfe05a
--- /dev/null
+++ b/files/.config/nnn/plugins/mimelist
@@ -0,0 +1,15 @@
+#!/usr/bin/env sh
+
+# Description: Find and list files by mime type in smart context
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+# shellcheck disable=SC1090,SC1091
+. "$(dirname "$0")"/.nnn-plugin-helper
+
+printf "mime (e.g., video/audio/image): "
+read -r mime
+
+printf "%s" "+l" > "$NNN_PIPE"
+find . | file -if- | grep "$mime" | awk -F: '{printf "%s\0", $1}' > "$NNN_PIPE"
diff --git a/files/.config/nnn/plugins/moclyrics b/files/.config/nnn/plugins/moclyrics
new file mode 100755
index 0000000..2f69807
--- /dev/null
+++ b/files/.config/nnn/plugins/moclyrics
@@ -0,0 +1,40 @@
+#!/usr/bin/env sh
+
+# Description: Fetches the lyrics of the track currently playing in MOC
+#
+# Dependencies: ddgr (https://github.com/jarun/ddgr)
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+# Check if MOC server is running
+cmd=$(pgrep -x mocp 2>/dev/null)
+ret=$cmd
+if [ -z "$ret" ]; then
+ exit
+fi
+
+# Grab the output
+out="$(mocp -i)"
+
+# Check if anything is playing
+state=$(echo "$out" | grep "State:" | cut -d' ' -f2)
+if ! [ "$state" = 'PLAY' ]; then
+ exit
+fi
+
+# Try by Artist and Song Title first
+ARTIST="$(echo "$out" | grep 'Artist:' | cut -d':' -f2 | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//')"
+TITLE="$(echo "$out" | grep 'SongTitle:' | cut -d':' -f2 | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//')"
+
+if [ -n "$ARTIST" ] && [ -n "$TITLE" ]; then
+ ddgr -w azlyrics.com --ducky "$ARTIST" "$TITLE"
+else
+ # Try by file name
+ FILENAME="$(basename "$(echo "$out" | grep 'File:' | cut -d':' -f2)")"
+ FILENAME="$(echo "${FILENAME%%.*}" | tr -d -)"
+
+ if [ -n "$FILENAME" ]; then
+ ddgr -w azlyrics.com --ducky "$FILENAME"
+ fi
+fi
diff --git a/files/.config/nnn/plugins/mocq b/files/.config/nnn/plugins/mocq
new file mode 100755
index 0000000..038ecc9
--- /dev/null
+++ b/files/.config/nnn/plugins/mocq
@@ -0,0 +1,89 @@
+#!/usr/bin/env sh
+
+# Description: Appends and optionally plays music in MOC
+#
+# Notes:
+# - if selection is available, plays it, else plays the current file or directory
+# - appends tracks and exits is MOC is running, else clears playlist and adds tracks
+# - to let mocp shuffle tracks, set SHUFFLE=1
+#
+# Shell: POSIX compliant
+# Authors: Arun Prakash Jana, ath3
+
+IFS="$(printf '\n\r')"
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+cmd=$(pgrep -x mocp 2>/dev/null)
+ret=$cmd
+
+SHUFFLE="${SHUFFLE:-0}"
+
+mocp_add ()
+{
+ if [ "$SHUFFLE" = 1 ]; then
+ if [ "$resp" = "y" ]; then
+ arr=$(tr '\0' '\n' < "$selection")
+ elif [ -n "$1" ]; then
+ arr="$1"
+ fi
+
+ for entry in $arr
+ do
+ if [ -d "$entry" ]; then
+ arr2=$arr2$(find "$entry" -type f \( ! -iname "*.m3u" ! -iname "*.pls" \))
+ elif echo "$entry" | grep -qv '\.m3u$\|\.pls$' ; then
+ arr2=$(printf "%s\n%s" "$entry" "$arr2")
+ fi
+ done
+
+ mocp -o shuffle
+ echo "$arr2" | xargs -d "\n" mocp -a
+ else
+ if [ "$resp" = "y" ]; then
+ xargs < "$selection" -0 mocp -a
+ else
+ mocp -a "$1"
+ fi
+ fi
+}
+
+if [ ! -s "$selection" ] && [ -z "$1" ]; then
+ exit
+fi
+
+if [ "$2" = "opener" ]; then
+ :
+elif [ -s "$selection" ]; then
+ printf "Work with selection? Enter 'y' to confirm: "
+ read -r resp
+fi
+
+if [ -z "$ret" ]; then
+ # mocp not running
+ mocp -S
+else
+ # mocp running, check if it's playing
+ state=$(mocp -i | grep "State:" | cut -d' ' -f2)
+
+ if [ "$state" = 'PLAY' ]; then
+ # add to playlist and exit
+ mocp_add "$1"
+
+ # uncomment the line below to show mocp interface after appending
+ # mocp
+
+ exit
+ fi
+fi
+
+# clear selection and play
+mocp -c
+mocp_add "$1" "$resp"
+mocp -p
+
+# uncomment the line below to show mocp interface after appending
+# mocp
+
+# Clear selection
+if [ "$resp" = "y" ] && [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+fi
diff --git a/files/.config/nnn/plugins/mp3conv b/files/.config/nnn/plugins/mp3conv
new file mode 100755
index 0000000..029f544
--- /dev/null
+++ b/files/.config/nnn/plugins/mp3conv
@@ -0,0 +1,41 @@
+#!/usr/bin/env sh
+
+# Description: Extract audio from multimedia files and convert to mp3
+#
+# Dependencies: ffmpeg compiled with libmp3lame audio codec support
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+outdir=_mp3files
+
+handle_multimedia() {
+ mime="${1}"
+ file="${2}"
+
+ case "${mime}" in
+ audio/* | video/*)
+ ffmpeg -i "${file}" -vn -codec:a libmp3lame -q:a 2 "${outdir}/${file%.*}.mp3"
+ ;;
+ *)
+ ;;
+ esac
+}
+
+printf "Process 'a'll in directory or 'c'urrent? "
+read -r resp
+
+if [ "$resp" = "a" ]; then
+ if ! [ -e "${outdir}" ]; then
+ mkdir "${outdir}"
+ fi
+
+ for f in *; do
+ if [ -f "${f}" ]; then
+ mimestr="$( file --dereference --brief --mime-type -- "${f}" )"
+ handle_multimedia "${mimestr}" "${f}"
+ fi
+ done
+elif [ "$resp" = "c" ] && [ -f "$1" ]; then
+ ffmpeg -i "${1}" -vn -codec:a libmp3lame -q:a 2 "${1%.*}.mp3"
+fi
diff --git a/files/.config/nnn/plugins/mtpmount b/files/.config/nnn/plugins/mtpmount
new file mode 100755
index 0000000..d6feea0
--- /dev/null
+++ b/files/.config/nnn/plugins/mtpmount
@@ -0,0 +1,76 @@
+#!/usr/bin/env sh
+
+# Description: Toggle mount of MTP device (eg. Android device)
+# 'l' to list mountable devices
+# 'n' integer associated to device to mount
+# 'q'/'Return' exit
+#
+# Dependencies: gvfs-mtp
+#
+# Notes: The MTP device should be mounted at /run/user/$UID/gvfs.
+# Put /run/user/$UID/gvfs to bookmark entries (NNN_BMS) for faster access.
+# Make sure the device is unlocked when mounting.
+#
+# When doing copy-paste into MTP device, you will get an error like this:
+# cp: preserving times for './gambar1.png': Operation not supported
+# That just means the file is copied but timestamp won't be preserved.
+# It's like doing `cp -p localfile.txt file-to-SMB.txt`.
+#
+# Shell: POSIX compliant
+# Author: Benawi Adha
+
+prompt="Device number ('l' to list): "
+
+IFS='
+'
+
+lsmtp () {
+ devs=$(gio mount -li | grep -e 'activation_root' | sed 's/\s*activation_root=//g')
+ c=1
+ printf "Devices list:\n"
+ for i in $devs; do
+ printf "%s %s\\n" "$c" "$i"
+ c=$(( c + 1 ))
+ done
+ echo
+}
+
+lsmtp
+printf "%s" "$prompt"
+read -r input
+
+while [ -n "$input" ]
+do
+ if [ "$input" = "l" ]; then
+ lsmtp
+ elif [ "$input" = "q" ] || [ "$input" -eq 0 ]; then
+ exit
+ elif [ "$input" -le "$(printf '%s\n' "${devs}" | grep -c '^')" ]; then
+ # dev=$(printf "%s\n" "$devs" | cut -d$'\n' -f${input})
+ c=1
+ for i in $devs; do
+ dev=$i
+ if [ "$input" -eq $c ]; then
+ break
+ fi
+ c=$(( c + 1 ))
+ done
+
+ if (gio mount -l | grep '^Mount([1-9]).*'"$dev" ) 1>/dev/null; then
+ if gio mount -u "${dev}"; then
+ printf "%s unmounted\n" "$dev"
+ fi
+ else
+ if gio mount "${dev}"; then
+ printf "%s mounted to /run/user/\$UID/gvfs\n" "$dev"
+ fi
+ fi
+ echo
+ else
+ printf "Invalid input\n"
+ fi
+
+ printf "%s" "$prompt"
+ read -r input
+done
+
diff --git a/files/.config/nnn/plugins/nbak b/files/.config/nnn/plugins/nbak
new file mode 100755
index 0000000..f9cb644
--- /dev/null
+++ b/files/.config/nnn/plugins/nbak
@@ -0,0 +1,75 @@
+#!/usr/bin/env sh
+
+# Description: Backup nnn configuration
+# - config dir content
+# - environment config
+# - shell functions and aliases
+#
+# Shell: POSIX compliant
+# Author: Léo Villeveygoux
+
+nnn_aliases="n nnn"
+
+outdir="nnn-$(whoami)@$(hostname)"
+
+outfile="${outdir}.tar.bz2"
+
+shellname="$(basename "$SHELL")"
+
+conffile="config.txt"
+
+configdir="${XDG_CONFIG_HOME:-$HOME/.config}/nnn"
+
+workdir="$PWD"
+
+tempdir="$(mktemp -d)"
+
+mkdir "$tempdir/$outdir"
+
+if [ ! -d "$tempdir" ]; then
+ echo "Can't create work directory." >&2
+ exit 1
+fi
+
+cd "$tempdir/$outdir" || exit 1
+
+# Backing up config dir content
+cp -r "$configdir" . || exit 1
+
+# Environment config
+env | sed "s/'/'\\\\''/" |\
+ awk '/^NNN_/{print "export '\''"$0"'\''"}' > "$conffile"
+
+# Shell functions/aliases
+case "$shellname" in
+ bash)
+ for name in $nnn_aliases ; do
+ if [ "$(bash -ic "type -t $name")" = "function" ] ; then
+ bash -ic "type $name" | tail -n+2 >> "$conffile"
+ elif bash -ic "alias $name" >/dev/null 2>&1 ; then
+ bash -ic "alias $name" >> "$conffile"
+ fi
+ done
+ ;;
+ zsh)
+ for name in $nnn_aliases ; do
+ if zsh -ic "functions $name" ; then
+ zsh -ic "functions $name" >> "$conffile"
+ elif zsh -ic "alias $name" ; then
+ echo alias "$(zsh -ic "alias $name")" >> "$conffile"
+ fi
+ done
+ ;;
+
+ *)
+ echo "Unknown shell, skipping alias/function checking." >&2
+ ;;
+esac
+
+cd .. || exit 1
+
+printf "Saving as '%s' ... " "$workdir/$outfile"
+
+tar caf "$workdir/$outfile" "$outdir" && echo "Done" || echo "Failed"
+
+cd "$workdir" && rm -rf "$tempdir"
diff --git a/files/.config/nnn/plugins/nmount b/files/.config/nnn/plugins/nmount
new file mode 100755
index 0000000..e05453f
--- /dev/null
+++ b/files/.config/nnn/plugins/nmount
@@ -0,0 +1,88 @@
+#!/usr/bin/env sh
+
+# Description: Toggle mount status of a device using pmount
+# If the device is not mounted, it will be mounted.
+# If the device is mounted, it will be unmounted and powered down.
+#
+# Dependencies: lsblk, pmount (optional), udisks2
+#
+# Usage: Runs `lsblk` on 'l', exits on 'Return`.
+#
+# Notes:
+# - The script uses Linux-specific lsblk to list block devices. Alternatives:
+# macOS: "diskutil list"
+# BSD: "geom disk list"
+# - The script uses udisksctl (from udisks2) to power down devices. This is also Linux-specific.
+# Users on non-Linux platforms can comment it and use an alternative to power-down disks.
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+prompt="device name [e.g. sdXn] ('l'ist, 'q'uit): "
+
+lsblk
+
+printf "\nEnsure you aren't still in the mounted device.\n"
+printf "%s" "$prompt"
+read -r dev
+
+while [ -n "$dev" ]; do
+ if [ "$dev" = "l" ]; then
+ lsblk
+ elif [ "$dev" = "q" ]; then
+ exit
+ else
+ # LUKS volumes mounted with udisksctl appear differently than with pmount
+ if grep -qs "$dev " /proc/mounts || [ -n "$(lsblk -n "/dev/$dev" -o MOUNTPOINT)" ]; then
+ sync "$(lsblk -n "/dev/$dev" -o MOUNTPOINT | sed "/^$/d")"
+ if type pumount >/dev/null 2>&1; then
+ pumount "/dev/$dev"
+ exit_code="$?"
+ else
+ # Unlike pmount, udisksctl does not transparently handle LUKS volumes
+ # We need to manually get the unlocked device, unmount it, and then lock the volume
+ if lsblk -n "/dev/$dev" -o FSTYPE | grep "crypto_LUKS" >/dev/null; then
+ dev_map="$(udisksctl info -b /dev/"$dev" | grep "CleartextDevice" | grep -o "dm_2d[[:digit:]]*" | sed "s/_2d/-/")"
+ udisksctl unmount -b "/dev/$dev_map" --no-user-interaction >/dev/null
+ exit_code="$?"
+ udisksctl lock -b "/dev/$dev" --no-user-interaction >/dev/null
+ else
+ udisksctl unmount -b "/dev/$dev" --no-user-interaction >/dev/null
+ exit_code="$?"
+ fi
+ fi
+ if [ $exit_code -eq 0 ]; then
+ echo "/dev/$dev unmounted."
+ if udisksctl power-off -b "/dev/$dev" --no-user-interaction; then
+ echo "/dev/$dev ejected."
+ fi
+ fi
+ elif [ -b "/dev/$dev" ]; then
+ if type pmount >/dev/null 2>&1; then
+ pmount "/dev/$dev"
+ exit_code="$?"
+ else
+ # Unlike pmount, udisksctl does not transparently handle LUKS volumes
+ # We need to manually get the unlocked device and mount that instead of the volume itself
+ if [ "$(lsblk "/dev/$dev" -n -o FSTYPE)" = "crypto_LUKS" ]; then
+ dev_map=$(udisksctl unlock -b "/dev/$dev" --no-user-interaction | grep -o "dm-[[:digit:]]*")
+ udisksctl mount -b "/dev/$dev_map" --no-user-interaction >/dev/null
+ exit_code="$?"
+ else
+ udisksctl mount -b "/dev/$dev" --no-user-interaction >/dev/null
+ exit_code="$?"
+ fi
+ fi
+ if [ $exit_code -eq 0 ]; then
+ sleep 1
+ echo "/dev/$dev mounted to $(lsblk -n "/dev/$dev" -o MOUNTPOINT | sed "/^$/d")."
+ fi
+ else
+ echo "/dev/$dev does not exist or is not a block device."
+ fi
+ fi
+
+ echo
+ printf "%s" "$prompt"
+ read -r dev
+done
diff --git a/files/.config/nnn/plugins/nuke b/files/.config/nnn/plugins/nuke
new file mode 100755
index 0000000..b3eafc8
--- /dev/null
+++ b/files/.config/nnn/plugins/nuke
@@ -0,0 +1,555 @@
+#!/usr/bin/env sh
+
+# Description: Sample script to play files in apps by file type or mime
+#
+# Shell: POSIX compliant
+# Usage: nuke filepath
+#
+# Integration with nnn:
+# 1. Export the required config:
+# export NNN_OPENER=/absolute/path/to/nuke
+# # Otherwise, if nuke is in $PATH
+# # export NNN_OPENER=nuke
+# 2. Run nnn with the program option to indicate a CLI opener
+# nnn -c
+# # The -c program option overrides option -e
+# 3. nuke can use nnn plugins (e.g. mocq is used for audio), $PATH is updated.
+#
+# Details:
+# Inspired by ranger's scope.sh, modified for usage with nnn.
+#
+# Guards against accidentally opening mime types like executables, shared libs etc.
+#
+# Tries to play 'file' (1st argument) in the following order:
+# 1. by extension
+# 2. by mime (image, video, audio, pdf)
+# 3. by mime (other file types)
+# 4. by mime (prompt and run executables)
+#
+# Modification tips:
+# 1. Invokes CLI utilities by default. Set GUI to 1 to enable GUI apps.
+# 2. PAGER is "less -R".
+# 3. Start GUI apps in bg to unblock. Redirect stdout and strerr if required.
+# 4. Some CLI utilities are piped to the $PAGER, to wait and quit uniformly.
+# 5. If the output cannot be paged use "read -r _" to wait for user input.
+# 6. On a DE, try 'xdg-open' or 'open' in handle_fallback() as last resort.
+#
+# Feel free to change the utilities to your favourites and add more mimes.
+#
+# Defaults:
+# By extension (only the enabled ones):
+# most archives: list with atool, bsdtar
+# rar: list with unrar
+# 7-zip: list with 7z
+# pdf: zathura (GUI), pdftotext, mutool, exiftool
+# audio: mocq (nnn plugin using MOC), mpv, media_client (Haiku), mediainfo, exiftool
+# avi|mkv|mp4: smplayer, mpv (GUI), ffmpegthumbnailer, mediainfo, exiftool
+# log: vi
+# torrent: rtorrent, transmission-show
+# odt|ods|odp|sxw: odt2txt
+# md: glow (https://github.com/charmbracelet/glow), lowdown (https://kristaps.bsd.lv/lowdown)
+# htm|html|xhtml: w3m, lynx, elinks
+# json: jq, python (json.tool module)
+# Multimedia by mime:
+# image/*: imv/sxiv/nsxiv (GUI), viu (https://github.com/atanunq/viu), img2txt, exiftool
+# video/*: smplayer, mpv (GUI), ffmpegthumbnailer, mediainfo, exiftool
+# audio/*: mocq (nnn plugin using MOC), mpv, media_client (Haiku), mediainfo, exiftool
+# application/pdf: zathura (GUI), pdftotext, mutool, exiftool
+# Other mimes:
+# text/troff: man -l
+# text/* | */xml: vi
+# image/vnd.djvu): djvutxt, exiftool
+#
+# TODO:
+# 1. Adapt, test and enable all mimes
+# 2. Clean-up the unnecessary exit codes
+
+# set to 1 to enable GUI apps and/or BIN execution
+GUI="${GUI:-0}"
+BIN="${BIN:-0}"
+
+set -euf -o noclobber -o noglob -o nounset
+IFS="$(printf '%b_' '\n')"; IFS="${IFS%_}" # protect trailing \n
+
+PATH=$PATH:"${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins"
+IMAGE_CACHE_PATH="$(dirname "$1")"/.thumbs
+
+FPATH="$1"
+FNAME=$(basename "$1")
+EDITOR="${VISUAL:-${EDITOR:-vi}}"
+PAGER="${PAGER:-less -R}"
+ext="${FNAME##*.}"
+if [ -n "$ext" ]; then
+ ext="$(printf "%s" "${ext}" | tr '[:upper:]' '[:lower:]')"
+fi
+
+is_mac() {
+ uname | grep -q "Darwin"
+}
+
+handle_pdf() {
+ if [ "$GUI" -ne 0 ]; then
+ if is_mac; then
+ nohup open "${FPATH}" >/dev/null 2>&1 &
+ elif type zathura >/dev/null 2>&1; then
+ nohup zathura "${FPATH}" >/dev/null 2>&1 &
+ else
+ return
+ fi
+ elif type pdftotext >/dev/null 2>&1; then
+ ## Preview as text conversion
+ pdftotext -l 10 -nopgbrk -q -- "${FPATH}" - | eval "$PAGER"
+ elif type mutool >/dev/null 2>&1; then
+ mutool draw -F txt -i -- "${FPATH}" 1-10 | eval "$PAGER"
+ elif type exiftool >/dev/null 2>&1; then
+ exiftool "${FPATH}" | eval "$PAGER"
+ else
+ return
+ fi
+ exit 0
+}
+
+handle_audio() {
+ if type mocp >/dev/null 2>&1 && type mocq >/dev/null 2>&1; then
+ mocq "${FPATH}" "opener" >/dev/null 2>&1
+ elif type mpv >/dev/null 2>&1; then
+ mpv "${FPATH}" >/dev/null 2>&1 &
+ elif type media_client >/dev/null 2>&1; then
+ media_client play "${FPATH}" >/dev/null 2>&1 &
+ elif type mediainfo >/dev/null 2>&1; then
+ mediainfo "${FPATH}" | eval "$PAGER"
+ elif type exiftool >/dev/null 2>&1; then
+ exiftool "${FPATH}"| eval "$PAGER"
+ else
+ return
+ fi
+ exit 0
+}
+
+handle_video() {
+ if [ "$GUI" -ne 0 ]; then
+ if is_mac; then
+ nohup open "${FPATH}" >/dev/null 2>&1 &
+ elif type smplayer >/dev/null 2>&1; then
+ nohup smplayer "${FPATH}" >/dev/null 2>&1 &
+ elif type mpv >/dev/null 2>&1; then
+ nohup mpv "${FPATH}" >/dev/null 2>&1 &
+ else
+ return
+ fi
+ elif type ffmpegthumbnailer >/dev/null 2>&1; then
+ # Thumbnail
+ [ -d "${IMAGE_CACHE_PATH}" ] || mkdir "${IMAGE_CACHE_PATH}"
+ ffmpegthumbnailer -i "${FPATH}" -o "${IMAGE_CACHE_PATH}/${FNAME}.jpg" -s 0
+ viu -n "${IMAGE_CACHE_PATH}/${FNAME}.jpg" | eval "$PAGER"
+ elif type mediainfo >/dev/null 2>&1; then
+ mediainfo "${FPATH}" | eval "$PAGER"
+ elif type exiftool >/dev/null 2>&1; then
+ exiftool "${FPATH}"| eval "$PAGER"
+ else
+ return
+ fi
+ exit 0
+}
+
+# handle this extension and exit
+handle_extension() {
+ case "${ext}" in
+ ## Archive
+ a|ace|alz|arc|arj|bz|bz2|cab|cpio|deb|gz|jar|lha|lz|lzh|lzma|lzo|\
+ rpm|rz|t7z|tar|tbz|tbz2|tgz|tlz|txz|tZ|tzo|war|xpi|xz|Z|zip)
+ if type atool >/dev/null 2>&1; then
+ atool --list -- "${FPATH}" | eval "$PAGER"
+ exit 0
+ elif type bsdtar >/dev/null 2>&1; then
+ bsdtar --list --file "${FPATH}" | eval "$PAGER"
+ exit 0
+ fi
+ exit 1;;
+ rar)
+ if type unrar >/dev/null 2>&1; then
+ ## Avoid password prompt by providing empty password
+ unrar lt -p- -- "${FPATH}" | eval "$PAGER"
+ fi
+ exit 1;;
+ 7z)
+ if type 7z >/dev/null 2>&1; then
+ ## Avoid password prompt by providing empty password
+ 7z l -p -- "${FPATH}" | eval "$PAGER"
+ exit 0
+ fi
+ exit 1;;
+
+ ## PDF
+ pdf)
+ handle_pdf
+ exit 1;;
+
+ ## Audio
+ aac|flac|m4a|mid|midi|mpa|mp2|mp3|ogg|wav|wma)
+ handle_audio
+ exit 1;;
+
+ ## Video
+ avi|mkv|mp4)
+ handle_video
+ exit 1;;
+
+ ## Log files
+ log)
+ "$EDITOR" "${FPATH}"
+ exit 0;;
+
+ ## BitTorrent
+ torrent)
+ if type rtorrent >/dev/null 2>&1; then
+ rtorrent "${FPATH}"
+ exit 0
+ elif type transmission-show >/dev/null 2>&1; then
+ transmission-show -- "${FPATH}"
+ exit 0
+ fi
+ exit 1;;
+
+ ## OpenDocument
+ odt|ods|odp|sxw)
+ if type odt2txt >/dev/null 2>&1; then
+ ## Preview as text conversion
+ odt2txt "${FPATH}" | eval "$PAGER"
+ exit 0
+ fi
+ exit 1;;
+
+ ## Markdown
+ md)
+ if type glow >/dev/null 2>&1; then
+ glow -sdark "${FPATH}" | eval "$PAGER"
+ exit 0
+ elif type lowdown >/dev/null 2>&1; then
+ lowdown -Tterm "${FPATH}" | eval "$PAGER"
+ exit 0
+ fi
+ ;;
+
+ ## HTML
+ htm|html|xhtml)
+ ## Preview as text conversion
+ if type w3m >/dev/null 2>&1; then
+ w3m -dump "${FPATH}" | eval "$PAGER"
+ exit 0
+ elif type lynx >/dev/null 2>&1; then
+ lynx -dump -- "${FPATH}" | eval "$PAGER"
+ exit 0
+ elif type elinks >/dev/null 2>&1; then
+ elinks -dump "${FPATH}" | eval "$PAGER"
+ exit 0
+ fi
+ ;;
+
+ ## JSON
+ json)
+ if type jq >/dev/null 2>&1; then
+ jq --color-output . "${FPATH}" | eval "$PAGER"
+ exit 0
+ elif type python >/dev/null 2>&1; then
+ python -m json.tool -- "${FPATH}" | eval "$PAGER"
+ exit 0
+ fi
+ ;;
+ esac
+}
+
+# sets the variable abs_target, this should be faster than calling printf
+abspath() {
+ case "$1" in
+ /*) abs_target="$1";;
+ *) abs_target="$PWD/$1";;
+ esac
+}
+
+# storing the result to a tmp file is faster than calling listimages twice
+listimages() {
+ find -L "///${1%/*}" -maxdepth 1 -type f -print0 |
+ grep -izZE '\.(jpe?g|png|gif|webp|tiff|bmp|ico|svg)$' |
+ sort -z | tee "$tmp"
+}
+
+load_dir() {
+ abspath "$2"
+ tmp="${TMPDIR:-/tmp}/nuke_$$"
+ trap 'rm -f $tmp' EXIT
+ count="$(listimages "$abs_target" | grep -a -m 1 -ZznF "$abs_target" | cut -d: -f1)"
+
+ if [ -n "$count" ]; then
+ if [ "$GUI" -ne 0 ]; then
+ xargs -0 nohup "$1" -n "$count" -- < "$tmp"
+ else
+ xargs -0 "$1" -n "$count" -- < "$tmp"
+ fi
+ else
+ shift
+ "$1" -- "$@" # fallback
+ fi
+}
+
+handle_multimedia() {
+ ## Size of the preview if there are multiple options or it has to be
+ ## rendered from vector graphics. If the conversion program allows
+ ## specifying only one dimension while keeping the aspect ratio, the width
+ ## will be used.
+ # local DEFAULT_SIZE="1920x1080"
+
+ mimetype="${1}"
+ case "${mimetype}" in
+ ## SVG
+ # image/svg+xml|image/svg)
+ # convert -- "${FPATH}" "${IMAGE_CACHE_PATH}" && exit 6
+ # exit 1;;
+
+ ## DjVu
+ # image/vnd.djvu)
+ # ddjvu -format=tiff -quality=90 -page=1 -size="${DEFAULT_SIZE}" \
+ # - "${IMAGE_CACHE_PATH}" < "${FPATH}" \
+ # && exit 6 || exit 1;;
+
+ ## Image
+ image/*)
+ if [ "$GUI" -ne 0 ]; then
+ if is_mac; then
+ nohup open "${FPATH}" >/dev/null 2>&1 &
+ exit 0
+ elif type imv >/dev/null 2>&1; then
+ load_dir imv "${FPATH}" >/dev/null 2>&1 &
+ exit 0
+ elif type imvr >/dev/null 2>&1; then
+ load_dir imvr "${FPATH}" >/dev/null 2>&1 &
+ exit 0
+ elif type sxiv >/dev/null 2>&1; then
+ load_dir sxiv "${FPATH}" >/dev/null 2>&1 &
+ exit 0
+ elif type nsxiv >/dev/null 2>&1; then
+ load_dir nsxiv "${FPATH}" >/dev/null 2>&1 &
+ exit 0
+ fi
+ elif type viu >/dev/null 2>&1; then
+ viu -n "${FPATH}" | eval "$PAGER"
+ exit 0
+ elif type img2txt >/dev/null 2>&1; then
+ img2txt --gamma=0.6 -- "${FPATH}" | eval "$PAGER"
+ exit 0
+ elif type exiftool >/dev/null 2>&1; then
+ exiftool "${FPATH}" | eval "$PAGER"
+ exit 0
+ fi
+ # local orientation
+ # orientation="$( identify -format '%[EXIF:Orientation]\n' -- "${FPATH}" )"
+ ## If orientation data is present and the image actually
+ ## needs rotating ("1" means no rotation)...
+ # if [[ -n "$orientation" && "$orientation" != 1 ]]; then
+ ## ...auto-rotate the image according to the EXIF data.
+ # convert -- "${FPATH}" -auto-orient "${IMAGE_CACHE_PATH}" && exit 6
+ # fi
+
+ ## `w3mimgdisplay` will be called for all images (unless overridden
+ ## as above), but might fail for unsupported types.
+ exit 7;;
+
+ ## PDF
+ application/pdf)
+ handle_pdf
+ exit 1;;
+
+ ## Audio
+ audio/*)
+ handle_audio
+ exit 1;;
+
+ ## Video
+ video/*)
+ handle_video
+ exit 1;;
+
+ # pdftoppm -f 1 -l 1 \
+ # -scale-to-x "${DEFAULT_SIZE%x*}" \
+ # -scale-to-y -1 \
+ # -singlefile \
+ # -jpeg -tiffcompression jpeg \
+ # -- "${FPATH}" "${IMAGE_CACHE_PATH%.*}" \
+ # && exit 6 || exit 1;;
+
+
+ ## ePub, MOBI, FB2 (using Calibre)
+ # application/epub+zip|application/x-mobipocket-ebook|\
+ # application/x-fictionbook+xml)
+ # # ePub (using https://github.com/marianosimone/epub-thumbnailer)
+ # epub-thumbnailer "${FPATH}" "${IMAGE_CACHE_PATH}" \
+ # "${DEFAULT_SIZE%x*}" && exit 6
+ # ebook-meta --get-cover="${IMAGE_CACHE_PATH}" -- "${FPATH}" \
+ # >/dev/null && exit 6
+ # exit 1;;
+
+ ## Font
+ # application/font*|application/*opentype)
+ # preview_png="/tmp/$(basename "${IMAGE_CACHE_PATH%.*}").png"
+ # if fontimage -o "${preview_png}" \
+ # --pixelsize "120" \
+ # --fontname \
+ # --pixelsize "80" \
+ # --text " ABCDEFGHIJKLMNOPQRSTUVWXYZ " \
+ # --text " abcdefghijklmnopqrstuvwxyz " \
+ # --text " 0123456789.:,;(*!?') ff fl fi ffi ffl " \
+ # --text " The quick brown fox jumps over the lazy dog. " \
+ # "${FPATH}";
+ # then
+ # convert -- "${preview_png}" "${IMAGE_CACHE_PATH}" \
+ # && rm "${preview_png}" \
+ # && exit 6
+ # else
+ # exit 1
+ # fi
+ # ;;
+
+ ## Preview archives using the first image inside.
+ ## (Very useful for comic book collections for example.)
+ # application/zip|application/x-rar|application/x-7z-compressed|\
+ # application/x-xz|application/x-bzip2|application/x-gzip|application/x-tar)
+ # local fn=""; local fe=""
+ # local zip=""; local rar=""; local tar=""; local bsd=""
+ # case "${mimetype}" in
+ # application/zip) zip=1 ;;
+ # application/x-rar) rar=1 ;;
+ # application/x-7z-compressed) ;;
+ # *) tar=1 ;;
+ # esac
+ # { [ "$tar" ] && fn=$(tar --list --file "${FPATH}"); } || \
+ # { fn=$(bsdtar --list --file "${FPATH}") && bsd=1 && tar=""; } || \
+ # { [ "$rar" ] && fn=$(unrar lb -p- -- "${FPATH}"); } || \
+ # { [ "$zip" ] && fn=$(zipinfo -1 -- "${FPATH}"); } || return
+ #
+ # fn=$(echo "$fn" | python -c "import sys; import mimetypes as m; \
+ # [ print(l, end='') for l in sys.stdin if \
+ # (m.guess_type(l[:-1])[0] or '').startswith('image/') ]" |\
+ # sort -V | head -n 1)
+ # [ "$fn" = "" ] && return
+ # [ "$bsd" ] && fn=$(printf '%b' "$fn")
+ #
+ # [ "$tar" ] && tar --extract --to-stdout \
+ # --file "${FPATH}" -- "$fn" > "${IMAGE_CACHE_PATH}" && exit 6
+ # fe=$(echo -n "$fn" | sed 's/[][*?\]/\\\0/g')
+ # [ "$bsd" ] && bsdtar --extract --to-stdout \
+ # --file "${FPATH}" -- "$fe" > "${IMAGE_CACHE_PATH}" && exit 6
+ # [ "$bsd" ] || [ "$tar" ] && rm -- "${IMAGE_CACHE_PATH}"
+ # [ "$rar" ] && unrar p -p- -inul -- "${FPATH}" "$fn" > \
+ # "${IMAGE_CACHE_PATH}" && exit 6
+ # [ "$zip" ] && unzip -pP "" -- "${FPATH}" "$fe" > \
+ # "${IMAGE_CACHE_PATH}" && exit 6
+ # [ "$rar" ] || [ "$zip" ] && rm -- "${IMAGE_CACHE_PATH}"
+ # ;;
+ esac
+}
+
+handle_mime() {
+ mimetype="${1}"
+ case "${mimetype}" in
+ ## Manpages
+ text/troff)
+ man -l "${FPATH}"
+ exit 0;;
+
+ ## Text
+ text/* | */xml)
+ "$EDITOR" "${FPATH}"
+ exit 0;;
+ ## Syntax highlight
+ # if [[ "$( stat --printf='%s' -- "${FPATH}" )" -gt "${HIGHLIGHT_SIZE_MAX}" ]]; then
+ # exit 2
+ # fi
+ # if [[ "$( tput colors )" -ge 256 ]]; then
+ # local pygmentize_format='terminal256'
+ # local highlight_format='xterm256'
+ # else
+ # local pygmentize_format='terminal'
+ # local highlight_format='ansi'
+ # fi
+ # env HIGHLIGHT_OPTIONS="${HIGHLIGHT_OPTIONS}" highlight \
+ # --out-format="${highlight_format}" \
+ # --force -- "${FPATH}" && exit 5
+ # pygmentize -f "${pygmentize_format}" -O "style=${PYGMENTIZE_STYLE}"\
+ # -- "${FPATH}" && exit 5
+ # exit 2;;
+
+ ## DjVu
+ image/vnd.djvu)
+ if type djvutxt >/dev/null 2>&1; then
+ ## Preview as text conversion (requires djvulibre)
+ djvutxt "${FPATH}" | eval "$PAGER"
+ exit 0
+ elif type exiftool >/dev/null 2>&1; then
+ exiftool "${FPATH}" | eval "$PAGER"
+ exit 0
+ fi
+ exit 1;;
+ esac
+}
+
+handle_fallback() {
+ if [ "$GUI" -ne 0 ]; then
+ if type xdg-open >/dev/null 2>&1; then
+ nohup xdg-open "${FPATH}" >/dev/null 2>&1 &
+ exit 0
+ elif type open >/dev/null 2>&1; then
+ nohup open "${FPATH}" >/dev/null 2>&1 &
+ exit 0
+ fi
+ fi
+
+ echo '----- File details -----' && file --dereference --brief -- "${FPATH}"
+ exit 1
+}
+
+handle_blocked() {
+ case "${MIMETYPE}" in
+ application/x-sharedlib)
+ exit 0;;
+
+ application/x-shared-library-la)
+ exit 0;;
+
+ application/x-executable)
+ exit 0;;
+
+ application/x-shellscript)
+ exit 0;;
+
+ application/octet-stream)
+ exit 0;;
+ esac
+}
+
+handle_bin() {
+ case "${MIMETYPE}" in
+ application/x-executable|application/x-shellscript)
+ clear
+ echo '-------- Executable File --------' && file --dereference --brief -- "${FPATH}"
+ printf "Run executable (y/N/'a'rgs)? "
+ read -r answer
+ case "$answer" in
+ [Yy]* ) exec "${FPATH}";;
+ [Aa]* )
+ printf "args: "
+ read -r args
+ exec "${FPATH}" "$args";;
+ [Nn]* ) exit;;
+ esac
+ esac
+}
+
+MIMETYPE="$( file -bL --mime-type -- "${FPATH}" )"
+handle_extension
+handle_multimedia "${MIMETYPE}"
+handle_mime "${MIMETYPE}"
+[ "$BIN" -ne 0 ] && [ -x "${FPATH}" ] && handle_bin
+handle_blocked "${MIMETYPE}"
+handle_fallback
+
+exit 1
diff --git a/files/.config/nnn/plugins/oldbigfile b/files/.config/nnn/plugins/oldbigfile
new file mode 100755
index 0000000..0a21527
--- /dev/null
+++ b/files/.config/nnn/plugins/oldbigfile
@@ -0,0 +1,16 @@
+#!/usr/bin/env sh
+
+# Description: List files bigger than input size by ascending access date.
+#
+# Dependencies: find sort
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+printf "Min file size (MB): "
+read -r size
+
+find . -size +"$size"M -type f -printf '%A+ %s %p\n' | sort
+
+echo "Press any key to exit"
+read -r _
diff --git a/files/.config/nnn/plugins/openall b/files/.config/nnn/plugins/openall
new file mode 100755
index 0000000..5a7941f
--- /dev/null
+++ b/files/.config/nnn/plugins/openall
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+
+# Description: Open selected files in nuke one by one or in oneshot
+#
+# Notes: 1. Opens the hovered file if the selection is empty
+# 2. nuke is the default, set OPENER below for custom
+# 3. Opener is invoked once for each file in a loop
+# 4. Keep pressing "Enter" to open files one by one
+#
+# Shell: bash
+# Author: Arun Prakash Jana
+
+sel=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+OPENER="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins/nuke"
+
+if [ -s "$sel" ]; then
+ targets=()
+ while IFS= read -r -d '' entry || [ -n "$entry" ]; do
+ targets+=( "$entry" )
+ done < "$sel"
+
+ elements=${#targets[@]}
+
+ if (( elements == 1 )); then
+ # If there's only one file selected, open without prompts
+ "$OPENER" "${targets[0]}"
+ else
+ printf "open [A]ll? "
+ read -r all
+
+ for ((index=0; index <= ${#targets[@]}; index++)); do
+ "$OPENER" "${targets[index]}"
+ if [ "$all" != "A" ] && (( index+1 < elements )); then
+ printf "press Enter to open '%s'\n" "${targets[index+1]}"
+ read -r -s -n 1 key
+ if [[ $key != "" ]]; then
+ break
+ fi
+ fi
+ done
+ fi
+
+ # Clear selection
+ if [ -s "$sel" ] && [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+ fi
+elif [ -n "$1" ]; then
+ "$OPENER" "$1"
+fi
diff --git a/files/.config/nnn/plugins/organize b/files/.config/nnn/plugins/organize
new file mode 100755
index 0000000..fb70aaf
--- /dev/null
+++ b/files/.config/nnn/plugins/organize
@@ -0,0 +1,62 @@
+#!/usr/bin/env sh
+
+# Description: Organize files in directories by category
+#
+# Note: This plugin clears the selection as it changes the contents of the current dir
+#
+# Shell: POSIX compliant
+# Author: th3lusive
+
+sel=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+
+organize() {
+ case "$(file -biL "$1")" in
+ *video*)
+ [ ! -d "Videos" ] && mkdir "Videos"
+ mv "$1" "Videos/$1"
+ printf "Moved %s to Videos\n" "$1" ;;
+
+ *audio*) [ ! -d "Audio" ] && mkdir "Audio"
+ mv "$1" "Audio/$1"
+ printf "Moved %s to Audio\n" "$1" ;;
+
+ *image*)
+ [ ! -d "Images" ] && mkdir "Images"
+ mv "$1" "Images/$1"
+ printf "Moved %s to Images\n" "$1" ;;
+
+ *pdf*|*document*|*epub*|*djvu*|*cb*)
+ [ ! -d "Documents" ] && mkdir "Documents"
+ mv "$1" "Documents/$1"
+ printf "Moved %s to Documents\n" "$1" ;;
+
+ *text*)
+ [ ! -d "Plaintext" ] && mkdir "Plaintext"
+ mv "$1" "Plaintext/$1"
+ printf "Moved %s to Plaintext\n" "$1" ;;
+
+ *tar*|*xz*|*compress*|*7z*|*rar*|*zip*)
+ [ ! -d "Archives" ] && mkdir "Archives"
+ mv "$1" "Archives/$1"
+ printf "Moved %s to Archives\n" "$1" ;;
+
+ *binary*)
+ [ ! -d "Binaries" ] && mkdir "Binaries"
+ mv "$1" "Binaries/$1"
+ printf "Moved %s to Binaries\n" "$1" ;;
+ esac
+}
+
+main() {
+ for file in *
+ do
+ [ -f "$file" ] && organize "$file"
+ done
+
+ # Clear selection
+ if [ -s "$sel" ] && [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+ fi
+}
+
+main "$@"
diff --git a/files/.config/nnn/plugins/pdfread b/files/.config/nnn/plugins/pdfread
new file mode 100755
index 0000000..1e889be
--- /dev/null
+++ b/files/.config/nnn/plugins/pdfread
@@ -0,0 +1,30 @@
+#!/usr/bin/env sh
+
+# Description: Read a text or PDF file in British English
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+if [ -n "$1" ]; then
+ tmpf="$(basename "$1")"
+ tmpf="${TMPDIR:-/tmp}"/"${tmpf%.*}"
+
+ if [ "$(head -c 4 "$1")" = "%PDF" ]; then
+ # Convert using pdftotext
+ pdftotext -nopgbrk -layout "$1" - | sed 's/\xe2\x80\x8b//g' > "$tmpf".txt
+
+ pico2wave -w "$tmpf".wav -l en-GB "$(tr '\n' ' ' < "$tmpf".txt)"
+
+ rm "$tmpf".txt
+ else
+ pico2wave -w "$tmpf".wav -l en-GB "$(tr '\n' ' ' < "$1")"
+ fi
+
+ # to jump around and note the time
+ mpv "$tmpf".wav
+
+ # flat read but better quality
+ # play -qV0 "$tmpf".wav treble 2 gain -l 2
+
+ rm "$tmpf".wav
+fi
diff --git a/files/.config/nnn/plugins/preview-tabbed b/files/.config/nnn/plugins/preview-tabbed
new file mode 100755
index 0000000..5235c1e
--- /dev/null
+++ b/files/.config/nnn/plugins/preview-tabbed
@@ -0,0 +1,216 @@
+#!/usr/bin/env bash
+
+# Description: tabbed/xembed based file previewer
+#
+# 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) or,
+# - nsxiv (https://codeberg.org/nsxiv/nsxiv) : xembed client for images
+# - zathura (https://pwmt.org/projects/zathura): xembed client for PDF
+# - nnn's nuke plugin for text preview and fallback
+# nuke is a fallback for 'mpv', 'sxiv'/'nsxiv', and 'zathura', but has its
+# own dependencies, see the script for more information
+# - vim (or any editor/pager really)
+# - file
+# - mktemp
+# - xdotool (optional, to keep main window focused)
+#
+# Usage:
+# - Install the dependencies. Then set a NNN_FIFO
+# and set a key for the plugin, then start `nnn`:
+# $ NNN_FIFO=/tmp/nnn.fifo nnn
+# - Launch the plugin with the designated key from nnn
+#
+# Notes:
+# 1. This plugin needs a "NNN_FIFO" to work. See man.
+# 2. If the same NNN_FIFO is used in multiple nnn instances, there will be one
+# common preview window. With different FIFO paths, they will be independent.
+# 3. This plugin only works on X, not on Wayland.
+#
+# 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`/`nsxiv`: image viewer
+# - `zathura`: PDF viewer
+# - but we always fallback to `nuke` plugin
+#
+# [1]: https://tools.suckless.org/tabbed/
+# [2]: https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html
+#
+# Shell: Bash (job control is weakly specified in POSIX)
+# Author: Léo Villeveygoux
+
+
+XDOTOOL_TIMEOUT=2
+PAGER=${PAGER:-"vim -R"}
+NUKE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins/nuke"
+
+if [ -n "$WAYLAND_DISPLAY" ] ; then
+ echo "Wayland is not supported in preview-tabbed, this plugin could freeze your session!" >&2
+ exit 1
+fi
+
+if type xterm >/dev/null 2>&1 ; then
+ TERMINAL="xterm -into"
+elif type urxvt >/dev/null 2>&1 ; then
+ TERMINAL="urxvt -embed"
+elif type st >/dev/null 2>&1 ; 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 %%)"
+}
+
+kill_viewer () {
+ if [ -n "$VIEWERPID" ] && jobs -p | grep "$VIEWERPID" ; then
+ kill "$VIEWERPID"
+ fi
+}
+
+sigint_kill () {
+ kill_viewer
+ kill "$TABBEDPID"
+ exit 0
+}
+
+previewer_loop () {
+ unset -v NNN_FIFO
+ # mute from now
+ exec >/dev/null 2>&1
+
+ MAINWINDOW="$(xdotool getactivewindow)"
+
+ start_tabbed
+ trap sigint_kill SIGINT
+
+ 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
+
+ kill_viewer
+
+ MIME="$(file -bL --mime-type "$FILE")"
+
+ case "$MIME" in
+ video/*)
+ if type mpv >/dev/null 2>&1 ; then
+ mpv --force-window=immediate --loop-file --wid="$XID" "$FILE" &
+ else
+ term_nuke "$XID" "$FILE"
+ fi
+ ;;
+ audio/*)
+ if type mpv >/dev/null 2>&1 ; then
+ mpv --force-window=immediate --loop-file --wid="$XID" "$FILE" &
+ else
+ term_nuke "$XID" "$FILE"
+ fi
+ ;;
+ image/*)
+ if type sxiv >/dev/null 2>&1 ; then
+ sxiv -ae "$XID" "$FILE" &
+ elif type nsxiv >/dev/null 2>&1 ; then
+ nsxiv -ae "$XID" "$FILE" &
+ else
+ term_nuke "$XID" "$FILE"
+ fi
+ ;;
+ application/pdf)
+ if type zathura >/dev/null 2>&1 ; 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"
+ kill_viewer
+}
+
+if [ ! -r "$NNN_FIFO" ] ; then
+ echo "Can't read \$NNN_FIFO ('$NNN_FIFO')"
+ exit 1
+fi
+
+previewer_loop < "$NNN_FIFO" &
+disown
diff --git a/files/.config/nnn/plugins/pskill b/files/.config/nnn/plugins/pskill
new file mode 100755
index 0000000..e01c739
--- /dev/null
+++ b/files/.config/nnn/plugins/pskill
@@ -0,0 +1,35 @@
+#!/usr/bin/env sh
+
+# Description: Fuzzy list and kill a (zombie) process by name
+#
+# Dependencies: fzf, ps
+#
+# Note: To kill a zombie process enter "zombie"
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+printf "Enter process name ['defunct' for zombies]: "
+read -r psname
+
+# shellcheck disable=SC2009
+if [ -n "$psname" ]; then
+ if type sudo >/dev/null 2>&1; then
+ sucmd=sudo
+ elif type doas >/dev/null 2>&1; then
+ sucmd=doas
+ else
+ sucmd=: # noop
+ fi
+
+ if type fzf >/dev/null 2>&1; then
+ fuzzy=fzf
+ else
+ exit 1
+ fi
+
+ cmd="$(ps -ax | grep -iw "$psname" | "$fuzzy" | sed -e 's/^[ \t]*//' | cut -d' ' -f1)"
+ if [ -n "$cmd" ]; then
+ $sucmd kill -9 "$cmd"
+ fi
+fi
diff --git a/files/.config/nnn/plugins/renamer b/files/.config/nnn/plugins/renamer
new file mode 100755
index 0000000..51c586e
--- /dev/null
+++ b/files/.config/nnn/plugins/renamer
@@ -0,0 +1,45 @@
+#!/usr/bin/env sh
+
+# Description: Batch rename selection or current directory with qmv or vidir
+#
+# Notes:
+# - Try to mimic current batch rename functionality but with correct
+# handling of edge cases by qmv or vidir.
+# - Qmv opens with hidden files if no selection is used. Selected
+# directories are shown.
+# - Vidir don't show directories nor hidden files.
+#
+# Shell: POSIX compliant
+# Author: José Neder
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+
+if type qmv >/dev/null 2>&1; then
+ batchrenamesel="qmv -fdo -da"
+ batchrename="qmv -fdo -a"
+elif type vidir >/dev/null 2>&1; then
+ batchrenamesel="vidir"
+ batchrename="vidir"
+else
+ printf "there is not batchrename program installed."
+ exit
+fi
+
+if [ -s "$selection" ]; then
+ printf "rename selection? "
+ read -r resp
+fi
+
+if [ "$resp" = "y" ]; then
+ # -o flag is necessary for interactive editors
+ xargs -o -0 $batchrenamesel < "$selection"
+
+ # Clear selection
+ if [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+ fi
+elif [ ! "$(LC_ALL=C ls -a)" = ".
+.." ]; then
+ # On older systems that don't have ls -A
+ $batchrename
+fi
diff --git a/files/.config/nnn/plugins/ringtone b/files/.config/nnn/plugins/ringtone
new file mode 100755
index 0000000..c18f255
--- /dev/null
+++ b/files/.config/nnn/plugins/ringtone
@@ -0,0 +1,36 @@
+#!/usr/bin/env sh
+
+# Description: Create an mp3 ringtone out of an audio file in any format
+# Needs user to provide start and end where to cut the file
+# Input file audio.ext results in audio_ringtone.mp3
+#
+# Tip: To convert a complete media file, set start as 0 and
+# the runtime of the file as end.
+#
+# Dependencies: date, ffmpeg
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+if [ -n "$1" ]; then
+ printf "start (hh:mm:ss): "
+ read -r start
+ st=$(date -d "$start" +%s) || exit 1
+
+ printf "end (hh:mm:ss): "
+ read -r end
+ et=$(date -d "$end" +%s) || exit 1
+
+ if [ "$st" -ge "$et" ]; then
+ printf "error: start >= end "
+ read -r _
+ exit 1
+ fi
+
+ interval=$(( et - st ))
+
+ outfile=$(basename "$1")
+ outfile="${outfile%.*}"_ringtone.mp3
+
+ ffmpeg -i "$1" -ss "$start" -t "$interval" -vn -sn -acodec libmp3lame -q:a 2 "$outfile"
+fi
diff --git a/files/.config/nnn/plugins/rsynccp b/files/.config/nnn/plugins/rsynccp
new file mode 100755
index 0000000..902f9e7
--- /dev/null
+++ b/files/.config/nnn/plugins/rsynccp
@@ -0,0 +1,26 @@
+#!/usr/bin/env sh
+
+# Description: Simple script to give copy-paste a progress percentage
+# by utilizing rsync.
+#
+# LIMITATION: this won't work when pasting to MTP device.
+#
+# Dependencies: rsync
+#
+# Shell: POSIX compliant
+# Author: Benawi Adha
+
+sel=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+
+# Choose one of these two schemes by commenting
+
+# more verbose
+xargs -0 -I % rsync -ah --progress % "$PWD" < "$sel"
+
+# less verbose
+# xargs -0 -I % rsync -ah --info=progress2 % "$PWD" < "$sel"
+
+# Clear selection
+if [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+fi
diff --git a/files/.config/nnn/plugins/splitjoin b/files/.config/nnn/plugins/splitjoin
new file mode 100755
index 0000000..ec30dd6
--- /dev/null
+++ b/files/.config/nnn/plugins/splitjoin
@@ -0,0 +1,52 @@
+#!/usr/bin/env sh
+
+# Description: Splits the file passed as argument or joins selection
+#
+# Note: Adds numeric suffix to split files
+# Adds '.out suffix to the first file to be joined and saves as output file for join
+#
+# Shell: POSIX compliant
+# Authors: Arun Prakash Jana, ath3
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+resp=s
+
+if [ -s "$selection" ]; then
+ printf "press 's' (split current file) or 'j' (join selection): "
+ read -r resp
+fi
+
+if [ "$resp" = "j" ]; then
+ if [ -s "$selection" ]; then
+ arr=$(tr '\0' '\n' < "$selection")
+ if [ "$(echo "$arr" | wc -l)" -lt 2 ]; then
+ echo "joining needs at least 2 files"
+ exit
+ fi
+ for entry in $arr
+ do
+ if [ -d "$entry" ]; then
+ echo "can't join directories"
+ exit
+ fi
+ done
+
+ file="$(basename "$(echo "$arr" | sed -n '1p' | sed -e 's/[0-9][0-9]$//')")"
+ sort -z < "$selection" | xargs -0 -I{} cat {} > "${file}.out"
+
+ # Clear selection
+ if [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+ fi
+ fi
+elif [ "$resp" = "s" ]; then
+ if [ -n "$1" ] && [ -f "$1" ]; then
+ # a single file is passed
+ printf "split size in MB: "
+ read -r size
+
+ if [ -n "$size" ]; then
+ split -d -b "$size"M "$1" "$1"
+ fi
+ fi
+fi
diff --git a/files/.config/nnn/plugins/suedit b/files/.config/nnn/plugins/suedit
new file mode 100755
index 0000000..21dddf4
--- /dev/null
+++ b/files/.config/nnn/plugins/suedit
@@ -0,0 +1,16 @@
+#!/usr/bin/env sh
+
+# Description: Edit file as superuser
+#
+# Shell: POSIX compliant
+# Author: Anna Arad
+
+EDITOR="${EDITOR:-vim}"
+
+if type sudo >/dev/null 2>&1; then
+ sudo -E "$EDITOR" "$1"
+elif type sudoedit >/dev/null 2>&1; then
+ sudoedit -E "$1"
+elif type doas >/dev/null 2>&1; then
+ doas "$EDITOR" "$1"
+fi
diff --git a/files/.config/nnn/plugins/togglex b/files/.config/nnn/plugins/togglex
new file mode 100755
index 0000000..e42d65a
--- /dev/null
+++ b/files/.config/nnn/plugins/togglex
@@ -0,0 +1,21 @@
+#!/usr/bin/env sh
+
+# Description: Toggles executable mode for selection
+#
+# Dependencies: chmod
+#
+# Note: Works _only_ with selection (nnn can toggle the mode for the hovered file)
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+
+if [ -s "$selection" ]; then
+ xargs -0 -I {} sh -c 'if [ -x "{}" ] ; then chmod -x "{}" ; else chmod +x "{}" ; fi' < "$selection"
+
+ # Clear selection
+ if [ -p "$NNN_PIPE" ]; then
+ printf "-" > "$NNN_PIPE"
+ fi
+fi
diff --git a/files/.config/nnn/plugins/umounttree b/files/.config/nnn/plugins/umounttree
new file mode 100755
index 0000000..011d74d
--- /dev/null
+++ b/files/.config/nnn/plugins/umounttree
@@ -0,0 +1,52 @@
+#!/usr/bin/env sh
+
+# Description: Autodetects a nnn remote mountpoint (mounted with `c`)
+# from any of its subfolders and allows unmounting it
+# from the subdir without navigating to the mountppoint
+# or entering the remote name. Also works when hovering
+# the mountpoint directly like vanilla `u`.
+#
+# Dependencies: fusermount
+#
+# Shell: POSIX compliant
+# Authors: Kabouik & 0xACE
+#
+# TODO:
+# - Avoid lazy unmount by forcing nnn context to leave the subfolder before fusermount.
+# Tried `printf "%s" "0c$m" > "$NNN_PIPE"` but it breaks the nnn interface, see #854.
+
+err=0
+m=$HOME/.config/nnn/mounts
+if [ "$PWD" = "$m" ]; then
+ # Allow running the script on hovered directory if user is in ~/.config/nnn/mounts
+ d="$1"
+else
+ d=$(dirname "$(readlink -f "$1")" | grep -oP "^$m\K.*" | cut -d"/" -f2)
+fi
+
+# Test if user is within $m or a subdir, abort if not
+if [ "$d" = "" ]; then
+ clear && printf "You are not in a remote folder mounted with nnn. Press return to continue. " && read -r _
+else
+ # Test if $m/$d is a mountpoint and try unmounting if it is
+ mountpoint -q -- "$m/$d"
+ if [ "$?" -eq "1" ]; then
+ clear && printf "Parent '%s' is not a mountpoint. Press return to continue. " "$d" && read -r _
+ else
+ cd "$m" && fusermount -uq "$m/$d" || err=1
+ if [ "$err" -eq "0" ]; then
+ rmdir "$m/$d" && clear && printf "Parent '%s' unmounted." "$d"
+ else
+ clear && printf "Failed to unmount. Try lazy unmount? [Yy/Nn] " && read -r
+ fi
+ fi
+fi
+
+# If unmount fails, offer lazy unmount
+if [ "$REPLY" = "y" ] || [ "$REPLY" = "Y" ]; then
+ err=0
+ cd "$m" && fusermount -uqz "$m/$d" || err=1
+ if [ "$err" -eq "0" ]; then
+ rmdir "$m/$d" && clear && printf "Parent '%s' unmounted with lazy unmount. " "$d"
+ fi
+fi
diff --git a/files/.config/nnn/plugins/upload b/files/.config/nnn/plugins/upload
new file mode 100755
index 0000000..4948587
--- /dev/null
+++ b/files/.config/nnn/plugins/upload
@@ -0,0 +1,45 @@
+#!/usr/bin/env sh
+
+# Description: Selections are uploaded using Firefox Send
+# For single files:
+# Upload to Firefox Send if ffsend is found, else
+# Paste contents of a text a file http://ix.io
+# Upload a binary file to file.io
+#
+# Dependencies: ffsend (https://github.com/timvisee/ffsend), curl, jq, tr
+#
+# Note: Binary file set to expire after a week
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+if [ -s "$selection" ]; then
+ if type ffsend >/dev/null 2>&1; then
+ # File name will be randomized foo.tar
+ xargs -0 < "$selection" ffsend u
+ else
+ printf "ffsend is required to upload selection."
+ fi
+
+ # Clear selection
+ printf "-" > "$NNN_PIPE"
+else
+ if [ -n "$1" ] && [ -s "$1" ]; then
+ if type ffsend >/dev/null 2>&1; then
+ ffsend -fiq u "$1"
+ elif [ "$(mimetype --output-format %m "$1" | awk -F '/' '{print $1}')" = "text" ]; then
+ curl -F "f:1=@$1" ix.io
+ else
+ # Upload the file, show the download link and wait till user presses any key
+ curl -s -F "file=@$1" https://file.io/?expires=1w | jq '.link' | tr -d '"'
+
+ # To write download link to "$1".loc and exit
+ # curl -s -F "file=@$1" https://file.io/?expires=1w -o `basename "$1"`.loc
+ fi
+ else
+ printf "empty file!"
+ fi
+fi
+
+read -r _
diff --git a/files/.config/nnn/plugins/wallpaper b/files/.config/nnn/plugins/wallpaper
new file mode 100755
index 0000000..2017fbd
--- /dev/null
+++ b/files/.config/nnn/plugins/wallpaper
@@ -0,0 +1,37 @@
+#!/usr/bin/env sh
+
+# Description: Set the selected image as wallpaper.
+# Uses nitrogen or pywal on X11, swww on wayland.
+#
+# Usage: Hover on an image and run the script to set it as wallpaper.
+#
+# Shell: POSIX compliant
+# Author: juacq97
+
+if [ -n "$1" ]; then
+ if [ "$(file --mime-type "$1" | awk '{print $NF}' | awk -F '/' '{print $1}')" = "image" ]; then
+ if [ "$XDG_SESSION_TYPE" = "x11" ]; then
+ if type nitrogen >/dev/null 2>&1; then
+ nitrogen --set-zoom-fill --save "$1"
+ elif type wal >/dev/null 2>&1; then
+ wal -i "$1"
+ else
+ printf "nitrogen or pywal missing"
+ read -r _
+ fi
+ else
+ if type swww >/dev/null 2>&1; then
+ swww img "$1"
+ else
+ printf "swww missing"
+ read -r _
+ fi
+ fi
+
+ # If you want a system notification, uncomment the next 3 lines.
+ # notify-send -a "nnn" "Wallpaper changed!"
+ # else
+ # notify-send -a "nnn" "No image selected"
+
+ fi
+fi
diff --git a/files/.config/nnn/plugins/x2sel b/files/.config/nnn/plugins/x2sel
new file mode 100755
index 0000000..95414fc
--- /dev/null
+++ b/files/.config/nnn/plugins/x2sel
@@ -0,0 +1,62 @@
+#!/usr/bin/env sh
+
+# Description: Copy system clipboard newline-separated file list to selection
+#
+# Dependencies:
+# - tr
+# - xclip/xsel (Linux)
+# - pbpaste (macOS)
+# - termux-clipboard-get (Termux)
+# - powershell (WSL)
+# - cygwim's /dev/clipboard (Cygwin)
+# - wl-paste (Wayland)
+# - clipboard (Haiku)
+#
+# Note:
+# - Limitation: breaks if a filename has newline in it
+#
+# Shell: POSIX compliant
+# Author: Léo Villeveygoux, after Arun Prakash Jana's .cbcp
+
+IFS="$(printf '%b_' '\n')"; IFS="${IFS%_}" # protect trailing \n
+
+selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
+
+getclip () {
+ if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
+ # Wayland
+ wl-paste
+ elif type xsel >/dev/null 2>&1; then
+ # Linux
+ xsel -bo
+ elif type xclip >/dev/null 2>&1; then
+ # Linux
+ xclip -sel clip -o
+ elif type pbpaste >/dev/null 2>&1; then
+ # macOS
+ pbpaste
+ elif type termux-clipboard-get >/dev/null 2>&1; then
+ # Termux
+ termux-clipboard-get
+ elif type powershell.exe >/dev/null 2>&1; then
+ # WSL
+ powershell.exe Get-Clipboard
+ elif [ -r /dev/clipboard ] ; then
+ # Cygwin
+ cat /dev/clipboard
+ elif type clipboard >/dev/null 2>&1; then
+ # Haiku
+ clipboard --print
+ fi
+}
+
+CLIPBOARD=$(getclip)
+
+# Check if clipboard actually contains a file list
+for file in $CLIPBOARD ; do
+ if [ ! -e "$file" ] ; then
+ exit 1;
+ fi
+done
+
+printf "%s" "$CLIPBOARD" | tr '\n' '\0' > "$selection"
diff --git a/files/.config/nnn/plugins/xdgdefault b/files/.config/nnn/plugins/xdgdefault
new file mode 100755
index 0000000..cf64a2f
--- /dev/null
+++ b/files/.config/nnn/plugins/xdgdefault
@@ -0,0 +1,53 @@
+#!/usr/bin/env sh
+
+# Description: Sets the xdg-open's default application for the current entry's file
+# type. ${XDG_DATA_DIRS} and ${XDG_DATA_HOME} are set to the recommended
+# defaults if unset, as specified in XDG Base Directory Specification
+# - http://specifications.freedesktop.org/basedir-spec/.
+#
+# Dependencies: xdg-utils, fzf or dmenu (GUI)
+#
+# Shell: POSIX compliant
+# Author: lwnctd
+
+# set to 1 to enable GUI apps
+GUI="${GUI:-0}"
+
+if [ "$GUI" -ne 0 ] && command -v dmenu > /dev/null 2>& 1; then
+ menu="dmenu -i -l 7"
+elif command -v fzf > /dev/null 2>& 1; then
+ menu="fzf -e --tiebreak=begin"
+fi
+
+if [ -z "$1" ] || [ -z "$menu" ] > /dev/null 2>& 1; then
+ exit 1
+fi
+
+ftype=$(xdg-mime query filetype "$2/$1")
+
+if [ -z "$ftype" ]; then
+ exit 1
+fi
+
+dirs=${XDG_DATA_DIRS:-/usr/local/share:/usr/share}
+dirs=${dirs}:${XDG_DATA_HOME:-$HOME/.local/share}:
+
+while [ -n "$dirs" ]; do
+ d=${dirs%%:*}
+ if [ -n "$d" ] && [ -d "$d"/applications ]; then
+ set -- "$@" "$d"/applications
+ fi
+ dirs=${dirs#*:}
+done
+
+app=$(find "$@" -iname '*.desktop' -exec grep '^Name=' {} + \
+ | sort -u -t ':' -k 1,1 \
+ | sed -e 's;..*/\(..*desktop\):Name=\(..*\);\2:\1;' \
+ | sort -t ':' -k 1,1 \
+ | column -t -s ':' -o "$(printf '\t')" \
+ | $menu \
+ | cut -f 2)
+
+if [ -n "$app" ]; then
+ xdg-mime default "${app%%[[:blank:]]*}" "$ftype"
+fi