license: BSD 2-Clause
summary: The missing terminal file manager for X.
homepage: https://github.com/jarun/nnn
commands:
install:
- make PREFIX="/usr" strip install DESTDIR="${BP_DESTDIR}"
packages:
archlinux:
builddeps:
- make
- gcc
- pkg-config
deps:
- ncurses
- readline
container: "archlinux/base"
centos7.5:
builddeps:
- make
- gcc
- pkgconfig
- ncurses-devel
- readline-devel
deps:
- ncurses
- readline
commands:
pre:
- yum install epel-release
centos7.6:
builddeps:
- make
- gcc
- pkgconfig
- ncurses-devel
- readline-devel
deps:
- ncurses
- readline
commands:
pre:
- yum install epel-release
centos8.0:
builddeps:
- make
- gcc
- pkgconfig
- ncurses-devel
- readline-devel
deps:
- ncurses
- readline
commands:
pre:
- yum install epel-release
debian9:
builddeps:
- make
- gcc
- pkg-config
- libncursesw5-dev
- libreadline-dev
deps:
- libncursesw5
- readline-common
debian10:
builddeps:
- make
- gcc
- pkg-config
- libncursesw5-dev
- libreadline-dev
deps:
- libncursesw5
- readline-common
fedora29:
builddeps:
- make
- gcc
- pkg-config
- ncurses-devel
- readline-devel
deps:
- ncurses
- readline
fedora30:
builddeps:
- make
- gcc
- pkg-config
- ncurses-devel
- readline-devel
deps:
- ncurses
- readline
fedora31:
builddeps:
- make
- gcc
- pkg-config
- ncurses-devel
- readline-devel
deps:
- ncurses
- readline
opensuse15.1:
builddeps:
- make
- gcc
- pkg-config
- readline-devel
- ncurses-devel
deps:
- libncurses6
- libreadline7
ubuntu16.04:
builddeps:
- make
- gcc
- pkg-config
- libncursesw5-dev
- libreadline6-dev
deps:
- libncursesw5
- libreadline6
ubuntu18.04:
builddeps:
- make
- gcc
- pkg-config
- libncursesw5-dev
- libreadline-dev
deps:
- libncursesw5
- libreadline7
nnn-3.0/misc/quitcd/ 0000775 0000000 0000000 00000000000 13620656057 0014403 5 ustar 00root root 0000000 0000000 nnn-3.0/misc/quitcd/quitcd.bash 0000664 0000000 0000000 00000001431 13620656057 0016532 0 ustar 00root root 0000000 0000000 n ()
{
# Block nesting of nnn in subshells
if [ -n $NNNLVL ] && [ "${NNNLVL:-0}" -ge 1 ]; then
echo "nnn is already running"
return
fi
# The default behaviour is to cd on quit (nnn checks if NNN_TMPFILE is set)
# To cd on quit only on ^G, remove the "export" as in:
# NNN_TMPFILE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.lastd"
# NOTE: NNN_TMPFILE is fixed, should not be modified
export NNN_TMPFILE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.lastd"
# Unmask ^Q (, ^V etc.) (if required, see `stty -a`) to Quit nnn
# stty start undef
# stty stop undef
# stty lwrap undef
# stty lnext undef
nnn "$@"
if [ -f "$NNN_TMPFILE" ]; then
. "$NNN_TMPFILE"
rm -f "$NNN_TMPFILE" > /dev/null
fi
}
nnn-3.0/misc/quitcd/quitcd.csh 0000664 0000000 0000000 00000000771 13620656057 0016400 0 ustar 00root root 0000000 0000000 # NOTE: set NNN_TMPFILE correctly if you use 'XDG_CONFIG_HOME'
# The default behaviour is to cd on quit (nnn checks if NNN_TMPFILE is set)
# To cd on quit only on ^G, export NNN_TMPFILE after the call to nnn
# NOTE: NNN_TMPFILE is fixed, should not be modified
set NNN_TMPFILE=~/.config/nnn/.lastd
# Unmask ^Q (, ^V etc.) (if required, see `stty -a`) to Quit nnn
# stty start undef
# stty stop undef
# stty lwrap undef
# stty lnext undef
alias n 'nnn -fis; source "$NNN_TMPFILE"; rm -f "$NNN_TMPFILE"'
nnn-3.0/misc/quitcd/quitcd.fish 0000664 0000000 0000000 00000002053 13620656057 0016547 0 ustar 00root root 0000000 0000000 # Rename this file to match the name of the function
# e.g. ~/.config/fish/functions/n.fish
# or, add the lines to the 'config.fish' file.
function n --description 'support nnn quit and change directory'
# Block nesting of nnn in subshells
if test -n NNNLVL
if [ (expr $NNNLVL + 0) -ge 1 ]
echo "nnn is already running"
return
end
end
# The default behaviour is to cd on quit (nnn checks if NNN_TMPFILE is set)
# To cd on quit only on ^G, remove the "-x" as in:
# set NNN_TMPFILE "$XDG_CONFIG_HOME/nnn/.lastd"
# NOTE: NNN_TMPFILE is fixed, should not be modified
if test -n "$XDG_CONFIG_HOME"
set -x NNN_TMPFILE "$XDG_CONFIG_HOME/nnn/.lastd"
else
set -x NNN_TMPFILE "$HOME/.config/nnn/.lastd"
end
# Unmask ^Q (, ^V etc.) (if required, see `stty -a`) to Quit nnn
# stty start undef
# stty stop undef
# stty lwrap undef
# stty lnext undef
nnn $argv
if test -e $NNN_TMPFILE
source $NNN_TMPFILE
rm $NNN_TMPFILE
end
end
nnn-3.0/misc/quitcd/quitcd.zsh 0000664 0000000 0000000 00000001431 13620656057 0016421 0 ustar 00root root 0000000 0000000 n ()
{
# Block nesting of nnn in subshells
if [ -n $NNNLVL ] && [ "${NNNLVL:-0}" -ge 1 ]; then
echo "nnn is already running"
return
fi
# The default behaviour is to cd on quit (nnn checks if NNN_TMPFILE is set)
# To cd on quit only on ^G, remove the "export" as in:
# NNN_TMPFILE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.lastd"
# NOTE: NNN_TMPFILE is fixed, should not be modified
export NNN_TMPFILE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.lastd"
# Unmask ^Q (, ^V etc.) (if required, see `stty -a`) to Quit nnn
# stty start undef
# stty stop undef
# stty lwrap undef
# stty lnext undef
nnn "$@"
if [ -f "$NNN_TMPFILE" ]; then
. "$NNN_TMPFILE"
rm -f "$NNN_TMPFILE" > /dev/null
fi
}
nnn-3.0/misc/test/ 0000775 0000000 0000000 00000000000 13620656057 0014071 5 ustar 00root root 0000000 0000000 nnn-3.0/misc/test/mktest.sh 0000775 0000000 0000000 00000007153 13620656057 0015745 0 ustar 00root root 0000000 0000000 #!/bin/sh
# Create test files and directories
test -e outdir && {
echo "Remove 'outdir' and try again"
exit 1
}
mkdir -p outdir && cd outdir || exit 1
echo 'It works!' > normal.txt
echo 'Με δουλέβει;' > 'κοινό.txt'
ln -sf normal.txt ln-normal.txt
ln -sf normal.txt ln-normal
mkdir -p normal-dir
ln -sf normal-dir ln-normal-dir
ln -sf nowhere ln-nowhere
mkfifo mk-fifo
touch no-access && chmod 000 no-access
mkdir -p no-access-dir && chmod 000 no-access-dir
ln -sf ../normal.txt normal-dir/ln-normal.txt
ln -sf ../normal.txt normal-dir/ln-normal
echo 'int main(void) { *((char *)0) = 0; }' > ill.c
make ill > /dev/null
echo 'test/ill' > ill.sh
mkdir -p empty-dir
mkdir -p cage
echo 'chmod 000 test/cage' > cage/lock.sh
echo 'chmod 755 test/cage' > cage-unlock.sh
mkdir -p cage/lion
echo 'chmod 000 test/cage' > cage/lion/lock.sh
mkdir -p korean
touch 'korean/[ENG sub] PRODUCE48 울림ㅣ김채원ㅣ행복 나눠주는 천사소녀 @자기소개_1분 PR 180615 EP.0-Cgnmr6Fd82'
touch 'korean/[ENG sub] PRODUCE48 [48스페셜] 윙크요정, 내꺼야!ㅣ김채원(울림) 180615 EP.0-K7ulTiuJZK8.mp4'
touch 'korean/[FULL ENG SUB] 181008 SALEWA x IZ_ONE Long Padding Photoshoot Behind Film-[오늘의 시구] 아이즈원 (IZONE) 장원영&미야와키 사쿠라! 시구 시타! (10.06)-VmDl5eBJ3x0.mkv'
touch 'korean/IZ_ONE (아이즈원) - 1st Mini Album [COLOR_IZ] Highlight Medley-w9V2xFrYIgk.web'
touch 'korean/IZ_ONE (아이즈원) - 1st Mini Album [COLOR_IZ] MV TEASER 1-uhnJLBNBNto.mkv'
touch 'korean/IZ_ONE CHU [1회] ′순도 100%′ 우리즈원 숙소 생활 ★최초 공개★ 181025 EP.1-pcutrQN1Sbg.mkv'
touch 'korean/IZ_ONE CHU [1회_예고] 아이즈원 데뷔 준비 과정 ★독점 공개★ 아이즈원 츄 이번주 (목) 밤 11시 첫방송 181025'
touch 'korean/IZ_ONE CHU [1회] 도치기현 1호 이모 팬과의 만남! 181025 EP.1-5kYoReT5x44.mp4'
touch 'korean/IZ_ONE CHU [1회] ′12명 소녀들의 새로운 시작′ 앞으로 아이즈원 잘 부탁해♥ 181025 EP.1-RVNvgbdLQLQ'
touch 'korean/IZ_ONE CHU [1회] ′앗..그것만은!′ 자비없는 합숙생활 폭로전 181025 EP.1-AmP5KzpoI38.mkv'
touch 'korean/IZ_ONE CHU [1회] 휴게소 간식 내기 노래 맞히기 게임 181025 EP.1-LyNDKflpWYE.mp4'
touch 'korean/IZ_ONE CHU [1회] 2018 아이즈원 걸크러시능력시험 (feat. 치타쌤) 181025 EP.1-9qHWpbo0eB8.mp4'
touch 'korean/IZ_ONE CHU [1회] ′돼지요′ 아니죠, ′되지요′ 맞습니다! (feat. 꾸라먹방) 181025EP.1-WDLFqMWiKn'
touch 'korean/IZ_ONE CHU [1회] ′두근두근′ 첫 MT를 앞둔 비글력 만렙의 아이즈원 181025 EP.1'
mkdir -p unicode
touch 'unicode/Malgudi Days - मालगुडी डेज - E05. Swami and Friends - स्वामी और उसके दोस्त (Part 1)'
touch 'unicode/Malgudi Days - मालगुडी डेज - E05. Swami and Friends - स्वामी और उसके दोस्त (Part 2)'
touch 'unicode/Malgudi Days - मालगुडी डेज - E05. Swami and Friends - स्वामी और उसके दोस्त (Part 3)'
chmod +x 'unicode/Malgudi Days - मालगुडी डेज - E05. Swami and Friends - स्वामी और उसके दोस्त (Part 2)'
touch 'unicode/Führer'
touch 'unicode/Eso eso aamar ghare eso ♫ এসো এসো আমার ঘরে এসো ♫ Swagatalakshmi Dasgupta'
touch 'max_chars_filename_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
nnn-3.0/nnn.1 0000664 0000000 0000000 00000025751 13620656057 0013044 0 ustar 00root root 0000000 0000000 .Dd Feb 12, 2020
.Dt NNN 1
.Os
.Sh NAME
.Nm nnn
.Nd the missing terminal file manager for X
.Sh SYNOPSIS
.Nm
.Op Ar -a
.Op Ar -A
.Op Ar -b key
.Op Ar -c
.Op Ar -d
.Op Ar -e
.Op Ar -E
.Op Ar -g
.Op Ar -H
.Op Ar -K
.Op Ar -n
.Op Ar -p file
.Op Ar -Q
.Op Ar -r
.Op Ar -R
.Op Ar -s name
.Op Ar -S
.Op Ar -t secs
.Op Ar -v
.Op Ar -V
.Op Ar -x
.Op Ar -h
.Op Ar PATH
.Sh DESCRIPTION
.Nm
(Nnn's Not Noice) is a performance-optimized, feature-packed fork of
noice (http://git.2f30.org/noice/) with seamless desktop
integration, simplified navigation, \fInavigate-as-you-type\fR mode with
auto select, disk usage analyzer mode, bookmarks, contexts, application
launcher, familiar navigation shortcuts, subshell spawning and much
more.It remains a simple and efficient file manager that stays out of your way.
.Pp
.Nm
opens the current working directory by default if
.Ar PATH
is not specified.
.Sh KEYBINDS
.Pp
Press \fB?\fR in
.Nm
to see the list of keybinds.
.Sh OPTIONS
.Pp
.Nm
supports the following options:
.Pp
.Fl a
use access time for all operations (default: modification time)
.Pp
.Fl A
disable directory auto-select in navigate-as-you-type mode
.Pp
.Fl "b key"
specify bookmark key to open
.Pp
.Fl c
opener opens files in cli utilities only (overrides -e)
.Pp
.Fl d
detail mode
.Pp
.Fl e
open text files in $VISUAL (else $EDITOR, fallback vi) [preferably CLI]
.Pp
.Fl E
use $EDITOR for internal undetached edits
.Pp
.Fl g
use regex filters instead of substring match
.Pp
.Fl H
show hidden files
.Pp
.Fl K
test for keybind collision
.Pp
.Fl n
start in navigate-as-you-type mode
.Pp
.Fl o
open files only on Enter key
.Pp
.Fl "p file"
copy (or \fIpick\fR) selection to file, or stdout if file='-'
.Pp
.Fl Q
disable confirmation on quit with multiple contexts active
.Pp
.Fl r
show cp, mv progress
(Linux-only, needs advcpmv; '^T' shows the progress on BSD/macOS)
.Pp
.Fl R
disable rollover at edges
.Pp
.Fl "s name"
load a session by name
.Pp
.Fl S
start in disk usage analyzer mode
.Pp
.Fl "t secs"
idle timeout in seconds to lock terminal
.Pp
.Fl v
use case-insensitive version compare to sort files
.Pp
.Fl V
show version and exit
.Pp
.Fl x
show notis on selection cp, mv, rm completion
copy path to system clipboard on select
.Pp
.Fl h
show program help and exit
.Sh CONFIGURATION
There is no configuration file. Associated files are at
.Pp
\fB${XDG_CONFIG_HOME:-$HOME/.config}/nnn/\fR
.Pp
Configuration is done using a few optional (set if you need) environment
variables. See ENVIRONMENT section.
.Pp
.Nm
uses \fIxdg-open\fR (on Linux), \fIopen(1)\fR (on macOS), \fIcygstart\fR on
(Cygwin) and \fIopen\fR on (Haiku) as the desktop opener. It's also possible
to specify a custom opener. See ENVIRONMENT section.
.Sh CONTEXTS
Contexts serve the purpose of exploring multiple directories simultaneously. 4
contexts are available. The status of the contexts are shown in the top left
corner:
.Pp
- the current context is in reverse video
.br
- other active contexts are underlined
.br
- rest are inactive
.Pp
On context creation, the state of the previous context is copied. Each context
remembers its last visited directory.
.Pp
Each context can have its own directory color specified. See ENVIRONMENT
section.
.Sh SESSIONS
Sessions are a way to save and restore states of work. A session stores the
settings and contexts.
.Pp
Sessions can be loaded dynamically from within a running
.Nm
instance, or with a program option.
.Pp
When a session is loaded dynamically, the last working session is saved
automatically to a dedicated -- "last session" -- session file.
.Pp
All the session files are located by session name in the directory
.Pp
\fB${XDG_CONFIG_HOME:-$HOME/.config}/nnn/sessions\fR
.Pp
"@" is the "last session" file.
.Sh FILTERS
Filters are strings to find matching entries in the current directory
instantly (\fIsearch-as-you-type\fR). There is a program option to switch to
regex filters. Matches are case-insensitive by default. In each context the
last filter is persisted at runtime or in saved sessions.
.Pp
Special keys at empty filter prompt:
.Pp
- toggle between string and regex: '/'
.br
- toggle case sensitivity: ':'
.br
- apply the last filter (or clear filter if non-empty): '^L'
.br
- show help and config screen: '?'
.br
- show command prompt: ']'
.br
- launch an application: '='
.br
- run a plugin by its key: ';'
.br
- pin current directory: ','
.Pp
Other noteworthy keys:
.Pp
- '^char': usual keybind functionality
.br
- 'Esc': exit filter prompt but skip dir refresh
.Pp
Common regex use cases:
.Pp
(1) To list all matches starting with the filter expression,
start the expression with a '^' (caret) symbol.
.br
(2) Type '\\.mkv' to list all MKV files.
.br
(3) Use '.*' to match any character (\fIsort of\fR fuzzy search).
.Pp
In the \fInavigate-as-you-type\fR mode directories are opened in filter
mode, allowing continuous navigation. Works best with the \fBarrow keys\fR.
.br
When there's a unique match and it's a directory,
.Nm
auto selects the directory and enters it in this mode. Use the relevant
program option to disable this behaviour.
.Sh SELECTION
.Nm
allows file selection across directories and contexts!
.Pp
There are 3 groups of keybinds to add files to selection:
.Pp
(1) hovered file selection toggle (deselects if '+' is visible before the
entry, else adds to selection)
.br
(2) add a range of files to selection (repeat the range key on the same entry
twice to clear selection completely)
.br
(3) add all files in the current directory to selection
.Pp
A selection can be edited, copied, moved, removed, archived or linked.
.Pp
Absolute paths of the selected files are copied to \fB.selection\fR file in
the config directory.
.Pp
To edit the selection use the _edit selection_ key. Use this key to remove a
file from selection after you navigate away from its directory. Editing doesn't
end the selection mode. You can add more files to the selection and edit the
list again. If no file is selected in the current session, this option attempts
to list the selection file.
.Sh LIST FILES
.Nm
can receive a list of files as input. The paths should be NUL-separated ('\\0')
but doesn't need to be NUL-terminated. Paths and can be relative to the current
directory or absolute.
.Pp
Input is limited by 65,536 paths or 256 MiB of input.
.Pp
Start
.Nm
in this mode by writing to its standard input. So the output of another command
can be piped to it. For example, to list files in current directory larger than
1M:
.Bd -literal
find -maxdepth 1 -size +1M -print0 | nnn
.Ed
.Pp
or you can redirect a list from a file:
.Bd -literal
nnn < files.txt
.Ed
.Pp
A temporary directory will be created containing symlinks to the given
paths. Any action performed on these symlinks will be performed only on their
targets, after which they might become invalid.
.Pp
Though the term "files" is used, any input is valid as long as it's a valid
path. \fBInvalid paths are ignored.\fR
.Sh UNITS
The minimum file size unit is byte (B). The rest are K, M, G, T, P, E, Z, Y
(powers of 1024), same as the default units in \fIls\fR.
.Sh ENVIRONMENT
The SHELL, EDITOR (VISUAL, if defined) and PAGER environment variables are
used. A single combination of arguments is supported for SHELL and PAGER.
.Pp
\fBNNN_OPENER:\fR specify a custom file opener.
.Bd -literal
export NNN_OPENER=nuke
NOTE: `nuke` is a file opener available in plugin repository
.Ed
.Pp
\fBNNN_BMS:\fR bookmark string as \fIkey_char:location\fR pairs
(max 10) separated by \fI;\fR:
.Bd -literal
export NNN_BMS='d:~/Documents;u:/home/user/Cam Uploads;D:~/Downloads/'
NOTE: To go to a bookmark, press the Lead key followed by the bookmark key.
.Ed
.Pp
\fBNNN_PLUG:\fR directly executable plugins as \fIkey_char:location\fR pairs
(max 15) separated by \fI;\fR:
.Bd -literal
export NNN_PLUG='o:fzopen;p:mocplay;d:diffs;m:nmount;t:imgthumb'
NOTES:
1. To run a plugin directly, press \fI;\fR followed by the plugin key
2. To skip directory refresh after running a plugin, prefix with \fB-\fR
export NNN_PLUG='m:-mediainfo'
.Ed
.Pp
To assign keys to arbitrary non-background non-shell-interpreted cli
commands and invoke like plugins, add \fI_\fR (underscore) before the
command.
.Bd -literal
export NNN_PLUG='x:_chmod +x $nnn;g:_git log;s:_smplayer $nnn;o:fzopen'
NOTES:
1. Use single quotes for $NNN_PLUG so $nnn is not interpreted
2. $nnn should be the last argument (IF used)
3. (Again) add \fB_\fR before the command
4. To disable directory refresh after running a \fIcommand as plugin\fR,
prefix with \fB-_\fR
5. To skip user confirmation after command execution, suffix with \fB*\fR
export NNN_PLUG='y:-_sync*'
6. To run a \fIGUI app as plugin\fR, add a \fB|\fR after \fB_\fR
export NNN_PLUG='m:-_|mousepad $nnn'
EXAMPLES:
----------------------------------- + -------------------------------------------------
Key:Command | Description
----------------------------------- + -------------------------------------------------
k:-_fuser -kiv $nnn* | Interactively kill process(es) using hovered file
l:_git log | Show git log
n:-_vi /home/user/Dropbox/dir/note* | Take quick notes in a synced file/dir of notes
p:-_less -iR $nnn* | Page through hovered file in less
s:-_|smplayer -minigui $nnn | Play hovered media file, even unfinished download
x:_chmod +x $nnn | Make the hovered file executable
y:-_sync* | Flush cached writes
----------------------------------- + -------------------------------------------------
.Ed
.Pp
\fBNNN_COLORS:\fR string of color codes for each context, e.g.:
.Bd -literal
export NNN_COLORS='1234'
codes: 0-black, 1-red, 2-green, 3-yellow, 4-blue (default), 5-magenta, 6-cyan, 7-white
.Ed
.Pp
\fBNNN_SSHFS:\fR pass additional options to sshfs command:
.Bd -literal
export NNN_SSHFS='sshfs -o reconnect,idmap=user,cache_timeout=3600'
NOTE: The options must be preceded by `sshfs` and comma-separated without any space between them.
.Ed
.Pp
\fBNNN_RCLONE:\fR pass additional options to rclone command:
.Bd -literal
export NNN_RCLONE='rclone mount --read-only --no-checksum'
NOTE: The options must be preceded by `rclone` and max 5 flags are supported.
.Ed
.Pp
\fBNNN_TRASH:\fR trash (instead of \fIdelete\fR) files to desktop Trash.
.Bd -literal
export NNN_TRASH=1
.Ed
.Pp
\fBnnn:\fR this is a special variable set to the hovered entry before executing
a command from the command prompt or spawning a shell.
.Sh KNOWN ISSUES
.Nm
may not handle keypresses correctly when used with tmux (see issue #104 for
more details). Set \fBTERM=xterm-256color\fR to address it.
.Sh AUTHORS
.An Arun Prakash Jana Aq Mt engineerarun@gmail.com ,
.An Lazaros Koromilas Aq Mt lostd@2f30.org ,
.An Dimitris Papastamos Aq Mt sin@2f30.org .
.Sh HOME
.Em https://github.com/jarun/nnn
nnn-3.0/plugins/ 0000775 0000000 0000000 00000000000 13620656057 0013640 5 ustar 00root root 0000000 0000000 nnn-3.0/plugins/.cbcp 0000775 0000000 0000000 00000002423 13620656057 0014554 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Copy selection to system clipboard as newline-separated entries
# Requires: tr and
# xclip/xsel (Linux)
# pbcopy (macOS)
# termux-clipboard-set (Termux)
# clip.exe (WSL)
# clip (Cygwin)
# wl-copy (Wayland)
#
# 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=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection
if which xsel >/dev/null 2>&1; then
# Linux
tr '\0' '\n' < "$SELECTION" | xsel -bi
elif which xclip >/dev/null 2>&1; then
# Linux
tr '\0' '\n' < "$SELECTION" | xclip -sel clip
elif which pbcopy >/dev/null 2>&1; then
# macOS
tr '\0' '\n' < "$SELECTION" | pbcopy
elif which termux-clipboard-set >/dev/null 2>&1; then
# Termux
tr '\0' '\n' < "$SELECTION" | termux-clipboard-set
elif which clip.exe >/dev/null 2>&1; then
# WSL
tr '\0' '\n' < "$SELECTION" | clip.exe
elif which clip >/dev/null 2>&1; then
# Cygwin
tr '\0' '\n' < "$SELECTION" | clip
elif which wl-copy >/dev/null 2>&1; then
# Wayland
tr '\0' '\n' < "$SELECTION" | wl-copy
fi
nnn-3.0/plugins/.nnn-plugin-helper 0000664 0000000 0000000 00000001227 13620656057 0017205 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Helper script for plugins
#
# Shell: POSIX compliant
# Author: Anna Arad
selection=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection
export selection
## Ask nnn to switch to directory $1 in context $2.
## If $2 is not provided, the function asks explicitly.
nnn_cd () {
dir=$1
if [ -z "$NNN_PIPE" ]; then
echo "No pipe file found" 1>&2
return
fi
if [ -n "$2" ]; then
context=$2
else
printf "Choose context 1-4 (blank for current): "
read -r context
fi
printf "%s" "${context:-0}$dir" > "$NNN_PIPE"
}
cmd_exists () {
which "$1" > /dev/null 2>&1
echo $?
}
nnn-3.0/plugins/.ntfy 0000775 0000000 0000000 00000001037 13620656057 0014625 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Show a notification
#
# Details: nnn invokes this plugin to show notification when a cp/mv/rm operation is complete.
#
# Requires: notify-send (Ubuntu)/ntfy (https://github.com/dschep/ntfy)/osascript (macOS)
#
# Shell: POSIX compliant
# Author: Anna Arad
OS="$(uname)"
if which notify-send >/dev/null 2>&1; then
notify-send nnn "Done!"
elif [ "$OS" = "Darwin" ]; then
osascript -e 'display notification "Done!" with title "nnn"'
elif which ntfy >/dev/null 2>&1; then
ntfy -t nnn send "Done!"
fi
nnn-3.0/plugins/README.md 0000664 0000000 0000000 00000024057 13620656057 0015127 0 ustar 00root root 0000000 0000000 nnn plugins

read ebooks with plugin gutenread (Android)

image preview with plugin imgthumb
## Introduction
Plugins extend the capabilities of `nnn`. They are _executable_ scripts (or binaries) which `nnn` can communicate with and trigger. This mechanism fits perfectly with the fundamental design to keep the core file manager lean and fast, by delegating repetitive (but not necessarily file manager-specific) tasks to the plugins.
`nnn` is language-agnostic when it comes to plugins. You can write a plugin in any (scripting) language you are comfortable in!
## Installing plugins
The following command installs or updates (after backup) all plugins:
curl -Ls https://raw.githubusercontent.com/jarun/nnn/master/plugins/getplugs | sh
Plugins are installed to `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins`.
## List of plugins
| Plugin (a-z) | Description | Lang | Deps |
| --- | --- | --- | --- |
| autojump | Navigate to dir/path (**autojump stores navigation patterns**) | sh | autojump |
| boom | Play random music from dir | sh | [moc](http://moc.daper.net/) |
| dups | List non-empty duplicate files in current dir | sh | find, md5sum,
sort uniq xargs |
| chksum | Create and verify checksums | sh | md5sum,
sha256sum |
| diffs | Diff for selection (limited to 2 for directories) | sh | vimdiff |
| dragdrop | Drag/drop files from/into nnn | sh | [dragon](https://github.com/mwh/dragon) |
| fzcd | Change to the directory of a fuzzy-selected file/dir | sh | fzf/fzy
fd/fdfind/find |
| fzhist | Fuzzy-select a cmd from history, edit in `$EDITOR` and run | sh | fzf/fzy |
| fzopen | Fuzzy find a file in dir subtree and edit or open | sh | fzf/fzy, xdg-open |
| getplugs | Update plugins | sh | curl |
| gutenread | Browse, download, read from Project Gutenberg | sh | curl, unzip, w3m
[epr](https://github.com/wustho/epr) (optional) |
| hexview | View a file in hex in `$PAGER` | sh | xxd |
| imgresize | Resize images in dir to screen resolution | sh | [imgp](https://github.com/jarun/imgp) |
| imgthumb | View thumbnail of an image or dir of images | sh | [lsix](https://github.com/hackerb9/lsix) |
| imgur | Upload an image to imgur (from [imgur-screenshot](https://github.com/jomo/imgur-screenshot)) | bash | - |
| imgview | Browse images, set wallpaper, copy path ([config](https://wiki.archlinux.org/index.php/Sxiv#Assigning_keyboard_shortcuts)), [rename](https://github.com/jarun/nnn/wiki/Basic-use-cases#browse-rename-images)| sh | sxiv/[viu](https://github.com/atanunq/viu), less|
| ipinfo | Fetch external IP address and whois information | sh | curl, whois |
| kdeconnect | Send selected files to an Android device | sh | kdeconnect-cli |
| launch | GUI application launcher | sh | fzf/fzy |
| mediainf | Show media information | sh | mediainfo |
| moclyrics | Show lyrics of the track playing in moc | sh | [ddgr](https://github.com/jarun/ddgr), [moc](http://moc.daper.net/) |
| mocplay | Append (and/or play) selection/dir/file in moc | sh | [moc](http://moc.daper.net/) |
| nmount | Toggle mount status of a device as normal user | sh | pmount, udisks2 |
| nuke | Sample file opener (CLI-only by default) | sh | various |
| oldbigfile | List large files by access time | sh | find, sort |
| organize | Auto-organize files in directories by file type | sh | file |
| pdfread | Read a PDF or text file aloud | sh | pdftotext, mpv,
pico2wave |
| pdfview | View PDF file in `$PAGER` | sh | pdftotext/
mupdf-tools |
| picker | Pick files and list one per line (to pipe) | sh | nnn |
| pskill | Fuzzy list by name and kill process or zombie | sh | fzf/fzy, ps,
sudo/doas |
| renamer | Batch rename selection or files in dir | sh | [qmv](https://www.nongnu.org/renameutils/)/[vidir](https://joeyh.name/code/moreutils/) |
| ringtone | Create a variable bitrate mp3 ringtone from file | sh | date, ffmpeg |
| splitjoin | Split file or join selection | sh | split, cat |
| suedit | Edit file using superuser permissions | sh | sudoedit/sudo/doas |
| treeview | Informative tree output in `$EDITOR` | sh | tree |
| uidgid | List user and group of all files in dir | sh | ls, less |
| upgrade | Upgrade nnn manually on Debian 9 Stretch | sh | curl |
| upload | Paste text to ix.io, upload binary to file.io | sh | curl, jq, tr |
| vidthumb | Show video thumbnails in terminal | sh | [ffmpegthumbnailer](https://github.com/dirkvdb/ffmpegthumbnailer),
[lsix](https://github.com/hackerb9/lsix) |
| wall | Set wallpaper or change colorscheme | sh | nitrogen/pywal |
## Invoking a plugin
Use the plugin shortcut (;key or ^Skey) to list the defined plugin keys and press the required key. E.g., with the below config:
export NNN_PLUG='o:fzopen;p:mocplay;d:diffs;m:nmount;n:notes;v:imgviu;t:imgthumb'
Plugin `fzopen` can be run with the keybind ;o, `mocplay` can be run with ;p and so on... The key vs. plugin pairs are shown in the help and config screen.
A maximum of 15 keys can be defined. To select and invoke a plugin from the plugin directory, press Enter (to _enter_ the plugin dir) after the plugin shortcut.
#### Skip directory refresh after running a plugin
`nnn` refreshes the directory after running a plugin to reflect any changes by the plugin. To disable this (say while running the `mediainfo` plugin on some filtered files), add a `-` before the plugin name:
export NNN_PLUG='m:-mediainfo'
Now `nnn` will not refresh the directory after running the `mediainfo` plugin.
## Running commands as plugin
To assign keys to arbitrary non-background, non-shell-interpreted cli commands and invoke like plugins, add `_` (underscore) before the command.
For example:
export NNN_PLUG='x:_chmod +x $nnn;g:_git log;s:_smplayer $nnn;o:fzopen'
Now ;x can be used to make a file executable, ;g can be used to the git log of a git project directory, ;s can be used to preview a partially downloaded media file.
#### Skip user confirmation after command execution
`nnn` waits for user confirmation (the prompt `Press Enter to continue`) after it executes a command as plugin (unlike plugins which can add a `read` to wait). To skip this, add a `*` after the command. For example:
export NNN_PLUG='s:_smplayer $nnn*;n:-_vim /home/vaio/Dropbox/Public/synced_note*'
Now there will be no prompt after ;s and ;n.
#### Run GUI app as plugin
To run a GUI app as plugin, add a `|` after `_`. For example:
export NNN_PLUG='m:-_|mousepad $nnn'
Notes:
1. Use single quotes for `$NNN_PLUG` so `$nnn` is not interpreted
2. `$nnn` should be the last argument (IF used)
3. (_Again_) add `_` before the command
4. To disable directory refresh after running a _command as plugin_, prefix with `-_`
#### Some useful key-command examples
| Key:Command | Description |
|---|---|
| `k:-_fuser -kiv $nnn*` | Interactively kill process(es) using hovered file |
| `l:_git log` | Show git log |
| `n:-_vi /home/user/Dropbox/dir/note*` | Take quick notes in a synced file/dir of notes |
| `p:-_less -iR $nnn*` | Page through hovered file in less |
| `s:-_\|smplayer -minigui $nnn` | Play hovered media file, even unfinished download |
| `x:_chmod +x $nnn` | Make the hovered file executable |
| `y:-_sync*` | Flush cached writes |
## Access level of plugins
When `nnn` executes a plugin, it does the following:
- Changes to the directory where the plugin is to be run (`$PWD` pointing to the active directory)
- Passes two arguments to the script:
1. The hovered file's name.
2. The working directory (might differ from `$PWD` in case of symlinked paths; non-canonical).
- Sets the environment variable `NNN_PIPE` used to control `nnn` active directory.
Plugins can also read the `.selection` file in the config directory.
## Create your own plugins
Plugins can be written in any scripting language. However, POSIX-compliant shell scripts runnable in `sh` are preferred.
Drop the plugin in `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins` and make it executable. Optionally add a hotkey in `$NNN_PLUG` for frequent usage.
#### Controlling `nnn`'s active directory
`nnn` provides a mechanism for plugins to control its active directory.
The way to do so is by writing to the pipe pointed by the environment variable `NNN_PIPE`.
The plugin should write a single string in the format `` without a newline at the end. For example, `1/etc`.
The number indicates the context to change the active directory of (0 is used to indicate the current context).
For convenience, we provided a helper script named `.nnn-plugin-helper` and a function named `nnn_cd` to ease this process. `nnn_cd` receives the path to change to as the first argument, and the context as an optional second argument.
If a context is not provided, it is asked for explicitly.
Usage examples can be found in the Examples section below.
#### Examples
There are many plugins provided by `nnn` which can be used as examples. Here are a few simple selected examples.
- Show the git log of changes to the particular file along with the code for a quick and easy review.
```sh
#!/usr/bin/env sh
git log -p -- "$1"
```
- Change to directory in clipboard using helper script
```sh
#!/usr/bin/env sh
. $(dirname $0)/.nnn-plugin-helper
nnn_cd "$(xsel -ob)"
```
- Change directory to the location of a link using helper script with specific context (current)
```sh
#!/usr/bin/env sh
. $(dirname $0)/.nnn-plugin-helper
nnn_cd "$(dirname $(readlink -fn $1))" 0
```
- Change to arbitrary directory without helper script
```sh
#!/usr/bin/env sh
printf "cd to: "
read -r dir
printf "%s" "0$dir" > "$NNN_PIPE"
```
## Contributing plugins
1. Add informative sections like _Description_, _Notes_, _Dependencies_, _Shell_, _Author_ etc. in the plugin.
2. Add an entry in the table above.
3. Keep non-portable commands (like `notify-send`) commented so users from any other OS/DE aren't surprised.
4. The plugin file should be executable.
nnn-3.0/plugins/autojump 0000775 0000000 0000000 00000000654 13620656057 0015437 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Navigate to directory using autojump
#
# Requires: autojump - https://github.com/wting/autojump
#
# Note: autojump STORES NAVIGATION PATTERNS
#
# Shell: POSIX compliant
# Author: Marty Buchaus
if which autojump >/dev/null 2>&1; then
printf "jump to: "
read -r dir
odir="$(autojump "$dir")"
printf "%s" "0$odir" > "$NNN_PIPE"
else
printf "autojump missing"
read -r _
fi
nnn-3.0/plugins/boom 0000775 0000000 0000000 00000001640 13620656057 0014523 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Play random music from current directory. Identifies MP3, FLAC, M4A, WEBM, WMA.
# You may want to set GUIPLAYER.
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
#GUIPLAYER=smplayer
NUMTRACKS=100
if [ ! -z "$GUIPLAYER" ]; then
PLAYER="$GUIPLAYER"
find . -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.m4a" -o -iname "*.webm" -o -iname "*.wma" \) | shuf | head -n $NUMTRACKS | xargs -d "\n" "$PLAYER" > /dev/null 2>&1 &
# detach the player
sleep 1
elif which mocp >/dev/null 2>&1; then
# start MOC server
mocp -S
# clear MOC playlist
mocp -c
# add up to 100 random audio files
find . -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.m4a" -o -iname "*.webm" -o -iname "*.wma" \) | shuf | head -n $NUMTRACKS | xargs -d "\n" mocp -a
# start playing
mocp -p
else
printf "moc missing"
read -r _
fi
nnn-3.0/plugins/chksum 0000775 0000000 0000000 00000004153 13620656057 0015063 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Create and verify checksums
#
# For selection: it will generate one file containing the checksums with file names
# [and with paths if they are in another directory]
# the output checksum filename will be checksum_timestamp.checksum_type
# For 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
# For directory: recursively calculates checksum for all the files in the directory
# the output checksum filename will be directory.checksum_type
#
# Shell: POSIX compliant
# Author: ath3, Arun Prakash Jana
selection=${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"
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 _
return
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
nnn-3.0/plugins/diffs 0000775 0000000 0000000 00000002312 13620656057 0014657 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Show diff of 2 directories or multiple files in vimdiff
#
# Note: vim may show the warning: 'Vim: Warning: Input is not from a terminal'
# press 'Enter' to ignore and proceed.
#
# Shell: POSIX compliant
# Authors: Arun Prakash Jana, ath3
selection=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection
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
dir1=$(mktemp "${TMPDIR:-/tmp}"/nnn-"$(basename "$f1")".XXXXXXXX)
dir2=$(mktemp "${TMPDIR:-/tmp}"/nnn-"$(basename "$f2")".XXXXXXXX)
ls -A1 "$f1" > "$dir1"
ls -A1 "$f2" > "$dir2"
vimdiff "$dir1" "$dir2"
rm "$dir1" "$dir2"
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
xargs -0 vimdiff +0 < "$selection"
fi
else
echo "needs at least 2 files or directories selected for comparison"
fi
fi
nnn-3.0/plugins/dragdrop 0000775 0000000 0000000 00000003441 13620656057 0015372 0 ustar 00root root 0000000 0000000 #!/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.
#
# Files that are dropped will be added to nnn's selection
# Some webbased files will be downloaded to current directory with curl
# and it may overwrite some existing files
#
# The user has to mm to clear nnn's selection first
#
# Dependency: https://github.com/mwh/dragon
# Shell: POSIX compliant
# Author: 0xACE
selection=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection
resp=f
all=
if which dragon-drag-and-drop >/dev/null 2>&1; then
dnd="dragon-drag-and-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
nnn-3.0/plugins/dups 0000775 0000000 0000000 00000001033 13620656057 0014536 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: List non-empty duplicate files in the current directory (based on size followed by MD5)
#
# Source: https://www.commandlinefu.com/commands/view/3555/find-duplicate-files-based-on-size-first-then-md5-hash
#
# Requires: find md5sum sort uniq xargs
#
# Shell: POSIX compliant
# Author: syssyphus
find . -size +0 -type f -printf "%s\n" | sort -rn | uniq -d | xargs -I{} -n1 find -type f -size {}c -print0 | xargs -0 md5sum | sort | uniq -w32 --all-repeated=separate
printf "Press any key to exit"
read -r _
nnn-3.0/plugins/fzcd 0000775 0000000 0000000 00000001225 13620656057 0014514 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Run fzf/fzy, fd/fdfind/find and go to the directory of the file selected
#
# Shell: POSIX compliant
# Author: Anna Arad
. "$(dirname "$0")"/.nnn-plugin-helper
if [ "$(cmd_exists fzy)" -eq "0" ]; then
if [ "$(cmd_exists fd)" -eq "0" ]; then
fd=fd
elif [ "$(cmd_exists fdfind)" -eq "0" ]; then
fd=fdfind
else
fd=find
fi
sel=$($fd | fzy)
elif [ "$(cmd_exists fzf)" -eq "0" ]; then
sel=$(fzf)
else
exit 1
fi
if [ -n "$sel" ]; then
if ! [ -d "$sel" ]; then
sel=$(dirname "$sel")
elif [ "$sel" = "." ]; then
exit 0
fi
# Remove "./" prefix if it exists
sel="${sel#./}"
nnn_cd "$PWD/$sel"
fi
nnn-3.0/plugins/fzhist 0000775 0000000 0000000 00000001600 13620656057 0015072 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Fuzzy find a command from history, edit in $EDITOR and run as a command
# Currently supports only bash and fish history
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
if which fzf >/dev/null 2>&1; then
fuzzy=fzf
elif which fzy >/dev/null 2>&1; then
fuzzy=fzy
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/.config/fish/fish_history"
entry="$(grep "\- cmd: " "$hist_file" | cut -c 8- | "$fuzzy")"
fi
if ! [ -z "$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
nnn-3.0/plugins/fzopen 0000775 0000000 0000000 00000001114 13620656057 0015064 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Fuzzy find a file in directory subtree with fzy
# Opens in $VISUAL or $EDITOR if text
# Opens other type of files with xdg-open
#
# Requires: fzf/fzy, xdg-open
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
if which fzf >/dev/null 2>&1; then
fuzzy=fzf
elif which fzy >/dev/null 2>&1; then
fuzzy=fzy
else
exit 1
fi
entry="$(find . -type f 2>/dev/null | "$fuzzy")"
case "$(file -biL "$entry")" in
*text*)
"${VISUAL:-$EDITOR}" "$entry" ;;
*)
xdg-open "$entry" >/dev/null 2>&1 ;;
esac
nnn-3.0/plugins/getplugs 0000775 0000000 0000000 00000002673 13620656057 0015430 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Update nnn plugins
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana, KlzXS
CONFIG_DIR=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/
PLUGIN_DIR=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins
is_cmd_exists () {
which "$1" > /dev/null 2>&1
echo $?
}
merge () {
vimdiff +0 "$1" "$2"
}
prompt () {
printf "%s" "Plugin $1 already exists and is different.\n"
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 [ "$(is_cmd_exists sudo)" -eq "0" ]; then
# sucmd=sudo
# elif [ "$(is_cmd_exists doas)" -eq "0" ]; then
# sucmd=doas
# else
# sucmd=: # noop
# 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 -O https://github.com/jarun/nnn/archive/master.tar.gz
tar -zxf master.tar.gz
cd nnn-master/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-master/ master.tar.gz
nnn-3.0/plugins/gutenread 0000775 0000000 0000000 00000003053 13620656057 0015545 0 ustar 00root root 0000000 0000000 #!/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 dowload 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=
DIR="${XDG_CACHE_HOME:-$HOME/.cache}/nnn/gutenbooks/$EBOOK_ID"
BROWSE_LINK="http://www.gutenberg.org/ebooks/search/?sort_order=downloads"
BROWSER=w3m
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 "http://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
nnn-3.0/plugins/hexview 0000775 0000000 0000000 00000000270 13620656057 0015244 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: View a file in hex
# Requires: xxd and $PAGER
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
if ! [ -z "$1" ]; then
xxd "$1" | $PAGER
fi
nnn-3.0/plugins/imgresize 0000775 0000000 0000000 00000001403 13620656057 0015562 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Resize images in a directory to screen resolution with imgp
# imgp homepage: https://github.com/jarun/imgp
#
# Notes:
# 1. Set res if you don't want to be prompted for desktop resolution every 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=
# set minimum image size (in bytes) to resize (default: 1MB)
minsize=1048576
if [ -z "$res" ]; then
printf "desktop resolution (hxv): "
read -r res
fi
if ! [ -z "$res" ] && ! [ -z "$minsize" ]; then
imgp -ackx "$res" -s "$minsize"
fi
nnn-3.0/plugins/imgthumb 0000775 0000000 0000000 00000000466 13620656057 0015410 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: View thumbnail of an image or a directory of images with lsix
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
if ! [ -z "$1" ]; then
if [ -d "$1" ]; then
lsix "$1"/*
else
lsix "$1"
fi
printf "Press any key to exit..."
read -r _
fi
nnn-3.0/plugins/imgur 0000775 0000000 0000000 00000050423 13620656057 0014715 0 ustar 00root root 0000000 0000000 #!/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://imgur.com/tools
#
# 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
source "${settings_path}"
fi
# dependency check
if [ "${1}" = "--check" ]; then
(which grep &>/dev/null && echo "OK: found grep") || echo "ERROR: grep not found"
if is_mac; then
if which growlnotify &>/dev/null; then
echo "OK: found growlnotify"
elif which terminal-notifier &>/dev/null; then
echo "OK: found terminal-notifier"
else
echo "ERROR: growlnotify nor terminal-notifier found"
fi
(which screencapture &>/dev/null && echo "OK: found screencapture") || echo "ERROR: screencapture not found"
(which pbcopy &>/dev/null && echo "OK: found pbcopy") || echo "ERROR: pbcopy not found"
else
(which notify-send &>/dev/null && echo "OK: found notify-send") || echo "ERROR: notify-send (from libnotify-bin) not found"
(which scrot &>/dev/null && echo "OK: found scrot") || echo "ERROR: scrot not found"
(which xclip &>/dev/null && echo "OK: found xclip") || echo "ERROR: xclip not found"
fi
(which curl &>/dev/null && echo "OK: found curl") || echo "ERROR: curl not found"
exit 0
fi
# notify <'ok'|'error'>
function notify() {
if is_mac; then
if which 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 ! [ -z "$remote_version" ]; then
if [ ! "${current_version}" = "${remote_version}" ] && [ ! -z "${current_version}" ] && [ ! -z "${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
source "${credentials_file}"
fi
current_time="$(date +%s)"
preemptive_refresh_time="$((10*60))"
expired="$((current_time > (token_expire_time - preemptive_refresh_time)))"
if [ ! -z "${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 < "${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 [ ! -z "${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 [ ! -z "${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 Override 'open' config"
echo " -e, --edit Override 'edit' config"
echo " -i, --edit-command Override 'edit_command' config (include '%img'), sets --edit 'true'"
echo " -l, --login Override 'login' config"
echo " -a, --album Create new album and upload there"
echo " -A, --album-id Override 'album_id' config"
echo " -k, --keep-file Override 'keep_file' config"
echo " -d, --auto-delete Automatically delete image after 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 "http://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 _
nnn-3.0/plugins/imgview 0000775 0000000 0000000 00000001153 13620656057 0015235 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Open images in hovered directory and thumbnails
# open hovered image in sxiv or viu and browse other images in the directory
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
if [ -z "$1" ] || ! [ -s "$1" ]; then
printf "empty file"
read -r _
exit 1
fi
if command -v sxiv >/dev/null 2>&1; then
if [ -f "$1" ]; then
sxiv -q "$1" "$PWD"
elif [ -d "$1" ] || [ -h "$1" ]; then
sxiv -qt "$1"
fi
elif command -v viu >/dev/null 2>&1; then
viu -n "$1" | less -R
else
printf "install sxiv or viu"
read -r _
exit 2
fi
nnn-3.0/plugins/ipinfo 0000775 0000000 0000000 00000000372 13620656057 0015054 0 ustar 00root root 0000000 0000000 #!/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 _
nnn-3.0/plugins/kdeconnect 0000775 0000000 0000000 00000001175 13620656057 0015707 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Send the selected files to your Android device using kdeconnect-cli. You must have installed and configured kdeconnect both on the Android device and on the PC.
#
# Shell: POSIX compliant
# Author: juacq97
SELECTION=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection
id=$(kdeconnect-cli -a --id-only | awk '{print $1}')
if [ "$(find "$SELECTION")" ]; then
kdeconnect-cli -d "$id" --share "$(cat "$SELECTION")"
# If you want a system notification, uncomment the next 3 lines.
# notify-send -a "Kdeconnect" "Sending $(cat "$SELECTION")"
#else
# notify-send -a "Kdeconnect" "No file selected"
fi
nnn-3.0/plugins/launch 0000775 0000000 0000000 00000002174 13620656057 0015044 0 ustar 00root root 0000000 0000000 #!/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
#
# Requires: fzf/fzy
#
# 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 which fzf >/dev/null 2>&1; then
{ IFS=':'; ls -H $PATH; } | sort | fzf
elif which fzy >/dev/null 2>&1; then
{ IFS=':'; ls -H $PATH; } | sort | fzy
else
exit 1
fi
}
if selection=$( get_selection ); then
setsid "$selection" 2>/dev/null 1>/dev/null &
if ! [ -z "$1" ]; then
sleep "$1"
else
sleep 1
fi
fi
nnn-3.0/plugins/mediainf 0000775 0000000 0000000 00000000376 13620656057 0015350 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Show media information of a file in pager
#
# Requires: mediainfo
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
if ! [ -z "$1" ] && [ -f "$1" ]; then
mediainfo "$1" | $PAGER
# exiftool "$1" | $PAGER
fi
nnn-3.0/plugins/moclyrics 0000775 0000000 0000000 00000002064 13620656057 0015574 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Fetches the lyrics of the track currently playing in MOC
# Requires 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 ! [ -z "$ARTIST" ] && ! [ -z "$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 ! [ -z "$FILENAME" ]; then
ddgr -w azlyrics.com --ducky "$FILENAME"
fi
fi
nnn-3.0/plugins/mocplay 0000775 0000000 0000000 00000004151 13620656057 0015233 0 ustar 00root root 0000000 0000000 #!/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 randomize the order of files appended to the playlist, set SHUFFLE=1
# if you add a directory with many files when SHUFFLE=1 is set, it might take a very long time to finish!
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana, ath3
IFS="$(printf '\n\r')"
selection=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection
cmd=$(pgrep -x mocp 2>/dev/null)
ret=$cmd
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)
else
arr2=$(printf "%s\n%s" "$entry" "$arr2")
fi
done
arr2=$(echo "$arr2" | awk 'BEGIN{srand();}{print rand()"\t"$0}' | sort -k1 -n | cut -f2-)
for entry in $arr2
do
if [ -f "$entry" ] && echo "$entry" | grep -qv '\.m3u$\|\.pls$' ; then
mocp -a "$entry"
fi
done
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 [ -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
nnn-3.0/plugins/nmount 0000775 0000000 0000000 00000002652 13620656057 0015113 0 ustar 00root root 0000000 0000000 #!/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.
#
# Runs `lsblk` if 'l' is entered, exits on 'Return`.
#
# Note:
# - 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 pwoer down devices. This is also Linux-specific.
# Users on non-Linux platforms can comment it and use an alterntive to power-down disks.
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
prompt="device name ['l' lists]: "
lsblk
printf "\nEnsure you aren't still in the mounted device.\n"
printf "%s" "$prompt"
read -r dev
while ! [ -z "$dev" ]
do
if [ "$dev" = "l" ]; then
lsblk
elif [ "$dev" = "q" ]; then
exit
else
if grep -qs "$dev " /proc/mounts; then
sync
if pumount "$dev"
then
echo "$dev" unmounted.
if udisksctl power-off -b /dev/"$dev"
then
echo "$dev" ejected.
fi
fi
else
pmount "$dev"
echo "$dev" mounted to "$(lsblk -n /dev/"$dev" | rev | cut -d' ' -f1 | rev)".
fi
fi
echo
printf "%s" "$prompt"
read -r dev
done
nnn-3.0/plugins/nuke 0000775 0000000 0000000 00000036370 13620656057 0014541 0 ustar 00root root 0000000 0000000 #!/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. mocplay 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:
# i. by extension
# ii. by mime (image, video, audio, pdf)
# iii. by mime (other file types)
#
# 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' in handle_fallback() as last resort.
#
# Feel free to change the utilities to your favourites and add more mimes.
#
# Defaults:
# By extension (only the enbaled ones):
# most archives: list with atool, bsdtar
# rar: list with unrar
# 7-zip: list with 7z
# pdf: zathura (GUI), pdftotext, mutool, exiftool
# audio: mocplay (nnn plugin using MOC), mpv, mediainfo, exiftool
# avi|dat|mkv|mp4: smplayer, mpv (GUI), ffmpegthumbnailer, mediainfo, exiftool
# torrent: rtorrent, transmission-show
# odt|ods|odp|sxw: odt2txt
# md: glow (https://github.com/charmbracelet/glow)
# htm|html|xhtml: w3m, lynx, elinks
# json: jq, python (json.tool module)
# Multimedia by mime:
# image/*: sxiv (GUI), viu, img2txt, exiftool
# video/*: smplayer, mpv (GUI), ffmpegthumbnailer, mediainfo, exiftool
# audio/*: mocplay (nnn plugin using MOC), mpv, 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 unnecessary the exit codes
# #############################################################################
# set to 1 to enable GUI apps
GUI=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")
ext="${FNAME##*.}"
if ! [ -z "$ext" ]; then
ext="$(printf "%s" "${ext}" | tr '[:upper:]' '[:lower:]')"
fi
handle_pdf() {
if [ $GUI -ne 0 ] && which zathura >/dev/null 2>&1; then
zathura "${FPATH}" >/dev/null 2>&1 &
exit 0
elif which pdftotext >/dev/null 2>&1; then
## Preview as text conversion
pdftotext -l 10 -nopgbrk -q -- "${FPATH}" - | less -R
exit 0
elif which mutool >/dev/null 2>&1; then
mutool draw -F txt -i -- "${FPATH}" 1-10
exit 0
elif which exiftool >/dev/null 2>&1; then
exiftool "${FPATH}" | less -R
exit 0
fi
}
handle_audio() {
if which mocp >/dev/null 2>&1; then
mocplay "${FPATH}" >/dev/null 2>&1
exit 0
elif which mpv >/dev/null 2>&1; then
mpv "${FPATH}" >/dev/null 2>&1 &
exit 0
elif which mediainfo >/dev/null 2>&1; then
mediainfo "${FPATH}" | less -R
exit 0
elif which exiftool >/dev/null 2>&1; then
exiftool "${FPATH}"| less -R
exit 0
fi
}
handle_video() {
if [ $GUI -ne 0 ] && which smplayer >/dev/null 2>&1; then
smplayer "${FPATH}" >/dev/null 2>&1 &
exit 0
elif [ $GUI -ne 0 ] && which mpv >/dev/null 2>&1; then
mpv "${FPATH}" >/dev/null 2>&1 &
exit 0
elif which 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" | less -R
exit 0
elif which mediainfo >/dev/null 2>&1; then
mediainfo "${FPATH}" | less -R
exit 0
elif which exiftool >/dev/null 2>&1; then
exiftool "${FPATH}"| less -R
exit 0
fi
}
# 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 which atool >/dev/null 2>&1; then
atool --list -- "${FPATH}" | less -R
exit 0
elif which bsdtar >/dev/null 2>&1; then
bsdtar --list --file "${FPATH}" | less -R
exit 0
fi
exit 1;;
rar)
if which unrar >/dev/null 2>&1; then
## Avoid password prompt by providing empty password
unrar lt -p- -- "${FPATH}" | less -R
fi
exit 1;;
7z)
if which 7z >/dev/null 2>&1; then
## Avoid password prompt by providing empty password
7z l -p -- "${FPATH}" | less -R
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|dat|mkv|mp4)
handle_video
exit 1;;
## BitTorrent
torrent)
if which rtorrent >/dev/null 2>&1; then
rtorrent "${FPATH}"
exit 0
elif which transmission-show >/dev/null 2>&1; then
transmission-show -- "${FPATH}"
exit 0
fi
exit 1;;
## OpenDocument
odt|ods|odp|sxw)
if which odt2txt >/dev/null 2>&1; then
## Preview as text conversion
odt2txt "${FPATH}" | less -R
exit 0
fi
exit 1;;
## Markdown
md)
if which glow >/dev/null 2>&1; then
glow -sdark "${FPATH}" | less -R
exit 0
fi
;;
## HTML
htm|html|xhtml)
## Preview as text conversion
if which w3m >/dev/null 2>&1; then
w3m -dump "${FPATH}" | less -R
exit 0
elif which lynx >/dev/null 2>&1; then
lynx -dump -- "${FPATH}" | less -R
exit 0
elif which elinks >/dev/null 2>&1; then
elinks -dump "${FPATH}" | less -R
exit 0
fi
;;
## JSON
json)
if which jq >/dev/null 2>&1; then
jq --color-output . "${FPATH}" | less -R
exit 0
elif which python >/dev/null 2>&1; then
python -m json.tool -- "${FPATH}" | less -R
exit 0
fi
;;
esac
}
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 ] && which sxiv >/dev/null 2>&1; then
sxiv -q "${FPATH}" &
exit 0
elif which viu >/dev/null 2>&1; then
viu -n "${FPATH}" | less -R
exit 0
elif which img2txt >/dev/null 2>&1; then
img2txt --gamma=0.6 -- "${FPATH}" | less -R
exit 0
elif which exiftool >/dev/null 2>&1; then
exiftool "${FPATH}" | less -R
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 overriden
## 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)
vi "${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 which djvutxt >/dev/null 2>&1; then
## Preview as text conversion (requires djvulibre)
djvutxt "${FPATH}" | less -R
exit 0
elif which exiftool >/dev/null 2>&1; then
exiftool "${FPATH}" | less -R
exit 0
fi
exit 1;;
esac
}
handle_fallback() {
if [ $GUI -ne 0 ]; then
xdg-open "${FPATH}" >/dev/null 2>&1 &
exit 0
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;;
esac
}
MIMETYPE="$( file --dereference --brief --mime-type -- "${FPATH}" )"
handle_blocked "${MIMETYPE}"
handle_extension
handle_multimedia "${MIMETYPE}"
handle_mime "${MIMETYPE}"
handle_fallback
exit 1
nnn-3.0/plugins/oldbigfile 0000775 0000000 0000000 00000000476 13620656057 0015675 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: List files bigger than input size by ascending access date.
#
# Requires: 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 _
nnn-3.0/plugins/organize 0000775 0000000 0000000 00000002565 13620656057 0015414 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Organize files in directories by category
#
# Shell: POSIX compliant
# Author: th3lusive
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
}
main "$@"
nnn-3.0/plugins/pdfread 0000775 0000000 0000000 00000001335 13620656057 0015175 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Read a text or PDF file in British English
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
if ! [ -z "$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
nnn-3.0/plugins/pdfview 0000775 0000000 0000000 00000001147 13620656057 0015235 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: View a PDF file in pager
#
# Notes:
# - $PAGER must be 'less -R' or 'most'
# - To use mutool, uncomment the relevant lines and comment the pdftotext line
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
if ! [ -z "$1" ]; then
if [ "$(head -c 4 "$1")" = "%PDF" ]; then
# Convert using pdftotext
pdftotext -nopgbrk -layout "$1" - | sed 's/\xe2\x80\x8b//g' | $PAGER
# Convert using mutool
# file=`basename "$1"`
# txt=/tmp/"$file".txt
# mutool convert -o "$txt" "$1"
# eval $PAGER $txt
# rm "$txt"
fi
fi
nnn-3.0/plugins/picker 0000775 0000000 0000000 00000001136 13620656057 0015044 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Pick files and pipe the newline-separated list to another utility
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
#
# Usage:
# Copy this file in your $PATH, make it executable and preferably name it to picker.
# Run commands like:
# ls -l `picker`
# cd `picker`
# vimdiff `picker`
# or, in fish shell:
# ls -l (picker)
# cd (picker)
# vimdiff (picker)
#
# NOTE: This use case is limited to picking files, other functionality may not work as expected.
nnn -p /tmp/picked
if [ -f /tmp/picked ]; then
tr '\0' '\n' < /tmp/picked
rm /tmp/picked
fi
nnn-3.0/plugins/pskill 0000775 0000000 0000000 00000001402 13620656057 0015061 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Fuzzy list and kill a (zombie) process by name
#
# Requires: fzf or fzy, 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 ! [ -z "$psname" ]; then
if which sudo >/dev/null 2>&1; then
sucmd=sudo
elif which doas >/dev/null 2>&1; then
sucmd=doas
else
sucmd=: # noop
fi
if which fzf >/dev/null 2>&1; then
fuzzy=fzf
elif which fzy >/dev/null 2>&1; then
fuzzy=fzy
else
exit 1
fi
cmd="$(ps -ax | grep -iw "$psname" | "$fuzzy" | sed -e 's/^[ \t]*//' | cut -d' ' -f1)"
$sucmd kill -9 "$cmd"
fi
nnn-3.0/plugins/renamer 0000775 0000000 0000000 00000002017 13620656057 0015217 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Batch rename selection or current directory with qmv
#
# 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=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection
if command -v qmv >/dev/null 2>&1; then
batchrenamesel="qmv -fdo -da"
batchrename="qmv -fdo -a"
elif command -v 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"
elif [ ! "$(LC_ALL=C ls -a)" = ".
.." ]; then
# On older systems that don't have ls -A
$batchrename
fi
nnn-3.0/plugins/ringtone 0000775 0000000 0000000 00000001656 13620656057 0015423 0 ustar 00root root 0000000 0000000 #!/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.
#
# Requires: 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
nnn-3.0/plugins/splitjoin 0000775 0000000 0000000 00000002417 13620656057 0015605 0 ustar 00root root 0000000 0000000 #!/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=${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 "cant 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"
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
nnn-3.0/plugins/suedit 0000775 0000000 0000000 00000000630 13620656057 0015062 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Edit file as superuser
#
# Shell: POSIX compliant
# Author: Anna Arad
EDITOR="${EDITOR:-vim}"
is_cmd_exists () {
which "$1" > /dev/null 2>&1
echo $?
}
if [ "$(is_cmd_exists sudo)" -eq "0" ]; then
sudo "$EDITOR" "$1"
elif [ "$(is_cmd_exists sudoedit)" -eq "0" ]; then
sudoedit "$1"
elif [ "$(is_cmd_exists doas)" -eq "0" ]; then
doas "$EDITOR" "$1"
fi
nnn-3.0/plugins/treeview 0000775 0000000 0000000 00000000213 13620656057 0015414 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Show tree output in $EDITOR
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
tree -ps | $EDITOR -
nnn-3.0/plugins/uidgid 0000775 0000000 0000000 00000000320 13620656057 0015026 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: list uid and gid of files
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana, superDuperCyberTechno
# shellcheck disable=SC2012
ls -lah --group-directories-first | less
nnn-3.0/plugins/upgrade 0000775 0000000 0000000 00000001222 13620656057 0015212 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Check and update to latest version of nnn manually on Debian 9 Stretch
#
# Shell: POSIX-compliant
# Author: Arun Prakash Jana
# NOTE: This script installs a package, should be issued with admin privilege
cur="$(nnn -v)"
new="$(curl -s "https://github.com/jarun/nnn/releases/latest" | grep -Eo "[0-9]+\.[0-9]+")"
if [ "$cur" = "$new" ]; then
echo 'Already at latest version'
exit 0
fi
# get the package
curl -Ls -O "https://github.com/jarun/nnn/releases/download/v$new/nnn_$new-1_debian9.amd64.deb"
# install it
sudo dpkg -i nnn_"$new"-1_debian9.amd64.deb
# remove the file
rm -rf nnn_"$new"-1_debian9.amd64.deb
nnn-3.0/plugins/upload 0000775 0000000 0000000 00000001414 13620656057 0015052 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Paste contents of a text a file http://ix.io
# Upload a binary file to file.io
# Requires: curl, jq, tr
# Note: Binary file set to expire after a week
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
if ! [ -z "$1" ] && [ -s "$1" ]; then
if [ "$(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
read -r _
nnn-3.0/plugins/vidthumb 0000775 0000000 0000000 00000001057 13620656057 0015413 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Generate video thumbnails and view them
#
# Requires:
# ffmpegthumbnailer: https://github.com/dirkvdb/ffmpegthumbnailer
# lsix: https://github.com/hackerb9/lsix
#
# Shell: POSIX compliant
# Author: Arun Prakash Jana
mkdir .nthumbs > /dev/null 2>&1
for file in *; do
if [ -f "$file" ]; then
ffmpegthumbnailer -i "$file" -o .nthumbs/"${file%%.*}".jpg 2> /dev/null
fi
done
# render thumbnails in lsix
lsix .nthumbs/*
# remove the thumbnails
rm -rf .nthumbs
printf "Press any key to exit..."
read -r _
nnn-3.0/plugins/wall 0000775 0000000 0000000 00000001503 13620656057 0014524 0 ustar 00root root 0000000 0000000 #!/usr/bin/env sh
# Description: Set the selected image as wallpaper using nitrogen or pywal.
# Usage: Hover on an image and run the script to set it as wallpaper.
#
# Shell: POSIX Compliant
# Author: juacq97
cmd_exists () {
which "$1" > /dev/null 2>&1
echo $?
}
if ! [ -z "$1" ]; then
if [ "$(mimetype --output-format %m "$1" | awk -F '/' '{print $1}')" = "image" ]; then
if [ "$(cmd_exists nitrogen)" -eq "0" ]; then
nitrogen --set-zoom-fill --save "$1"
elif [ "$(cmd_exists wal)" -eq "0" ]; then
wal -i "$1"
else
printf "nitrogen ir pywal missing"
read -r _
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
nnn-3.0/src/ 0000775 0000000 0000000 00000000000 13620656057 0012746 5 ustar 00root root 0000000 0000000 nnn-3.0/src/.clang-tidy 0000664 0000000 0000000 00000001617 13620656057 0015007 0 ustar 00root root 0000000 0000000 ---
Checks: 'clang-diagnostic-*,clang-analyzer-*,readability-*,modernize-*,bugprone-*,misc-*,-misc-unused-parameters,google-runtime-int,-llvm-header-guard,fuchsia-restrict-system-includes,-clang-analyzer-valist.Uninitialized,-clang-analyzer-security.insecureAPI.rand,-clang-analyzer-alpha.*,-readability-magic-numbers,-readability-braces-around-statements,-readability-isolate-declaration,-bugprone-narrowing-conversions'
WarningsAsErrors: '*'
HeaderFilterRegex: '.*(?