mimimum zsh plugins
This commit is contained in:
parent
dfd0ebf8c7
commit
28bae624a4
|
@ -13,3 +13,5 @@
|
|||
!.zsh/**
|
||||
!.tmux.conf
|
||||
!.gitconfig
|
||||
!.local
|
||||
!.local/**
|
||||
|
|
|
@ -0,0 +1,381 @@
|
|||
# ____ ____
|
||||
# / __/___ / __/
|
||||
# / /_/_ / / /_
|
||||
# / __/ / /_/ __/
|
||||
# /_/ /___/_/ completion.bash
|
||||
#
|
||||
# - $FZF_TMUX (default: 0)
|
||||
# - $FZF_TMUX_OPTS (default: empty)
|
||||
# - $FZF_COMPLETION_TRIGGER (default: '**')
|
||||
# - $FZF_COMPLETION_OPTS (default: empty)
|
||||
|
||||
if [[ $- =~ i ]]; then
|
||||
|
||||
# To use custom commands instead of find, override _fzf_compgen_{path,dir}
|
||||
if ! declare -f _fzf_compgen_path > /dev/null; then
|
||||
_fzf_compgen_path() {
|
||||
echo "$1"
|
||||
command find -L "$1" \
|
||||
-name .git -prune -o -name .hg -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
if ! declare -f _fzf_compgen_dir > /dev/null; then
|
||||
_fzf_compgen_dir() {
|
||||
command find -L "$1" \
|
||||
-name .git -prune -o -name .hg -prune -o -name .svn -prune -o -type d \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
###########################################################
|
||||
|
||||
# To redraw line after fzf closes (printf '\e[5n')
|
||||
bind '"\e[0n": redraw-current-line' 2> /dev/null
|
||||
|
||||
__fzf_comprun() {
|
||||
if [[ "$(type -t _fzf_comprun 2>&1)" = function ]]; then
|
||||
_fzf_comprun "$@"
|
||||
elif [[ -n "${TMUX_PANE-}" ]] && { [[ "${FZF_TMUX:-0}" != 0 ]] || [[ -n "${FZF_TMUX_OPTS-}" ]]; }; then
|
||||
shift
|
||||
fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- "$@"
|
||||
else
|
||||
shift
|
||||
fzf "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
__fzf_orig_completion() {
|
||||
local l comp f cmd
|
||||
while read -r l; do
|
||||
if [[ "$l" =~ ^(.*\ -F)\ *([^ ]*).*\ ([^ ]*)$ ]]; then
|
||||
comp="${BASH_REMATCH[1]}"
|
||||
f="${BASH_REMATCH[2]}"
|
||||
cmd="${BASH_REMATCH[3]}"
|
||||
[[ "$f" = _fzf_* ]] && continue
|
||||
printf -v "_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}" "%s" "${comp} %s ${cmd} #${f}"
|
||||
if [[ "$l" = *" -o nospace "* ]] && [[ ! "${__fzf_nospace_commands-}" = *" $cmd "* ]]; then
|
||||
__fzf_nospace_commands="${__fzf_nospace_commands-} $cmd "
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
_fzf_opts_completion() {
|
||||
local cur prev opts
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
opts="
|
||||
-x --extended
|
||||
-e --exact
|
||||
--algo
|
||||
-i +i
|
||||
-n --nth
|
||||
--with-nth
|
||||
-d --delimiter
|
||||
+s --no-sort
|
||||
--tac
|
||||
--tiebreak
|
||||
-m --multi
|
||||
--no-mouse
|
||||
--bind
|
||||
--cycle
|
||||
--no-hscroll
|
||||
--jump-labels
|
||||
--height
|
||||
--literal
|
||||
--reverse
|
||||
--margin
|
||||
--inline-info
|
||||
--prompt
|
||||
--pointer
|
||||
--marker
|
||||
--header
|
||||
--header-lines
|
||||
--ansi
|
||||
--tabstop
|
||||
--color
|
||||
--no-bold
|
||||
--history
|
||||
--history-size
|
||||
--preview
|
||||
--preview-window
|
||||
-q --query
|
||||
-1 --select-1
|
||||
-0 --exit-0
|
||||
-f --filter
|
||||
--print-query
|
||||
--expect
|
||||
--sync"
|
||||
|
||||
case "${prev}" in
|
||||
--tiebreak)
|
||||
COMPREPLY=( $(compgen -W "length begin end index" -- "$cur") )
|
||||
return 0
|
||||
;;
|
||||
--color)
|
||||
COMPREPLY=( $(compgen -W "dark light 16 bw" -- "$cur") )
|
||||
return 0
|
||||
;;
|
||||
--history)
|
||||
COMPREPLY=()
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$cur" =~ ^-|\+ ]]; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "$cur") )
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_fzf_handle_dynamic_completion() {
|
||||
local cmd orig_var orig ret orig_cmd orig_complete
|
||||
cmd="$1"
|
||||
shift
|
||||
orig_cmd="$1"
|
||||
orig_var="_fzf_orig_completion_$cmd"
|
||||
orig="${!orig_var-}"
|
||||
orig="${orig##*#}"
|
||||
if [[ -n "$orig" ]] && type "$orig" > /dev/null 2>&1; then
|
||||
$orig "$@"
|
||||
elif [[ -n "${_fzf_completion_loader-}" ]]; then
|
||||
orig_complete=$(complete -p "$orig_cmd" 2> /dev/null)
|
||||
_completion_loader "$@"
|
||||
ret=$?
|
||||
# _completion_loader may not have updated completion for the command
|
||||
if [[ "$(complete -p "$orig_cmd" 2> /dev/null)" != "$orig_complete" ]]; then
|
||||
__fzf_orig_completion < <(complete -p "$orig_cmd" 2> /dev/null)
|
||||
if [[ "${__fzf_nospace_commands-}" = *" $orig_cmd "* ]]; then
|
||||
eval "${orig_complete/ -F / -o nospace -F }"
|
||||
else
|
||||
eval "$orig_complete"
|
||||
fi
|
||||
fi
|
||||
return $ret
|
||||
fi
|
||||
}
|
||||
|
||||
__fzf_generic_path_completion() {
|
||||
local cur base dir leftover matches trigger cmd
|
||||
cmd="${COMP_WORDS[0]}"
|
||||
if [[ $cmd == \\* ]]; then
|
||||
cmd="${cmd:1}"
|
||||
fi
|
||||
cmd="${cmd//[^A-Za-z0-9_=]/_}"
|
||||
COMPREPLY=()
|
||||
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [[ "$cur" == *"$trigger" ]]; then
|
||||
base=${cur:0:${#cur}-${#trigger}}
|
||||
eval "base=$base"
|
||||
|
||||
dir=
|
||||
[[ $base = *"/"* ]] && dir="$base"
|
||||
while true; do
|
||||
if [[ -z "$dir" ]] || [[ -d "$dir" ]]; then
|
||||
leftover=${base/#"$dir"}
|
||||
leftover=${leftover/#\/}
|
||||
[[ -z "$dir" ]] && dir='.'
|
||||
[[ "$dir" != "/" ]] && dir="${dir/%\//}"
|
||||
matches=$(eval "$1 $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-} $2" __fzf_comprun "$4" -q "$leftover" | while read -r item; do
|
||||
printf "%q " "${item%$3}$3"
|
||||
done)
|
||||
matches=${matches% }
|
||||
[[ -z "$3" ]] && [[ "${__fzf_nospace_commands-}" = *" ${COMP_WORDS[0]} "* ]] && matches="$matches "
|
||||
if [[ -n "$matches" ]]; then
|
||||
COMPREPLY=( "$matches" )
|
||||
else
|
||||
COMPREPLY=( "$cur" )
|
||||
fi
|
||||
printf '\e[5n'
|
||||
return 0
|
||||
fi
|
||||
dir=$(dirname "$dir")
|
||||
[[ "$dir" =~ /$ ]] || dir="$dir"/
|
||||
done
|
||||
else
|
||||
shift
|
||||
shift
|
||||
shift
|
||||
_fzf_handle_dynamic_completion "$cmd" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
_fzf_complete() {
|
||||
# Split arguments around --
|
||||
local args rest str_arg i sep
|
||||
args=("$@")
|
||||
sep=
|
||||
for i in "${!args[@]}"; do
|
||||
if [[ "${args[$i]}" = -- ]]; then
|
||||
sep=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ -n "$sep" ]]; then
|
||||
str_arg=
|
||||
rest=("${args[@]:$((sep + 1)):${#args[@]}}")
|
||||
args=("${args[@]:0:$sep}")
|
||||
else
|
||||
str_arg=$1
|
||||
args=()
|
||||
shift
|
||||
rest=("$@")
|
||||
fi
|
||||
|
||||
local cur selected trigger cmd post
|
||||
post="$(caller 0 | awk '{print $2}')_post"
|
||||
type -t "$post" > /dev/null 2>&1 || post=cat
|
||||
|
||||
cmd="${COMP_WORDS[0]//[^A-Za-z0-9_=]/_}"
|
||||
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [[ "$cur" == *"$trigger" ]]; then
|
||||
cur=${cur:0:${#cur}-${#trigger}}
|
||||
|
||||
selected=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-} $str_arg" __fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | $post | tr '\n' ' ')
|
||||
selected=${selected% } # Strip trailing space not to repeat "-o nospace"
|
||||
if [[ -n "$selected" ]]; then
|
||||
COMPREPLY=("$selected")
|
||||
else
|
||||
COMPREPLY=("$cur")
|
||||
fi
|
||||
printf '\e[5n'
|
||||
return 0
|
||||
else
|
||||
_fzf_handle_dynamic_completion "$cmd" "${rest[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
_fzf_path_completion() {
|
||||
__fzf_generic_path_completion _fzf_compgen_path "-m" "" "$@"
|
||||
}
|
||||
|
||||
# Deprecated. No file only completion.
|
||||
_fzf_file_completion() {
|
||||
_fzf_path_completion "$@"
|
||||
}
|
||||
|
||||
_fzf_dir_completion() {
|
||||
__fzf_generic_path_completion _fzf_compgen_dir "" "/" "$@"
|
||||
}
|
||||
|
||||
_fzf_complete_kill() {
|
||||
_fzf_proc_completion "$@"
|
||||
}
|
||||
|
||||
_fzf_proc_completion() {
|
||||
_fzf_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <(
|
||||
command ps -ef | sed 1d
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_proc_completion_post() {
|
||||
awk '{print $2}'
|
||||
}
|
||||
|
||||
_fzf_host_completion() {
|
||||
_fzf_complete +m -- "$@" < <(
|
||||
command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?%]') \
|
||||
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
|
||||
<(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
|
||||
awk '{if (length($2) > 0) {print $2}}' | sort -u
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_var_completion() {
|
||||
_fzf_complete -m -- "$@" < <(
|
||||
declare -xp | sed -En 's|^declare [^ ]+ ([^=]+).*|\1|p'
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_alias_completion() {
|
||||
_fzf_complete -m -- "$@" < <(
|
||||
alias | sed -En 's|^alias ([^=]+).*|\1|p'
|
||||
)
|
||||
}
|
||||
|
||||
# fzf options
|
||||
complete -o default -F _fzf_opts_completion fzf
|
||||
# fzf-tmux is a thin fzf wrapper that has only a few more options than fzf
|
||||
# itself. As a quick improvement we take fzf's completion. Adding the few extra
|
||||
# fzf-tmux specific options (like `-w WIDTH`) are left as a future patch.
|
||||
complete -o default -F _fzf_opts_completion fzf-tmux
|
||||
|
||||
d_cmds="${FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir}"
|
||||
a_cmds="
|
||||
awk cat diff diff3
|
||||
emacs emacsclient ex file ftp g++ gcc gvim head hg java
|
||||
javac ld less more mvim nvim patch perl python ruby
|
||||
sed sftp sort source tail tee uniq vi view vim wc xdg-open
|
||||
basename bunzip2 bzip2 chmod chown curl cp dirname du
|
||||
find git grep gunzip gzip hg jar
|
||||
ln ls mv open rm rsync scp
|
||||
svn tar unzip zip"
|
||||
|
||||
# Preserve existing completion
|
||||
__fzf_orig_completion < <(complete -p $d_cmds $a_cmds 2> /dev/null)
|
||||
|
||||
if type _completion_loader > /dev/null 2>&1; then
|
||||
_fzf_completion_loader=1
|
||||
fi
|
||||
|
||||
__fzf_defc() {
|
||||
local cmd func opts orig_var orig def
|
||||
cmd="$1"
|
||||
func="$2"
|
||||
opts="$3"
|
||||
orig_var="_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}"
|
||||
orig="${!orig_var-}"
|
||||
if [[ -n "$orig" ]]; then
|
||||
printf -v def "$orig" "$func"
|
||||
eval "$def"
|
||||
else
|
||||
complete -F "$func" $opts "$cmd"
|
||||
fi
|
||||
}
|
||||
|
||||
# Anything
|
||||
for cmd in $a_cmds; do
|
||||
__fzf_defc "$cmd" _fzf_path_completion "-o default -o bashdefault"
|
||||
done
|
||||
|
||||
# Directory
|
||||
for cmd in $d_cmds; do
|
||||
__fzf_defc "$cmd" _fzf_dir_completion "-o nospace -o dirnames"
|
||||
done
|
||||
|
||||
unset cmd d_cmds a_cmds
|
||||
|
||||
_fzf_setup_completion() {
|
||||
local kind fn cmd
|
||||
kind=$1
|
||||
fn=_fzf_${1}_completion
|
||||
if [[ $# -lt 2 ]] || ! type -t "$fn" > /dev/null; then
|
||||
echo "usage: ${FUNCNAME[0]} path|dir|var|alias|host|proc COMMANDS..."
|
||||
return 1
|
||||
fi
|
||||
shift
|
||||
__fzf_orig_completion < <(complete -p "$@" 2> /dev/null)
|
||||
for cmd in "$@"; do
|
||||
case "$kind" in
|
||||
dir) __fzf_defc "$cmd" "$fn" "-o nospace -o dirnames" ;;
|
||||
var) __fzf_defc "$cmd" "$fn" "-o default -o nospace -v" ;;
|
||||
alias) __fzf_defc "$cmd" "$fn" "-a" ;;
|
||||
*) __fzf_defc "$cmd" "$fn" "-o default -o bashdefault" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Environment variables / Aliases / Hosts / Process
|
||||
_fzf_setup_completion 'var' export unset
|
||||
_fzf_setup_completion 'alias' unalias
|
||||
_fzf_setup_completion 'host' ssh telnet
|
||||
_fzf_setup_completion 'proc' kill
|
||||
|
||||
fi
|
|
@ -0,0 +1,324 @@
|
|||
# ____ ____
|
||||
# / __/___ / __/
|
||||
# / /_/_ / / /_
|
||||
# / __/ / /_/ __/
|
||||
# /_/ /___/_/ completion.zsh
|
||||
#
|
||||
# - $FZF_TMUX (default: 0)
|
||||
# - $FZF_TMUX_OPTS (default: '-d 40%')
|
||||
# - $FZF_COMPLETION_TRIGGER (default: '**')
|
||||
# - $FZF_COMPLETION_OPTS (default: empty)
|
||||
|
||||
# Both branches of the following `if` do the same thing -- define
|
||||
# __fzf_completion_options such that `eval $__fzf_completion_options` sets
|
||||
# all options to the same values they currently have. We'll do just that at
|
||||
# the bottom of the file after changing options to what we prefer.
|
||||
#
|
||||
# IMPORTANT: Until we get to the `emulate` line, all words that *can* be quoted
|
||||
# *must* be quoted in order to prevent alias expansion. In addition, code must
|
||||
# be written in a way works with any set of zsh options. This is very tricky, so
|
||||
# careful when you change it.
|
||||
#
|
||||
# Start by loading the builtin zsh/parameter module. It provides `options`
|
||||
# associative array that stores current shell options.
|
||||
if 'zmodload' 'zsh/parameter' 2>'/dev/null' && (( ${+options} )); then
|
||||
# This is the fast branch and it gets taken on virtually all Zsh installations.
|
||||
#
|
||||
# ${(kv)options[@]} expands to array of keys (option names) and values ("on"
|
||||
# or "off"). The subsequent expansion# with (j: :) flag joins all elements
|
||||
# together separated by spaces. __fzf_completion_options ends up with a value
|
||||
# like this: "options=(shwordsplit off aliases on ...)".
|
||||
__fzf_completion_options="options=(${(j: :)${(kv)options[@]}})"
|
||||
else
|
||||
# This branch is much slower because it forks to get the names of all
|
||||
# zsh options. It's possible to eliminate this fork but it's not worth the
|
||||
# trouble because this branch gets taken only on very ancient or broken
|
||||
# zsh installations.
|
||||
() {
|
||||
# That `()` above defines an anonymous function. This is essentially a scope
|
||||
# for local parameters. We use it to avoid polluting global scope.
|
||||
'local' '__fzf_opt'
|
||||
__fzf_completion_options="setopt"
|
||||
# `set -o` prints one line for every zsh option. Each line contains option
|
||||
# name, some spaces, and then either "on" or "off". We just want option names.
|
||||
# Expansion with (@f) flag splits a string into lines. The outer expansion
|
||||
# removes spaces and everything that follow them on every line. __fzf_opt
|
||||
# ends up iterating over option names: shwordsplit, aliases, etc.
|
||||
for __fzf_opt in "${(@)${(@f)$(set -o)}%% *}"; do
|
||||
if [[ -o "$__fzf_opt" ]]; then
|
||||
# Option $__fzf_opt is currently on, so remember to set it back on.
|
||||
__fzf_completion_options+=" -o $__fzf_opt"
|
||||
else
|
||||
# Option $__fzf_opt is currently off, so remember to set it back off.
|
||||
__fzf_completion_options+=" +o $__fzf_opt"
|
||||
fi
|
||||
done
|
||||
# The value of __fzf_completion_options here looks like this:
|
||||
# "setopt +o shwordsplit -o aliases ..."
|
||||
}
|
||||
fi
|
||||
|
||||
# Enable the default zsh options (those marked with <Z> in `man zshoptions`)
|
||||
# but without `aliases`. Aliases in functions are expanded when functions are
|
||||
# defined, so if we disable aliases here, we'll be sure to have no pesky
|
||||
# aliases in any of our functions. This way we won't need prefix every
|
||||
# command with `command` or to quote every word to defend against global
|
||||
# aliases. Note that `aliases` is not the only option that's important to
|
||||
# control. There are several others that could wreck havoc if they are set
|
||||
# to values we don't expect. With the following `emulate` command we
|
||||
# sidestep this issue entirely.
|
||||
'emulate' 'zsh' '-o' 'no_aliases'
|
||||
|
||||
# This brace is the start of try-always block. The `always` part is like
|
||||
# `finally` in lesser languages. We use it to *always* restore user options.
|
||||
{
|
||||
|
||||
# Bail out if not interactive shell.
|
||||
[[ -o interactive ]] || return 0
|
||||
|
||||
# To use custom commands instead of find, override _fzf_compgen_{path,dir}
|
||||
if ! declare -f _fzf_compgen_path > /dev/null; then
|
||||
_fzf_compgen_path() {
|
||||
echo "$1"
|
||||
command find -L "$1" \
|
||||
-name .git -prune -o -name .hg -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
if ! declare -f _fzf_compgen_dir > /dev/null; then
|
||||
_fzf_compgen_dir() {
|
||||
command find -L "$1" \
|
||||
-name .git -prune -o -name .hg -prune -o -name .svn -prune -o -type d \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
###########################################################
|
||||
|
||||
__fzf_comprun() {
|
||||
if [[ "$(type _fzf_comprun 2>&1)" =~ function ]]; then
|
||||
_fzf_comprun "$@"
|
||||
elif [ -n "${TMUX_PANE-}" ] && { [ "${FZF_TMUX:-0}" != 0 ] || [ -n "${FZF_TMUX_OPTS-}" ]; }; then
|
||||
shift
|
||||
if [ -n "${FZF_TMUX_OPTS-}" ]; then
|
||||
fzf-tmux ${(Q)${(Z+n+)FZF_TMUX_OPTS}} -- "$@"
|
||||
else
|
||||
fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%} -- "$@"
|
||||
fi
|
||||
else
|
||||
shift
|
||||
fzf "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# Extract the name of the command. e.g. foo=1 bar baz**<tab>
|
||||
__fzf_extract_command() {
|
||||
local token tokens
|
||||
tokens=(${(z)1})
|
||||
for token in $tokens; do
|
||||
token=${(Q)token}
|
||||
if [[ "$token" =~ [[:alnum:]] && ! "$token" =~ "=" ]]; then
|
||||
echo "$token"
|
||||
return
|
||||
fi
|
||||
done
|
||||
echo "${tokens[1]}"
|
||||
}
|
||||
|
||||
__fzf_generic_path_completion() {
|
||||
local base lbuf cmd compgen fzf_opts suffix tail dir leftover matches
|
||||
base=$1
|
||||
lbuf=$2
|
||||
cmd=$(__fzf_extract_command "$lbuf")
|
||||
compgen=$3
|
||||
fzf_opts=$4
|
||||
suffix=$5
|
||||
tail=$6
|
||||
|
||||
setopt localoptions nonomatch
|
||||
eval "base=$base"
|
||||
[[ $base = *"/"* ]] && dir="$base"
|
||||
while [ 1 ]; do
|
||||
if [[ -z "$dir" || -d ${dir} ]]; then
|
||||
leftover=${base/#"$dir"}
|
||||
leftover=${leftover/#\/}
|
||||
[ -z "$dir" ] && dir='.'
|
||||
[ "$dir" != "/" ] && dir="${dir/%\//}"
|
||||
matches=$(eval "$compgen $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-}" __fzf_comprun "$cmd" ${(Q)${(Z+n+)fzf_opts}} -q "$leftover" | while read item; do
|
||||
item="${item%$suffix}$suffix"
|
||||
echo -n "${(q)item} "
|
||||
done)
|
||||
matches=${matches% }
|
||||
if [ -n "$matches" ]; then
|
||||
LBUFFER="$lbuf$matches$tail"
|
||||
fi
|
||||
zle reset-prompt
|
||||
break
|
||||
fi
|
||||
dir=$(dirname "$dir")
|
||||
dir=${dir%/}/
|
||||
done
|
||||
}
|
||||
|
||||
_fzf_path_completion() {
|
||||
__fzf_generic_path_completion "$1" "$2" _fzf_compgen_path \
|
||||
"-m" "" " "
|
||||
}
|
||||
|
||||
_fzf_dir_completion() {
|
||||
__fzf_generic_path_completion "$1" "$2" _fzf_compgen_dir \
|
||||
"" "/" ""
|
||||
}
|
||||
|
||||
_fzf_feed_fifo() (
|
||||
command rm -f "$1"
|
||||
mkfifo "$1"
|
||||
cat <&0 > "$1" &
|
||||
)
|
||||
|
||||
_fzf_complete() {
|
||||
setopt localoptions ksh_arrays
|
||||
# Split arguments around --
|
||||
local args rest str_arg i sep
|
||||
args=("$@")
|
||||
sep=
|
||||
for i in {0..${#args[@]}}; do
|
||||
if [[ "${args[$i]-}" = -- ]]; then
|
||||
sep=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ -n "$sep" ]]; then
|
||||
str_arg=
|
||||
rest=("${args[@]:$((sep + 1)):${#args[@]}}")
|
||||
args=("${args[@]:0:$sep}")
|
||||
else
|
||||
str_arg=$1
|
||||
args=()
|
||||
shift
|
||||
rest=("$@")
|
||||
fi
|
||||
|
||||
local fifo lbuf cmd matches post
|
||||
fifo="${TMPDIR:-/tmp}/fzf-complete-fifo-$$"
|
||||
lbuf=${rest[0]}
|
||||
cmd=$(__fzf_extract_command "$lbuf")
|
||||
post="${funcstack[1]}_post"
|
||||
type $post > /dev/null 2>&1 || post=cat
|
||||
|
||||
_fzf_feed_fifo "$fifo"
|
||||
matches=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-} $str_arg" __fzf_comprun "$cmd" "${args[@]}" -q "${(Q)prefix}" < "$fifo" | $post | tr '\n' ' ')
|
||||
if [ -n "$matches" ]; then
|
||||
LBUFFER="$lbuf$matches"
|
||||
fi
|
||||
command rm -f "$fifo"
|
||||
}
|
||||
|
||||
_fzf_complete_telnet() {
|
||||
_fzf_complete +m -- "$@" < <(
|
||||
command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0' |
|
||||
awk '{if (length($2) > 0) {print $2}}' | sort -u
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_ssh() {
|
||||
_fzf_complete +m -- "$@" < <(
|
||||
setopt localoptions nonomatch
|
||||
command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?%]') \
|
||||
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
|
||||
<(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
|
||||
awk '{if (length($2) > 0) {print $2}}' | sort -u
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_export() {
|
||||
_fzf_complete -m -- "$@" < <(
|
||||
declare -xp | sed 's/=.*//' | sed 's/.* //'
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_unset() {
|
||||
_fzf_complete -m -- "$@" < <(
|
||||
declare -xp | sed 's/=.*//' | sed 's/.* //'
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_unalias() {
|
||||
_fzf_complete +m -- "$@" < <(
|
||||
alias | sed 's/=.*//'
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_kill() {
|
||||
_fzf_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <(
|
||||
command ps -ef | sed 1d
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_kill_post() {
|
||||
awk '{print $2}'
|
||||
}
|
||||
|
||||
fzf-completion() {
|
||||
local tokens cmd prefix trigger tail matches lbuf d_cmds
|
||||
setopt localoptions noshwordsplit noksh_arrays noposixbuiltins
|
||||
|
||||
# http://zsh.sourceforge.net/FAQ/zshfaq03.html
|
||||
# http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion-Flags
|
||||
tokens=(${(z)LBUFFER})
|
||||
if [ ${#tokens} -lt 1 ]; then
|
||||
zle ${fzf_default_completion:-expand-or-complete}
|
||||
return
|
||||
fi
|
||||
|
||||
cmd=$(__fzf_extract_command "$LBUFFER")
|
||||
|
||||
# Explicitly allow for empty trigger.
|
||||
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||
[ -z "$trigger" -a ${LBUFFER[-1]} = ' ' ] && tokens+=("")
|
||||
|
||||
# When the trigger starts with ';', it becomes a separate token
|
||||
if [[ ${LBUFFER} = *"${tokens[-2]-}${tokens[-1]}" ]]; then
|
||||
tokens[-2]="${tokens[-2]-}${tokens[-1]}"
|
||||
tokens=(${tokens[0,-2]})
|
||||
fi
|
||||
|
||||
lbuf=$LBUFFER
|
||||
tail=${LBUFFER:$(( ${#LBUFFER} - ${#trigger} ))}
|
||||
|
||||
# Trigger sequence given
|
||||
if [ ${#tokens} -gt 1 -a "$tail" = "$trigger" ]; then
|
||||
d_cmds=(${=FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir})
|
||||
|
||||
[ -z "$trigger" ] && prefix=${tokens[-1]} || prefix=${tokens[-1]:0:-${#trigger}}
|
||||
[ -n "${tokens[-1]}" ] && lbuf=${lbuf:0:-${#tokens[-1]}}
|
||||
|
||||
if eval "type _fzf_complete_${cmd} > /dev/null"; then
|
||||
prefix="$prefix" eval _fzf_complete_${cmd} ${(q)lbuf}
|
||||
zle reset-prompt
|
||||
elif [ ${d_cmds[(i)$cmd]} -le ${#d_cmds} ]; then
|
||||
_fzf_dir_completion "$prefix" "$lbuf"
|
||||
else
|
||||
_fzf_path_completion "$prefix" "$lbuf"
|
||||
fi
|
||||
# Fall back to default completion
|
||||
else
|
||||
zle ${fzf_default_completion:-expand-or-complete}
|
||||
fi
|
||||
}
|
||||
|
||||
[ -z "$fzf_default_completion" ] && {
|
||||
binding=$(bindkey '^I')
|
||||
[[ $binding =~ 'undefined-key' ]] || fzf_default_completion=$binding[(s: :w)2]
|
||||
unset binding
|
||||
}
|
||||
|
||||
zle -N fzf-completion
|
||||
bindkey '^I' fzf-completion
|
||||
|
||||
} always {
|
||||
# Restore the original options.
|
||||
eval $__fzf_completion_options
|
||||
'unset' '__fzf_completion_options'
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
# ____ ____
|
||||
# / __/___ / __/
|
||||
# / /_/_ / / /_
|
||||
# / __/ / /_/ __/
|
||||
# /_/ /___/_/ key-bindings.bash
|
||||
#
|
||||
# - $FZF_TMUX_OPTS
|
||||
# - $FZF_CTRL_T_COMMAND
|
||||
# - $FZF_CTRL_T_OPTS
|
||||
# - $FZF_CTRL_R_OPTS
|
||||
# - $FZF_ALT_C_COMMAND
|
||||
# - $FZF_ALT_C_OPTS
|
||||
|
||||
# Key bindings
|
||||
# ------------
|
||||
__fzf_select__() {
|
||||
local cmd opts
|
||||
cmd="${FZF_CTRL_T_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
||||
-o -type f -print \
|
||||
-o -type d -print \
|
||||
-o -type l -print 2> /dev/null | cut -b3-"}"
|
||||
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse ${FZF_DEFAULT_OPTS-} ${FZF_CTRL_T_OPTS-} -m"
|
||||
eval "$cmd" |
|
||||
FZF_DEFAULT_OPTS="$opts" $(__fzfcmd) "$@" |
|
||||
while read -r item; do
|
||||
printf '%q ' "$item" # escape special chars
|
||||
done
|
||||
}
|
||||
|
||||
if [[ $- =~ i ]]; then
|
||||
|
||||
__fzfcmd() {
|
||||
[[ -n "${TMUX_PANE-}" ]] && { [[ "${FZF_TMUX:-0}" != 0 ]] || [[ -n "${FZF_TMUX_OPTS-}" ]]; } &&
|
||||
echo "fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- " || echo "fzf"
|
||||
}
|
||||
|
||||
fzf-file-widget() {
|
||||
local selected="$(__fzf_select__ "$@")"
|
||||
READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$selected${READLINE_LINE:$READLINE_POINT}"
|
||||
READLINE_POINT=$(( READLINE_POINT + ${#selected} ))
|
||||
}
|
||||
|
||||
__fzf_cd__() {
|
||||
local cmd opts dir
|
||||
cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
||||
-o -type d -print 2> /dev/null | cut -b3-"}"
|
||||
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse ${FZF_DEFAULT_OPTS-} ${FZF_ALT_C_OPTS-} +m"
|
||||
dir=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" $(__fzfcmd)) && printf 'builtin cd -- %q' "$dir"
|
||||
}
|
||||
|
||||
__fzf_history__() {
|
||||
local output opts script
|
||||
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} -n2..,.. --scheme=history --bind=ctrl-r:toggle-sort ${FZF_CTRL_R_OPTS-} +m --read0"
|
||||
script='BEGIN { getc; $/ = "\n\t"; $HISTCOUNT = $ENV{last_hist} + 1 } s/^[ *]//; print $HISTCOUNT - $. . "\t$_" if !$seen{$_}++'
|
||||
output=$(
|
||||
builtin fc -lnr -2147483648 |
|
||||
last_hist=$(HISTTIMEFORMAT='' builtin history 1) perl -n -l0 -e "$script" |
|
||||
FZF_DEFAULT_OPTS="$opts" $(__fzfcmd) --query "$READLINE_LINE"
|
||||
) || return
|
||||
READLINE_LINE=${output#*$'\t'}
|
||||
if [[ -z "$READLINE_POINT" ]]; then
|
||||
echo "$READLINE_LINE"
|
||||
else
|
||||
READLINE_POINT=0x7fffffff
|
||||
fi
|
||||
}
|
||||
|
||||
# Required to refresh the prompt after fzf
|
||||
bind -m emacs-standard '"\er": redraw-current-line'
|
||||
|
||||
bind -m vi-command '"\C-z": emacs-editing-mode'
|
||||
bind -m vi-insert '"\C-z": emacs-editing-mode'
|
||||
bind -m emacs-standard '"\C-z": vi-editing-mode'
|
||||
|
||||
if (( BASH_VERSINFO[0] < 4 )); then
|
||||
# CTRL-T - Paste the selected file path into the command line
|
||||
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__fzf_select__`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f"'
|
||||
bind -m vi-command '"\C-t": "\C-z\C-t\C-z"'
|
||||
bind -m vi-insert '"\C-t": "\C-z\C-t\C-z"'
|
||||
|
||||
# CTRL-R - Paste the selected command from history into the command line
|
||||
bind -m emacs-standard '"\C-r": "\C-e \C-u\C-y\ey\C-u"$(__fzf_history__)"\e\C-e\er"'
|
||||
bind -m vi-command '"\C-r": "\C-z\C-r\C-z"'
|
||||
bind -m vi-insert '"\C-r": "\C-z\C-r\C-z"'
|
||||
else
|
||||
# CTRL-T - Paste the selected file path into the command line
|
||||
bind -m emacs-standard -x '"\C-t": fzf-file-widget'
|
||||
bind -m vi-command -x '"\C-t": fzf-file-widget'
|
||||
bind -m vi-insert -x '"\C-t": fzf-file-widget'
|
||||
|
||||
# CTRL-R - Paste the selected command from history into the command line
|
||||
bind -m emacs-standard -x '"\C-r": __fzf_history__'
|
||||
bind -m vi-command -x '"\C-r": __fzf_history__'
|
||||
bind -m vi-insert -x '"\C-r": __fzf_history__'
|
||||
fi
|
||||
|
||||
# ALT-C - cd into the selected directory
|
||||
bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__fzf_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d"'
|
||||
bind -m vi-command '"\ec": "\C-z\ec\C-z"'
|
||||
bind -m vi-insert '"\ec": "\C-z\ec\C-z"'
|
||||
|
||||
fi
|
|
@ -0,0 +1,121 @@
|
|||
# ____ ____
|
||||
# / __/___ / __/
|
||||
# / /_/_ / / /_
|
||||
# / __/ / /_/ __/
|
||||
# /_/ /___/_/ key-bindings.zsh
|
||||
#
|
||||
# - $FZF_TMUX_OPTS
|
||||
# - $FZF_CTRL_T_COMMAND
|
||||
# - $FZF_CTRL_T_OPTS
|
||||
# - $FZF_CTRL_R_OPTS
|
||||
# - $FZF_ALT_C_COMMAND
|
||||
# - $FZF_ALT_C_OPTS
|
||||
|
||||
# Key bindings
|
||||
# ------------
|
||||
|
||||
# The code at the top and the bottom of this file is the same as in completion.zsh.
|
||||
# Refer to that file for explanation.
|
||||
if 'zmodload' 'zsh/parameter' 2>'/dev/null' && (( ${+options} )); then
|
||||
__fzf_key_bindings_options="options=(${(j: :)${(kv)options[@]}})"
|
||||
else
|
||||
() {
|
||||
__fzf_key_bindings_options="setopt"
|
||||
'local' '__fzf_opt'
|
||||
for __fzf_opt in "${(@)${(@f)$(set -o)}%% *}"; do
|
||||
if [[ -o "$__fzf_opt" ]]; then
|
||||
__fzf_key_bindings_options+=" -o $__fzf_opt"
|
||||
else
|
||||
__fzf_key_bindings_options+=" +o $__fzf_opt"
|
||||
fi
|
||||
done
|
||||
}
|
||||
fi
|
||||
|
||||
'emulate' 'zsh' '-o' 'no_aliases'
|
||||
|
||||
{
|
||||
|
||||
[[ -o interactive ]] || return 0
|
||||
|
||||
# CTRL-T - Paste the selected file path(s) into the command line
|
||||
__fsel() {
|
||||
local cmd="${FZF_CTRL_T_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
||||
-o -type f -print \
|
||||
-o -type d -print \
|
||||
-o -type l -print 2> /dev/null | cut -b3-"}"
|
||||
setopt localoptions pipefail no_aliases 2> /dev/null
|
||||
local item
|
||||
eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_CTRL_T_OPTS-}" $(__fzfcmd) -m "$@" | while read item; do
|
||||
echo -n "${(q)item} "
|
||||
done
|
||||
local ret=$?
|
||||
echo
|
||||
return $ret
|
||||
}
|
||||
|
||||
__fzfcmd() {
|
||||
[ -n "${TMUX_PANE-}" ] && { [ "${FZF_TMUX:-0}" != 0 ] || [ -n "${FZF_TMUX_OPTS-}" ]; } &&
|
||||
echo "fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- " || echo "fzf"
|
||||
}
|
||||
|
||||
fzf-file-widget() {
|
||||
LBUFFER="${LBUFFER}$(__fsel)"
|
||||
local ret=$?
|
||||
zle reset-prompt
|
||||
return $ret
|
||||
}
|
||||
zle -N fzf-file-widget
|
||||
bindkey -M emacs '^T' fzf-file-widget
|
||||
bindkey -M vicmd '^T' fzf-file-widget
|
||||
bindkey -M viins '^T' fzf-file-widget
|
||||
|
||||
# ALT-C - cd into the selected directory
|
||||
fzf-cd-widget() {
|
||||
local cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
||||
-o -type d -print 2> /dev/null | cut -b3-"}"
|
||||
setopt localoptions pipefail no_aliases 2> /dev/null
|
||||
local dir="$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_ALT_C_OPTS-}" $(__fzfcmd) +m)"
|
||||
if [[ -z "$dir" ]]; then
|
||||
zle redisplay
|
||||
return 0
|
||||
fi
|
||||
zle push-line # Clear buffer. Auto-restored on next prompt.
|
||||
BUFFER="builtin cd -- ${(q)dir}"
|
||||
zle accept-line
|
||||
local ret=$?
|
||||
unset dir # ensure this doesn't end up appearing in prompt expansion
|
||||
zle reset-prompt
|
||||
return $ret
|
||||
}
|
||||
zle -N fzf-cd-widget
|
||||
bindkey -M emacs '\ec' fzf-cd-widget
|
||||
bindkey -M vicmd '\ec' fzf-cd-widget
|
||||
bindkey -M viins '\ec' fzf-cd-widget
|
||||
|
||||
# CTRL-R - Paste the selected command from history into the command line
|
||||
# EDIT BY plex: removed --scheme-history , as it causes errors on some debian based systems as it seems.
|
||||
fzf-history-widget() {
|
||||
local selected num
|
||||
setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
|
||||
selected=( $(fc -rl 1 | awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
|
||||
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} ${FZF_DEFAULT_OPTS-} -n2..,.. --bind=ctrl-r:toggle-sort,ctrl-z:ignore ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
|
||||
local ret=$?
|
||||
if [ -n "$selected" ]; then
|
||||
num=$selected[1]
|
||||
if [ -n "$num" ]; then
|
||||
zle vi-fetch-history -n $num
|
||||
fi
|
||||
fi
|
||||
zle reset-prompt
|
||||
return $ret
|
||||
}
|
||||
zle -N fzf-history-widget
|
||||
bindkey -M emacs '^R' fzf-history-widget
|
||||
bindkey -M vicmd '^R' fzf-history-widget
|
||||
bindkey -M viins '^R' fzf-history-widget
|
||||
|
||||
} always {
|
||||
eval $__fzf_key_bindings_options
|
||||
'unset' '__fzf_key_bindings_options'
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Copy selection to system clipboard as newline-separated entries
|
||||
# Dependencies:
|
||||
# - tr
|
||||
# - xclip/xsel (Linux)
|
||||
# - pbcopy (macOS)
|
||||
# - termux-clipboard-set (Termux)
|
||||
# - clip.exe (WSL)
|
||||
# - clip (Cygwin)
|
||||
# - wl-copy (Wayland)
|
||||
# - clipboard (Haiku)
|
||||
#
|
||||
# Limitation: breaks if a filename has newline in it
|
||||
#
|
||||
# Note: For a space-separated list:
|
||||
# xargs -0 < "$SELECTION"
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
IFS="$(printf '%b_' '\n')"; IFS="${IFS%_}" # protect trailing \n
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
[ -s "$selection" ] || { echo "plugin .cbcp error: empty selection" >&2 ; exit 1; }
|
||||
|
||||
if type xsel >/dev/null 2>&1; then
|
||||
# Linux
|
||||
tr '\0' '\n' < "$selection" | xsel -bi
|
||||
elif type xclip >/dev/null 2>&1; then
|
||||
# Linux
|
||||
tr '\0' '\n' < "$selection" | xclip -sel clip
|
||||
elif type pbcopy >/dev/null 2>&1; then
|
||||
# macOS
|
||||
tr '\0' '\n' < "$selection" | pbcopy
|
||||
elif type termux-clipboard-set >/dev/null 2>&1; then
|
||||
# Termux
|
||||
tr '\0' '\n' < "$selection" | termux-clipboard-set
|
||||
elif type clip.exe >/dev/null 2>&1; then
|
||||
# WSL
|
||||
tr '\0' '\n' < "$selection" | clip.exe
|
||||
elif type clip >/dev/null 2>&1; then
|
||||
# Cygwin
|
||||
tr '\0' '\n' < "$selection" | clip
|
||||
elif type wl-copy >/dev/null 2>&1; then
|
||||
# Wayland
|
||||
tr '\0' '\n' < "$selection" | wl-copy
|
||||
elif type clipboard >/dev/null 2>&1; then
|
||||
# Haiku
|
||||
tr '\0' '\n' < "$selection" | clipboard --stdin
|
||||
fi
|
|
@ -0,0 +1,428 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Print icons in front of list of directories/files
|
||||
|
||||
# Dependencies: awk
|
||||
|
||||
# Usage
|
||||
# 1. Set colors and/or icons to your liking
|
||||
# 2. Pipe any directory listing to iconlookup and it will output prepended icons
|
||||
# 3. preview-tui uses the script to prepend icon to directory listings
|
||||
# 4. Aditionally you can consider adding it to your PATH and/or FZF_DEFAULT_COMMAND to
|
||||
# make it work with various fzf plugins (make sure you also add --ansi to your FZF_DEFAULT_OPTS)
|
||||
|
||||
# Shell: POSIX compliant
|
||||
|
||||
# Author: Luuk van Baal (https://github.com/luukvbaal/iconlookup)
|
||||
|
||||
icon_lookup() {
|
||||
awk 'BEGIN {
|
||||
# Set your ANSI colorscheme below (https://en.wikipedia.org/wiki/ANSI_escape_code#Colors).
|
||||
# Default uses standard nnn icon colors, 8 and 24-bit nord themes are commented out.
|
||||
colordepth=8 #colordepth=8 #colordepth=24
|
||||
color_dirtxt=39 #color_dirtxt=111 #color_dirtxt="129;161;193"
|
||||
color_filetxt=15 #color_filetxt=111 #color_filetxt="129;161;193"
|
||||
color_default=39 #color_default=111 #color_default="129;161;193"
|
||||
color_video=93 #color_video=110 #color_video="136;192;208"
|
||||
color_audio=220 #color_audio=150 #color_audio="163;190;140"
|
||||
color_image=82 #color_image=150 #color_image="163;190;140"
|
||||
color_docs=202 #color_docs=173 #color_docs="208;135;112"
|
||||
color_archive=209 #color_archive=179 #color_archive="235;203;139"
|
||||
color_c=81 #color_c=150 #color_c="163;190;140"
|
||||
color_java=32 #color_java=139 #color_java="180;142;173"
|
||||
color_js=47 #color_js=109 #color_js="143;188;187"
|
||||
color_react=39 #color_react=111 #color_react="129;161;193"
|
||||
color_css=199 #color_css=110 #color_css="136;192;208"
|
||||
color_python=227 #color_python=68 #color_python="94;129;172"
|
||||
color_lua=19 #color_lua=167 #color_lua="191;97;106"
|
||||
color_document=15 #color_document=173 #color_document="208;135;112"
|
||||
color_fsharp=31 #color_fsharp=179 #color_fsharp="180;142;173"
|
||||
color_ruby=160 #color_ruby=150 #color_ruby="163;190;140"
|
||||
color_scala=196 #color_scala=139 #color_scala="143;188;187"
|
||||
color_shell=47 #color_shell=109 #color_shell="143;188;187"
|
||||
color_vim=28 #color_vim=109 #color_vim="143;188;187"
|
||||
|
||||
# icons[][1] contains icon and icons[][2] contains color
|
||||
icons["directory"][1] = ""; icons["directory"][2] = color_default
|
||||
icons["file"][1] = ""; icons["file"][2] = color_default
|
||||
icons["exec"][1] = ""; icons["exec"][2] = color_default
|
||||
icons["manual"][1] = ""; icons["manual"][2] = color_docs
|
||||
icons["pipe"][1] = "ﳣ"; icons["pipe"][2] = color_default
|
||||
icons["socket"][1] = "ﳧ"; icons["socket"][2] = color_default
|
||||
icons["door"][1] = "➡"; icons["door"][2] = color_default
|
||||
|
||||
# top level and common icons
|
||||
icons[".git"][1] = ""; icons[".git"][2] = color_default
|
||||
icons["desktop"][1] = "ﲾ"; icons["desktop"][2] = color_default
|
||||
icons["briefcase"][1] = ""; icons["briefcase"][2] = color_default
|
||||
icons["document"][1] = ""; icons["document"][2] = color_default
|
||||
icons["downloads"][1] = ""; icons["downloads"][2] = color_default
|
||||
icons["music"][1] = ""; icons["music"][2] = color_default
|
||||
icons["musicfile"][1] = ""; icons["musicfile"][2] = color_audio
|
||||
icons["pictures"][1] = ""; icons["pictures"][2] = color_default
|
||||
icons["picturefile"][1] = ""; icons["picturefile"][2] = color_image
|
||||
icons["public"][1] = ""; icons["public"][2] = color_default
|
||||
icons["templates"][1] = "陼"; icons["templates"][2] = color_default
|
||||
icons["videos"][1] = ""; icons["videos"][2] = color_default
|
||||
icons["videofile"][1] = "ﳜ"; icons["videofile"][2] = color_video
|
||||
icons["changelog"][1] = ""; icons["changelog"][2] = color_docs
|
||||
icons["configure"][1] = ""; icons["configure"][2] = color_default
|
||||
icons["license"][1] = ""; icons["license"][2] = color_docs
|
||||
icons["makefile"][1] = ""; icons["makefile"][2] = color_default
|
||||
icons["archive"][1] = ""; icons["archive"][2] = color_archive
|
||||
icons["script"][1] = ""; icons["script"][2] = color_shell
|
||||
icons["cplusplus"][1] = ""; icons["cplusplus"][2] = color_c
|
||||
icons["java"][1] = ""; icons["java"][2] = color_java
|
||||
icons["clojure"][1] = ""; icons["clojure"][2] = color_default
|
||||
icons["js"][1] = ""; icons["js"][2] = color_js
|
||||
icons["linux"][1] = ""; icons["linux"][2] = color_default
|
||||
icons["fsharp"][1] = ""; icons["fsharp"][2] = color_fsharp
|
||||
icons["ruby"][1] = ""; icons["ruby"][2] = color_ruby
|
||||
icons["c"][1] = ""; icons["c"][2] = color_c
|
||||
icons["chess"][1] = ""; icons["chess"][2] = color_default
|
||||
icons["haskell"][1] = ""; icons["haskell"][2] = color_vim
|
||||
icons["html"][1] = ""; icons["html"][2] = color_default
|
||||
icons["react"][1] = ""; icons["react"][2] = color_react
|
||||
icons["python"][1] = ""; icons["python"][2] = color_python
|
||||
icons["database"][1] = ""; icons["database"][2] = color_default
|
||||
icons["worddoc"][1] = ""; icons["worddoc"][2] = color_document
|
||||
icons["playlist"][1] = "蘿"; icons["playlist"][2] = color_audio
|
||||
icons["opticaldisk"][1] = ""; icons["opticaldisk"][2] = color_archive
|
||||
|
||||
# numbers
|
||||
icons["1"][1] = icons["manual"][1]; icons["1"][2] = icons["manual"][2]
|
||||
icons["7z"][1] = icons["archive"][1]; icons["7z"][2] = icons["archive"][2]
|
||||
|
||||
# a
|
||||
icons["a"][1] = icons["manual"][1]; icons["a"][2] = icons["manual"][2]
|
||||
icons["apk"][1] = icons["archive"][1]; icons["apk"][2] = icons["archive"][2]
|
||||
icons["asm"][1] = icons["file"][1]; icons["asm"][2] = icons["file"][2]
|
||||
icons["aup"][1] = icons["musicfile"][1]; icons["aup"][2] = icons["musicfile"][2]
|
||||
icons["avi"][1] = icons["videofile"][1]; icons["avi"][2] = icons["videofile"][2]
|
||||
|
||||
# b
|
||||
icons["bat"][1] = icons["script"][1]; icons["bat"][2] = icons["script"][2]
|
||||
icons["bin"][1] = ""; icons["bin"][2] = color_default
|
||||
icons["bmp"][1] = icons["picturefile"][1]; icons["bmp"][2] = icons["picturefile"][2]
|
||||
icons["bz2"][1] = icons["archive"][1]; icons["bz2"][2] = icons["archive"][2]
|
||||
|
||||
# c
|
||||
icons["cplusplus"][1] = icons["cplusplus"][1]; icons["cplusplus"][2] = icons["cplusplus"][2]
|
||||
icons["cabal"][1] = icons["haskell"][1]; icons["cab"][2] = icons["haskell"][2]
|
||||
icons["cab"][1] = icons["archive"][1]; icons["cab"][2] = icons["archive"][2]
|
||||
icons["cbr"][1] = icons["archive"][1]; icons["cbr"][2] = icons["archive"][2]
|
||||
icons["cbz"][1] = icons["archive"][1]; icons["cbz"][2] = icons["archive"][2]
|
||||
icons["cc"][1] = icons["cplusplus"][1]; icons["cc"][2] = icons["cplusplus"][2]
|
||||
icons["class"][1] = icons["java"][1]; icons["class"][2] = icons["java"][2]
|
||||
icons["clj"][1] = icons["clojure"][1]; icons["clj"][2] = icons["clojure"][2]
|
||||
icons["cljc"][1] = icons["clojure"][1]; icons["cljc"][2] = icons["clojure"][2]
|
||||
icons["cljs"][1] = icons["clojure"][1]; icons["cljs"][2] = icons["clojure"][2]
|
||||
icons["cmake"][1] = icons["makefile"][1]; icons["cmake"][2] = icons["makefile"][2]
|
||||
icons["coffee"][1] = ""; icons["coffee"][2] = color_default
|
||||
icons["conf"][1] = icons["configure"][1]; icons["conf"][2] = icons["configure"][2]
|
||||
icons["cpio"][1] = icons["archive"][1]; icons["cpio"][2] = icons["archive"][2]
|
||||
icons["cpp"][1] = icons["cplusplus"][1]; icons["cpp"][2] = icons["cplusplus"][2]
|
||||
icons["css"][1] = ""; icons["css"][2] = color_css
|
||||
icons["cue"][1] = icons["playlist"][1]; icons["cue"][2] = icons["playlist"][2]
|
||||
icons["cvs"][1] = icons["configure"][1]; icons["cvs"][2] = icons["configure"][2]
|
||||
icons["cxx"][1] = icons["cplusplus"][1]; icons["cxx"][2] = icons["cplusplus"][2]
|
||||
|
||||
# d
|
||||
icons["db"][1] = icons["database"][1]; icons["db"][2] = icons["database"][2]
|
||||
icons["deb"][1] = ""; icons["deb"][2] = color_archive
|
||||
icons["diff"][1] = ""; icons["diff"][2] = color_default
|
||||
icons["dll"][1] = icons["script"][1]; icons["dll"][2] = icons["script"][2]
|
||||
icons["doc"][1] = icons["worddoc"][1]; icons["doc"][2] = icons["worddoc"][2]
|
||||
icons["docx"][1] = icons["worddoc"][1]; icons["docx"][2] = icons["worddoc"][2]
|
||||
|
||||
# e
|
||||
icons["ejs"][1] = icons["js"][1]; icons["ejs"][2] = icons["js"][2]
|
||||
icons["elf"][1] = icons["linux"][1]; icons["elf"][2] = icons["linux"][2]
|
||||
icons["epub"][1] = icons["manual"][1]; icons["epub"][2] = icons["manual"][2]
|
||||
icons["exe"][1] = icons["exec"][1]; icons["exe"][2] = icons["exec"][2]
|
||||
|
||||
# f
|
||||
icons["fsharp"][1] = icons["fsharp"][1]; icons["fsharp"][2] = icons["fsharp"][2]
|
||||
icons["flac"][1] = icons["musicfile"][1]; icons["flac"][2] = icons["musicfile"][2]
|
||||
icons["fen"][1] = icons["chess"][1]; icons["fen"][2] = icons["chess"][2]
|
||||
icons["flv"][1] = icons["videofile"][1]; icons["flv"][2] = icons["videofile"][2]
|
||||
icons["fs"][1] = icons["fsharp"][1]; icons["fs"][2] = icons["fsharp"][2]
|
||||
icons["fsi"][1] = icons["fsharp"][1]; icons["fsi"][2] = icons["fsharp"][2]
|
||||
icons["fsscript"][1] = icons["fsharp"][1]; icons["fsscript"][2] = icons["fsharp"][2]
|
||||
icons["fsx"][1] = icons["fsharp"][1]; icons["fsx"][2] = icons["fsharp"][2]
|
||||
|
||||
# g
|
||||
icons["gem"][1] = icons["ruby"][1]; icons["gem"][2] = icons["ruby"][2]
|
||||
icons["gif"][1] = icons["picturefile"][1]; icons["gif"][2] = icons["picturefile"][2]
|
||||
icons["go"][1] = "ﳑ"; icons["go"][2] = color_default
|
||||
icons["gz"][1] = icons["archive"][1]; icons["gz"][2] = icons["archive"][2]
|
||||
icons["gzip"][1] = icons["archive"][1]; icons["gzip"][2] = icons["archive"][2]
|
||||
|
||||
# h
|
||||
icons["h"][1] = icons["c"][1]; icons["h"][2] = icons["c"][2]
|
||||
icons["hh"][1] = icons["cplusplus"][1]; icons["hh"][2] = icons["cplusplus"][2]
|
||||
icons["hpp"][1] = icons["cplusplus"][1]; icons["hpp"][2] = icons["cplusplus"][2]
|
||||
icons["hs"][1] = icons["haskell"][1]; icons["hs"][2] = icons["haskell"][2]
|
||||
icons["htaccess"][1] = icons["configure"][1]; icons["htaccess"][2] = icons["configure"][2]
|
||||
icons["htpasswd"][1] = icons["configure"][1]; icons["htpasswd"][2] = icons["configure"][2]
|
||||
icons["htm"][1] = icons["html"][1]; icons["htm"][2] = icons["html"][2]
|
||||
icons["hxx"][1] = icons["cplusplus"][1]; icons["hxx"][2] = icons["cplusplus"][2]
|
||||
|
||||
# i
|
||||
icons["ico"][1] = icons["picturefile"][1]; icons["ico"][2] = icons["picturefile"][2]
|
||||
icons["img"][1] = icons["opticaldisk"][1]; icons["img"][2] = icons["opticaldisk"][2]
|
||||
icons["ini"][1] = icons["configure"][1]; icons["ini"][2] = icons["configure"][2]
|
||||
icons["iso"][1] = icons["opticaldisk"][1]; icons["iso"][2] = icons["opticaldisk"][2]
|
||||
|
||||
# j
|
||||
icons["jar"][1] = icons["java"][1]; icons["jar"][2] = icons["java"][2]
|
||||
icons["java"][1] = icons["java"][1]; icons["java"][2] = icons["java"][2]
|
||||
icons["jl"][1] = icons["configure"][1]; icons["jl"][2] = icons["configure"][2]
|
||||
icons["jpeg"][1] = icons["picturefile"][1]; icons["jpeg"][2] = icons["picturefile"][2]
|
||||
icons["jpg"][1] = icons["picturefile"][1]; icons["jpg"][2] = icons["picturefile"][2]
|
||||
icons["json"][1] = "ﬥ"; icons["json"][2] = color_js
|
||||
icons["jsx"][1] = icons["react"][1]; icons["jsx"][2] = icons["react"][2]
|
||||
|
||||
# k
|
||||
|
||||
# l
|
||||
icons["lha"][1] = icons["archive"][1]; icons["lha"][2] = icons["archive"][2]
|
||||
icons["lhs"][1] = icons["haskell"][1]; icons["lhs"][2] = icons["haskell"][2]
|
||||
icons["ilog"][1] = icons["document"][1]; icons["ilog"][2] = icons["document"][2]
|
||||
icons["lua"][1] = ""; icons["lua"][2] = color_lua
|
||||
icons["lzh"][1] = icons["archive"][1]; icons["lzh"][2] = icons["archive"][2]
|
||||
icons["lzma"][1] = icons["archive"][1]; icons["lzma"][2] = icons["archive"][2]
|
||||
|
||||
# m
|
||||
icons["m"][1] = "ﴜ"; icons["mat"][2] = color_c
|
||||
icons["m4a"][1] = icons["musicfile"][1]; icons["m4a"][2] = icons["musicfile"][2]
|
||||
icons["m4v"][1] = icons["videofile"][1]; icons["m4v"][2] = icons["videofile"][2]
|
||||
icons["mat"][1] = ""; icons["mat"][2] = color_c
|
||||
icons["markdown"][1] = ""; icons["markdown"][2] = color_docs
|
||||
icons["md"][1] = ""; icons["md"][2] = color_docs
|
||||
icons["mk"][1] = icons["makefile"][1]; icons["mk"][2] = icons["makefile"][2]
|
||||
icons["mkv"][1] = icons["videofile"][1]; icons["mkv"][2] = icons["videofile"][2]
|
||||
icons["mov"][1] = icons["videofile"][1]; icons["mov"][2] = icons["videofile"][2]
|
||||
icons["mp3"][1] = icons["musicfile"][1]; icons["mp3"][2] = icons["musicfile"][2]
|
||||
icons["mp4"][1] = icons["videofile"][1]; icons["mp4"][2] = icons["videofile"][2]
|
||||
icons["mpeg"][1] = icons["videofile"][1]; icons["mpeg"][2] = icons["videofile"][2]
|
||||
icons["mpg"][1] = icons["videofile"][1]; icons["mpg"][2] = icons["videofile"][2]
|
||||
icons["msi"][1] = ""; icons["msi"][2] = color_default
|
||||
|
||||
# n
|
||||
icons["nix"][1] = ""; icons["nix"][2] = color_fsharp
|
||||
|
||||
# o
|
||||
icons["o"][1] = icons["manual"][1]; icons["o"][2] = icons["manual"][2]
|
||||
icons["ogg"][1] = icons["musicfile"][1]; icons["ogg"][2] = icons["musicfile"][2]
|
||||
icons["odownload"][1] = icons["download"][1]; icons["odownload"][2] = icons["download"][2]
|
||||
icons["out"][1] = icons["linux"][1]; icons["out"][2] = icons["linux"][2]
|
||||
|
||||
# p
|
||||
icons["part"][1] = icons["download"][1]; icons["part"][2] = icons["download"][2]
|
||||
icons["patch"][1] = icons["diff"][1]; icons["patch"][2] = icons["diff"][2]
|
||||
icons["pdf"][1] = ""; icons["pdf"][2] = color_docs
|
||||
icons["pgn"][1] = icons["chess"][1]; icons["pgn"][2] = icons["chess"][2]
|
||||
icons["php"][1] = ""; icons["php"][2] = color_default
|
||||
icons["png"][1] = icons["picturefile"][1]; icons["png"][2] = icons["picturefile"][2]
|
||||
icons["ppt"][1] = ""; icons["ppt"][2] = color_default
|
||||
icons["pptx"][1] = ""; icons["pptx"][2] = color_default
|
||||
icons["psb"][1] = ""; icons["psb"][2] = color_default
|
||||
icons["psd"][1] = ""; icons["psd"][2] = color_default
|
||||
icons["py"][1] = icons["python"][1]; icons["py"][2] = icons["python"][2]
|
||||
icons["pyc"][1] = icons["python"][1]; icons["pyc"][2] = icons["python"][2]
|
||||
icons["pyd"][1] = icons["python"][1]; icons["pyd"][2] = icons["python"][2]
|
||||
icons["pyo"][1] = icons["python"][1]; icons["pyo"][2] = icons["python"][2]
|
||||
|
||||
# q
|
||||
|
||||
# r
|
||||
icons["rar"][1] = icons["archive"][1]; icons["rar"][2] = icons["archive"][2]
|
||||
icons["rc"][1] = icons["configure"][1]; icons["rc"][2] = icons["configure"][2]
|
||||
icons["rom"][1] = ""; icons["rom"][2] = color_default
|
||||
icons["rpm"][1] = icons["archive"][1]; icons["rpm"][2] = icons["archive"][2]
|
||||
icons["rss"][1] = "參"; icons["rss"][2] = color_default
|
||||
icons["rtf"][1] = ""; icons["rtf"][2] = color_default
|
||||
|
||||
# s
|
||||
icons["sass"][1] = ""; icons["sass"][2] = color_css
|
||||
icons["scss"][1] = ""; icons["scss"][2] = color_css
|
||||
icons["so"][1] = icons["manual"][1]; icons["so"][2] = icons["manual"][2]
|
||||
icons["scala"][1] = ""; icons["scala"][2] = color_scala
|
||||
icons["sh"][1] = icons["script"][1]; icons["sh"][2] = icons["script"][2]
|
||||
icons["slim"][1] = icons["script"][1]; icons["slim"][2] = icons["script"][2]
|
||||
icons["sln"][1] = ""; icons["sln"][2] = color_default
|
||||
icons["sql"][1] = icons["database"][1]; icons["sql"][2] = icons["database"][2]
|
||||
icons["srt"][1] = ""; icons["srt"][2] = color_default
|
||||
icons["isub"][1] = ""; icons["isub"][2] = color_default
|
||||
icons["svg"][1] = icons["picturefile"][1]; icons["svg"][2] = icons["picturefile"][2]
|
||||
|
||||
# t
|
||||
icons["tar"][1] = icons["archive"][1]; icons["tar"][2] = icons["archive"][2]
|
||||
icons["tex"][1] = ""; icons["tex"][2] = color_default
|
||||
icons["tgz"][1] = icons["archive"][1]; icons["tgz"][2] = icons["archive"][2]
|
||||
icons["ts"][1] = ""; icons["ts"][2] = color_js
|
||||
icons["tsx"][1] = icons["react"][1]; icons["tsx"][2] = icons["react"][2]
|
||||
icons["txt"][1] = icons["document"][1]; icons["txt"][2] = icons["document"][2]
|
||||
icons["txz"][1] = icons["archive"][1]; icons["txz"][2] = icons["archive"][2]
|
||||
|
||||
# u
|
||||
|
||||
# v
|
||||
icons["vid"][1] = icons["videofile"][1]; icons["vid"][2] = icons["videofile"][2]
|
||||
icons["vim"][1] = ""; icons["vim"][2] = color_vim
|
||||
icons["vimrc"][1] = ""; icons["vimrc"][2] = color_vim
|
||||
icons["vtt"][1] = ""; icons["vtt"][2] = color_default
|
||||
# w
|
||||
icons["wav"][1] = icons["musicfile"][1]; icons["wav"][2] = icons["musicfile"][2]
|
||||
icons["webm"][1] = icons["videofile"][1]; icons["webm"][2] = icons["videofile"][2]
|
||||
icons["wma"][1] = icons["videofile"][1]; icons["wma"][2] = icons["videofile"][2]
|
||||
icons["wmv"][1] = icons["videofile"][1]; icons["wmv"][2] = icons["videofile"][2]
|
||||
|
||||
# x
|
||||
icons["xbps"][1] = icons["archive"][1]; icons["xbps"][2] = color_archive
|
||||
icons["xcf"][1] = icons["picturefile"][1]; icons["xcf"][2] = color_image
|
||||
icons["xhtml"][1] = icons["html"][1]; icons["xhtml"][2] = icons["html"][2]
|
||||
icons["xls"][1] = ""; icons["xls"][2] = color_default
|
||||
icons["xlsx"][1] = ""; icons["xlsx"][2] = color_default
|
||||
icons["xml"][1] = icons["html"][1]; icons["xml"][2] = icons["html"][2]
|
||||
icons["xz"][1] = icons["archive"][1]; icons["xz"][2] = icons["archive"][2]
|
||||
|
||||
# y
|
||||
icons["yaml"][1] = icons["configure"][1]; icons["yaml"][2] = icons["configure"][2]
|
||||
icons["yml"][1] = icons["configure"][1]; icons["yml"][2] = icons["configure"][2]
|
||||
# z
|
||||
icons["zip"][1] = icons["archive"][1]; icons["zip"][2] = icons["archive"][2]
|
||||
icons["zsh"][1] = icons["script"][1]; icons["zsh"][2] = icons["script"][2]
|
||||
icons["zst"][1] = icons["archive"][1]; icons["zst"][2] = icons["archive"][2]
|
||||
|
||||
FS = "."
|
||||
limit = ENVIRON["limit"]
|
||||
switch (colordepth) {
|
||||
case "4":
|
||||
escape="\033["
|
||||
break;
|
||||
case "8":
|
||||
escape="\033[38;5;"
|
||||
break;
|
||||
case "24":
|
||||
escape="\033[38;2;"
|
||||
break;
|
||||
}
|
||||
bstr = ENVIRON["beforestr"]
|
||||
}
|
||||
{
|
||||
# dont print cwd . and leading ./ from tree -f
|
||||
if ($0 ~/^\.$/)
|
||||
next
|
||||
ent = ($0 ~/^\.\//) ? substr($0, 3, length($0) - 2) : $0
|
||||
ext = $NF
|
||||
|
||||
# Print icons, set color and bold directories by using ansi escape codes
|
||||
if (ext in icons)
|
||||
printcolor(icons[ext][1], icons[ext][2], color_filetxt, ent, "10")
|
||||
else
|
||||
switch (substr(ent, length(ent), 1)) {
|
||||
case "/":
|
||||
printcolor(icons["directory"][1], color_default, color_dirtxt, ent, "1")
|
||||
break;
|
||||
case "*":
|
||||
printcolor(icons["exe"][1], color_default, color_filetxt, ent, "10")
|
||||
break;
|
||||
case "|":
|
||||
printcolor(icons["pipe"][1], color_default, color_filetxt, ent, "10")
|
||||
break;
|
||||
case "=":
|
||||
printcolor(icons["socket"][1], color_default, color_filetxt, ent, "10")
|
||||
break;
|
||||
case ">":
|
||||
printcolor(icons["door"][1], color_default, color_filetxt, ent, "10")
|
||||
break;
|
||||
default:
|
||||
printcolor(icons["file"][1], color_default, color_filetxt, ent, "10")
|
||||
}
|
||||
}
|
||||
function printcolor(i, c, d, n, b) {
|
||||
if (limit != "" && length(n) + 2 > limit)
|
||||
n = substr(n, 1, limit - 2)
|
||||
printf "\033[0m"
|
||||
printf "%s%s%s;%sm%s %s%sm%s\n", bstr, escape, c, b, i, escape, d, n
|
||||
}'
|
||||
printf '\033[0m'
|
||||
}
|
||||
|
||||
print_begin() {
|
||||
printf '%s\n' "$1" | sed 's/\\n/\n/g'
|
||||
}
|
||||
|
||||
print_end() {
|
||||
printf '%s\n' "$1" | sed 's/\\n/\n/g'
|
||||
}
|
||||
|
||||
print_help() {
|
||||
printf 'Icon Lookup\n
|
||||
Usage:
|
||||
iconlookup [options]
|
||||
iconlookup [-bBe] [string]
|
||||
iconlookup -l [number]
|
||||
iconlookup (-h | --help)
|
||||
|
||||
Prepend icons to list of files based on extension or appended indicator by ls/tree "-F" flag ("/" for directory, "*" for executable etc.)
|
||||
|
||||
Options:
|
||||
-h --help -? Show this screen.
|
||||
-b --before Prepend str before icon.
|
||||
-B --begin Prepend str before output.
|
||||
-e --end Append str after output.
|
||||
-l --limit Limit line length to [number] characters.'
|
||||
}
|
||||
|
||||
while :; do
|
||||
case $1 in
|
||||
-h|-\?|--help)
|
||||
print_help
|
||||
exit ;;
|
||||
-B|--begin)
|
||||
if [ -n "$2" ]; then
|
||||
print_begin "$2"
|
||||
fi
|
||||
shift ;;
|
||||
-e|--end)
|
||||
if [ -n "$2" ]; then
|
||||
end=1
|
||||
endstr="$2"
|
||||
fi
|
||||
shift ;;
|
||||
-b|--before)
|
||||
if [ -n "$2" ]; then
|
||||
export beforestr="$2"
|
||||
fi
|
||||
shift ;;
|
||||
-l|--limit)
|
||||
if [ -n "$2" ]; then
|
||||
export limit="$2"
|
||||
shift
|
||||
else
|
||||
printf 'ERROR: "--limit" requires a non-empty option argument.\n'
|
||||
exit
|
||||
fi ;;
|
||||
--)
|
||||
shift
|
||||
break ;;
|
||||
-?*)
|
||||
printf 'WARNING: Unknown option ignored: %s\n' "$1" ;;
|
||||
*) break ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ ! -t 0 ]; then
|
||||
[ -n "$beforestr" ] && limit="$((limit - ${#beforestr}))"
|
||||
icon_lookup
|
||||
else
|
||||
printf 'ERROR: no data provided...\nExpecting a directory listing in stdin\n'
|
||||
fi
|
||||
|
||||
if [ -n "$end" ]; then
|
||||
print_end "$endstr"
|
||||
fi
|
|
@ -0,0 +1,180 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Description: An almost fully POSIX compliant batch file renamer
|
||||
#
|
||||
# Note: nnn auto-detects and invokes this plugin if available
|
||||
# Whitespace is used as delimiter for read.
|
||||
# The plugin doesn't support filenames with leading or trailing whitespace
|
||||
# To use NNN_LIST your shell must support readlink(1)
|
||||
#
|
||||
# Capabilities:
|
||||
# 1. Basic file rename
|
||||
# 2. Detects order change
|
||||
# 3. Can move files
|
||||
# 4. Can remove files
|
||||
# 5. Switch number pairs to swap filenames
|
||||
#
|
||||
# Shell: bash
|
||||
# Author: KlzXS
|
||||
|
||||
EDITOR="${EDITOR:-vi}"
|
||||
TMPDIR="${TMPDIR:-/tmp}"
|
||||
NNN_INCLUDE_HIDDEN="${NNN_INCLUDE_HIDDEN:-0}"
|
||||
VERBOSE="${VERBOSE:-0}"
|
||||
RECURSIVE="${RECURSIVE:-0}"
|
||||
|
||||
case "$NNN_TRASH" in
|
||||
1)
|
||||
RM_UTIL="trash-put" ;;
|
||||
2)
|
||||
RM_UTIL="gio trash" ;;
|
||||
*)
|
||||
RM_UTIL="rm -ri" ;;
|
||||
esac
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
exit_status=0
|
||||
|
||||
dst_file=$(mktemp "$TMPDIR/.nnnXXXXXX")
|
||||
|
||||
if [ -s "$selection" ]; then
|
||||
printf "Rename 'c'urrent / 's'election? "
|
||||
read -r resp
|
||||
|
||||
if ! [ "$resp" = "c" ] && ! [ "$resp" = "s" ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$resp" = "s" ]; then
|
||||
arr=$(tr '\0' '\n' < "$selection")
|
||||
else
|
||||
findcmd="find . ! -name ."
|
||||
|
||||
if [ "$RECURSIVE" -eq 0 ]; then
|
||||
findcmd="$findcmd -prune"
|
||||
fi
|
||||
|
||||
if [ "$NNN_INCLUDE_HIDDEN" -eq 0 ]; then
|
||||
findcmd="$findcmd ! -name \".*\""
|
||||
fi
|
||||
|
||||
if [ -z "$NNN_LIST" ]; then
|
||||
findcmd="$findcmd -print"
|
||||
else
|
||||
findcmd="$findcmd -printf "'"'"$NNN_LIST/%P\n"'"'
|
||||
fi
|
||||
|
||||
arr=$(eval "$findcmd" | sort)
|
||||
fi
|
||||
|
||||
lines=$(printf "%s\n" "$arr" | wc -l)
|
||||
width=${#lines}
|
||||
|
||||
printf "%s" "$arr" | awk '{printf("%'"${width}"'d %s\n", NR, $0)}' > "$dst_file"
|
||||
|
||||
items=("~")
|
||||
while IFS='' read -r line; do
|
||||
if [ -n "$NNN_LIST" ]; then
|
||||
line=$(readlink "$line" || printf "%s" "$line")
|
||||
fi
|
||||
|
||||
items+=("$line");
|
||||
done < <(printf "%s\n" "$arr")
|
||||
|
||||
$EDITOR "$dst_file"
|
||||
|
||||
while read -r num name; do
|
||||
if [ -z "$name" ]; then
|
||||
if [ -z "$num" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
printf "%s: unable to parse line, aborting\n" "$0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# check if $num is an integer
|
||||
if [ ! "$num" -eq "$num" ] 2> /dev/null; then
|
||||
printf "%s: unable to parse line, aborting\n" "$0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
src=${items[$num]}
|
||||
|
||||
if [ -z "$src" ]; then
|
||||
printf "%s: unknown item number %s\n" "$0" "$num" > /dev/stderr
|
||||
continue
|
||||
elif [ "$name" != "$src" ]; then
|
||||
if [ -z "$name" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ ! -e "$src" ] && [ ! -L "$src" ]; then
|
||||
printf "%s: %s does not exit\n" "$0" "$src" > /dev/stderr
|
||||
|
||||
unset "items[$num]"
|
||||
continue
|
||||
fi
|
||||
|
||||
# handle swaps
|
||||
if [ -e "$name" ] || [ -L "$name" ]; then
|
||||
tmp="$name~"
|
||||
c=0
|
||||
|
||||
while [ -e "$tmp" ] || [ -L "$tmp" ]; do
|
||||
c=$((c+1))
|
||||
tmp="$tmp~$c"
|
||||
done
|
||||
|
||||
if mv "$name" "$tmp"; then
|
||||
if [ "$VERBOSE" -ne 0 ]; then
|
||||
printf "'%s' -> '%s'\n" "$name" "$tmp"
|
||||
fi
|
||||
else
|
||||
printf "%s: failed to rename %s to %s: %s\n" "$0" "$name" "$tmp" "$!" > /dev/stderr
|
||||
exit_status=1
|
||||
fi
|
||||
|
||||
for key in "${!items[@]}"; do
|
||||
if [ "${items[$key]}" = "$name" ]; then
|
||||
items[$key]="$tmp"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
dir=$(dirname "$name")
|
||||
if [ ! -d "$dir" ] && ! mkdir -p "$dir"; then
|
||||
printf "%s: failed to create directory tree %s\n" "$0" "$dir" > /dev/stderr
|
||||
exit_status=1
|
||||
elif ! mv -i "$src" "$name"; then
|
||||
printf "%s: failed to rename %s to %s: %s\n" "$0" "$name" "$tmp" "$!" > /dev/stderr
|
||||
exit_status=1
|
||||
else
|
||||
if [ -d "$name" ]; then
|
||||
for key in "${!items[@]}"; do
|
||||
items[$key]=$(printf "%s" "${items[$key]}" | sed "s|^$src\(\$\|\/\)|$name\1|")
|
||||
done
|
||||
|
||||
if [ "$VERBOSE" -ne 0 ]; then
|
||||
printf "'%s' => '%s'\n" "$src" "$name"
|
||||
fi
|
||||
else
|
||||
true
|
||||
if [ "$VERBOSE" -ne 0 ]; then
|
||||
printf "'%s' -> '%s'\n" "$src" "$name"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
unset "items[$num]"
|
||||
done <"$dst_file"
|
||||
|
||||
unset "items[0]"
|
||||
for item in "${items[@]}"; do
|
||||
$RM_UTIL "$item"
|
||||
done
|
||||
|
||||
rm "$dst_file"
|
||||
exit $exit_status
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Helper script for plugins
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Anna Arad
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
export selection
|
||||
|
||||
## Set CUR_CTX to 1 to open directory in current context
|
||||
CUR_CTX=0
|
||||
export CUR_CTX
|
||||
|
||||
## 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
|
||||
elif [ $CUR_CTX -ne 1 ]; then
|
||||
printf "Choose context 1-4 (blank for current): "
|
||||
read -r context
|
||||
fi
|
||||
|
||||
printf "%s" "${context:-0}c$dir" > "$NNN_PIPE"
|
||||
}
|
||||
|
||||
cmd_exists () {
|
||||
type "$1" > /dev/null 2>&1
|
||||
echo $?
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Show a notification
|
||||
#
|
||||
# Details: nnn invokes this plugin to show notification when a cp/mv/rm operation is complete.
|
||||
#
|
||||
# Dependencies: notify-send (Ubuntu)/ntfy (https://github.com/dschep/ntfy)/osascript (macOS)/notify (Haiku)
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Anna Arad
|
||||
|
||||
OS="$(uname)"
|
||||
|
||||
if type notify-send >/dev/null 2>&1; then
|
||||
notify-send nnn "Done!"
|
||||
elif [ "$OS" = "Darwin" ]; then
|
||||
osascript -e 'display notification "Done!" with title "nnn"'
|
||||
elif type ntfy >/dev/null 2>&1; then
|
||||
ntfy -t nnn send "Done!"
|
||||
elif [ "$OS" = "Haiku" ]; then
|
||||
notify --title "nnn" "Done!"
|
||||
fi
|
|
@ -0,0 +1,378 @@
|
|||
<h1 align="center">nnn plugins</h1>
|
||||
|
||||
<p align="center"><img src="https://i.imgur.com/SpT0L2W.png" /></p>
|
||||
<p align="center"><i>read ebooks with plugin gutenread (Android)</i></p>
|
||||
|
||||
## Introduction
|
||||
|
||||
Plugins extend the capabilities of `nnn`. They are _executable_ scripts (or binaries) `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 which can be run with custom hotkeys.
|
||||
|
||||
`nnn` is _**language-agnostic**_ when it comes to plugins. You can write a plugin in any (scripting) language you are comfortable in!
|
||||
|
||||
## List of plugins
|
||||
|
||||
| Plugin (a-z) | Description [Clears selection<sup>1</sup>] | Lang | Dependencies |
|
||||
| --- | --- | --- | --- |
|
||||
| [autojump](autojump) | Navigate to dir/path | sh | [jump](https://github.com/gsamokovarov/jump)/autojump/<br>zoxide/z/[z.lua](https://github.com/skywind3000/z.lua) |
|
||||
| [boom](boom) | Play random music from dir | sh | [moc](http://moc.daper.net/) |
|
||||
| [bulknew](bulknew) | Create multiple files/dirs at once | bash | sed, xargs, mktemp |
|
||||
| [cdpath](cdpath) | `cd` to the directory from `CDPATH` | sh | fzf |
|
||||
| [chksum](chksum) | Create and verify checksums [✓] | sh | md5sum,<br>sha256sum |
|
||||
| [cmusq](cmusq) | Queue/play files/dirs in cmus player [✓] | sh | cmus, pgrep |
|
||||
| [diffs](diffs) | Diff for selection (limited to 2 for directories) [✓] | sh | vimdiff, mktemp |
|
||||
| [dragdrop](dragdrop) | Drag/drop files from/into nnn | sh | [dragon](https://github.com/mwh/dragon) |
|
||||
| [dups](dups) | List non-empty duplicate files in current dir | bash | find, md5sum,<br>sort uniq xargs |
|
||||
| [finder](finder) | Run custom find command (**stored in histfile**) and list | sh | - |
|
||||
| [fixname](fixname) | Clean filename to be more shell-friendly [✓] | bash | sed |
|
||||
| [fzcd](fzcd) | Fuzzy search multiple dirs (or `$PWD`) and visit file | sh | fzf, (find) |
|
||||
| [fzhist](fzhist) | Fuzzy-select a cmd from history, edit in `$EDITOR` and run | sh | fzf, mktemp |
|
||||
| [fzopen](fzopen) | Fuzzy find file(s) in subtree to edit/open/pick | sh | fzf, xdg-open/open |
|
||||
| [fzplug](fzplug) | Fuzzy find, preview and run other plugins | sh | fzf |
|
||||
| [getplugs](getplugs) | Update plugins to installed `nnn` version | sh | curl |
|
||||
| [gitroot](gitroot) | Cd to the root of current git repo | sh | git |
|
||||
| [gpge](gpge) | Encrypt/decrypt files using GPG [✓] | sh | gpg |
|
||||
| [gutenread](gutenread) | Browse, download, read from Project Gutenberg | sh | curl, unzip, w3m<br>[epr](https://github.com/wustho/epr) (optional) |
|
||||
| [gsconnect](gsconnect) | GNOME's implementation of kdeconnect [✓] | sh | gsconnect |
|
||||
| [imgresize](imgresize) | Batch resize images in dir to screen resolution | sh | [imgp](https://github.com/jarun/imgp) |
|
||||
| [imgur](imgur) | Upload an image to imgur (from [imgur-screenshot](https://github.com/jomo/imgur-screenshot)) | bash | - |
|
||||
| [imgview](imgview) | View (thumbnail)images, set wallpaper, [rename](https://github.com/jarun/nnn/wiki/Basic-use-cases#browse-rename-images) and [more](https://wiki.archlinux.org/index.php/Sxiv#Assigning_keyboard_shortcuts)| sh | _see in-file docs_ |
|
||||
| [ipinfo](ipinfo) | Fetch external IP address and whois information | sh | curl, whois |
|
||||
| [kdeconnect](kdeconnect) | Send selected files to an Android device [✓] | sh | kdeconnect-cli |
|
||||
| [launch](launch) | GUI application launcher | sh | fzf |
|
||||
| [mimelist](mimelist) | List files by mime in subtree | sh | - |
|
||||
| [moclyrics](moclyrics) | Show lyrics of the track playing in moc | sh | [ddgr](https://github.com/jarun/ddgr), [moc](http://moc.daper.net/) |
|
||||
| [mocq](mocq) | Queue/play selection/dir/file in moc [✓] | sh | [moc](http://moc.daper.net/) |
|
||||
| [mp3conv](mp3conv) | Extract audio from multimedia as mp3 | sh | ffmpeg |
|
||||
| [mtpmount](mtpmount) | Toggle mount of MTP device (eg. Android) | sh | gvfs-mtp |
|
||||
| [nbak](nbak) | Backs up `nnn` config | sh | tar, awk, mktemp |
|
||||
| [nmount](nmount) | Toggle mount status of a device as normal user | sh | pmount, udisks2 |
|
||||
| [nuke](nuke) | Sample file opener (CLI-only by default) | sh | _see in-file docs_ |
|
||||
| [oldbigfile](oldbigfile) | List large files by access time | sh | find, sort |
|
||||
| [openall](openall) | Open selected files together or one by one [✓] | bash | - |
|
||||
| [organize](organize) | Auto-organize files in directories by file type [✓] | sh | file |
|
||||
| [pdfread](pdfread) | Read a PDF or text file aloud | sh | pdftotext, mpv,<br>pico2wave |
|
||||
| [preview-tabbed](preview-tabbed) | Preview files with Tabbed/xembed | bash | _see in-file docs_ |
|
||||
| [preview-tui](preview-tui) | Preview with Tmux/kitty/[QuickLook](https://github.com/QL-Win/QuickLook)/xterm/`$TERMINAL` | sh | _see in-file docs_ |
|
||||
| [pskill](pskill) | Fuzzy list by name and kill process or zombie | sh | fzf, ps, sudo/doas |
|
||||
| [renamer](renamer) | Batch rename selection or files in dir [✓] | sh | [qmv](https://www.nongnu.org/renameutils/)/[vidir](https://joeyh.name/code/moreutils/) |
|
||||
| [ringtone](ringtone) | Create a variable bitrate mp3 ringtone from file | sh | date, ffmpeg |
|
||||
| [rsynccp](rsynccp) | Gives copy-paste verbose progress percentage [✓] | sh | rsync |
|
||||
| [splitjoin](splitjoin) | Split file or join selection [✓] | sh | split, cat |
|
||||
| [suedit](suedit) | Edit file using superuser permissions | sh | sudoedit/sudo/doas |
|
||||
| [togglex](togglex) | Toggle executable mode for selection [✓] | sh | chmod |
|
||||
| [umounttree](umounttree) | Unmount a remote mountpoint from within | sh | fusermount |
|
||||
| [upload](upload) | Upload to Firefox Send or ix.io (text) or file.io (bin) | sh | [ffsend](https://github.com/timvisee/ffsend), curl, jq, tr |
|
||||
| [wallpaper](wall) | Set wallpaper or change colorscheme | sh | nitrogen/pywal |
|
||||
| [x2sel](x2sel) | Copy file list from system clipboard to selection | sh | _see in-file docs_ |
|
||||
| [xdgdefault](xdgdefault) | Set the default app for the hovered file type | sh | xdg-utils, fzf/dmenu |
|
||||
|
||||
Notes:
|
||||
|
||||
1. A plugin has to explicitly request `nnn` to clear the selection e.g. after operating on the selected files.
|
||||
2. Files starting with a dot in the `plugins` directory are internal files and should not be used as plugins.
|
||||
|
||||
### Table of contents
|
||||
|
||||
- [Installation](#installation)
|
||||
- [Configuration](#configuration)
|
||||
- [Skip directory refresh after running a plugin](#skip-directory-refresh-after-running-a-plugin)
|
||||
- [Running commands as plugin](#running-commands-as-plugin)
|
||||
- [Skip user confirmation after command execution](#skip-user-confirmation-after-command-execution)
|
||||
- [Run a GUI app as plugin](#run-a-gui-app-as-plugin)
|
||||
- [Page non-interactive command output](#page-non-interactive-command-output)
|
||||
- [Some useful key-command examples](#some-useful-key-command-examples)
|
||||
- [Access level of plugins](#access-level-of-plugins)
|
||||
- [Create your own plugins](#create-your-own-plugins)
|
||||
- [Send data to `nnn`](#send-data-to-nnn)
|
||||
- [Get notified on file hover](#get-notified-on-file-hover)
|
||||
- [Examples](#examples)
|
||||
- [Contributing plugins](#contributing-plugins)
|
||||
|
||||
## Installation
|
||||
|
||||
The following command installs or updates (after backup) all plugins:
|
||||
|
||||
```sh
|
||||
curl -Ls https://raw.githubusercontent.com/jarun/nnn/master/plugins/getplugs | sh
|
||||
```
|
||||
|
||||
Plugins are installed to `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins`.
|
||||
|
||||
## Configuration
|
||||
|
||||
Set environment variable `NNN_PLUG` to assign keybinds and invoke plugins directly using the plugin shortcut (<kbd>;</kbd>) followed by the assigned key character. E.g., with the below config:
|
||||
|
||||
```sh
|
||||
export NNN_PLUG='f:finder;o:fzopen;p:mocq;d:diffs;t:nmount;v:imgview'
|
||||
```
|
||||
|
||||
plugin `finder` can be invoked with the keybind <kbd>;f</kbd>, `fzopen` can be run with <kbd>;o</kbd> and so on... The key vs. plugin pairs are shown in the help and config screen.
|
||||
|
||||
Alternatively, combine with <kbd>Alt</kbd> (i.e. <kbd>Alt+key</kbd>).
|
||||
|
||||
To pick and run an unassigned plugin, press <kbd>Enter</kbd> (to _enter_ the plugin dir) at the plugin prompt.
|
||||
|
||||
To run a plugin at startup, use the option `-P` followed by the plugin key.
|
||||
|
||||
If the plugins list gets too long, try breaking them up into sections:
|
||||
|
||||
```
|
||||
NNN_PLUG_PERSONAL='g:personal/convert2zoom;p:personal/echo'
|
||||
NNN_PLUG_WORK='j:work/prettyjson;d:work/foobar'
|
||||
NNN_PLUG_INLINE='e:!go run $nnn*'
|
||||
NNN_PLUG_DEFAULT='1:ipinfo;p:preview-tui;o:fzz;b:nbak'
|
||||
NNN_PLUG="$NNN_PLUG_PERSONAL;$NNN_PLUG_WORK;$NNN_PLUG_DEFAULT;$NNN_PLUG_INLINE"
|
||||
export NNN_PLUG
|
||||
```
|
||||
|
||||
Note:
|
||||
- `'g:personal/convert2zoom'` will look in the personal sub-folder inside the plugin folder.
|
||||
- `'b:boom;b:bulknew` will result in only the first definition of *b* (`b:boom`) being used.
|
||||
- A keybinding definition of more than 1 character will prevent nnn from starting.
|
||||
|
||||
|
||||
#### 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 add a `-` before the plugin name:
|
||||
|
||||
```sh
|
||||
export NNN_PLUG='p:-plugin'
|
||||
```
|
||||
|
||||
## Running commands as plugin [`!`]
|
||||
|
||||
To assign keys to arbitrary non-background cli commands and invoke like plugins, add `!` (underscore) before the command.
|
||||
|
||||
```sh
|
||||
export NNN_PLUG='x:!chmod +x $nnn;g:!git log;s:!smplayer $nnn'
|
||||
```
|
||||
|
||||
Now <kbd>;x</kbd> can be used to make a file executable, <kbd>;g</kbd> can be used to the git log of a git project directory, <kbd>;s</kbd> 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.
|
||||
|
||||
```sh
|
||||
export NNN_PLUG='s:!smplayer $nnn*;n:-!vim /home/vaio/Dropbox/Public/synced_note*'
|
||||
```
|
||||
|
||||
Now there will be no prompt after <kbd>;s</kbd> and <kbd>;n</kbd>.
|
||||
|
||||
Note: Do not use `*` with programs those run and exit e.g. cat.
|
||||
|
||||
#### Run a GUI app as plugin [`&`]
|
||||
|
||||
To run a GUI app as plugin, add a `&` after `!`.
|
||||
|
||||
```sh
|
||||
export NNN_PLUG='m:-!&mousepad $nnn'
|
||||
```
|
||||
|
||||
Note: `$nnn` must be the last argument in this case.
|
||||
|
||||
#### Page non-interactive command output [`|`]
|
||||
|
||||
To show the output of run-and-exit commands which do not need user input, add `|` (pipe) after `!`.
|
||||
|
||||
```sh
|
||||
export NNN_PLUG='m:-!|mediainfo $nnn;t:-!|tree -ps;l:-!|ls -lah --group-directories-first'
|
||||
```
|
||||
|
||||
This option is incompatible with `&` (terminal output is masked for GUI programs) and ignores `*` (output is already paged for user).
|
||||
|
||||
Notes:
|
||||
|
||||
1. Use single quotes for `$NNN_PLUG` so `$nnn` is not interpreted
|
||||
2. `$nnn` must be the last argument (if used) to run a _command as plugin_
|
||||
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 |
|
||||
|---|---|
|
||||
| `c:!convert $nnn png:- \| xclip -sel clipboard -t image/png*` | Copy image to clipboard |
|
||||
| `e:-!sudo -E vim $nnn*` | Edit file as root in vim |
|
||||
| `g:-!git diff` | Show git diff |
|
||||
| `h:-!hx $nnn*` | Open hovered file in [hx](https://github.com/krpors/hx) hex editor |
|
||||
| `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 three arguments to the script:
|
||||
1. `$1`: The hovered file's name.
|
||||
2. `$2`: The working directory (might differ from `$PWD` in case of symlinked paths; non-canonical).
|
||||
3. `$3`: The picker mode output file (`-` for stdout) if `nnn` is executed as a file picker.
|
||||
- Sets the environment variable `NNN_PIPE` used to control `nnn` active directory.
|
||||
- Sets the environment variable `NNN_INCLUDE_HIDDEN` to `1` if hidden files are active, `0` otherwise.
|
||||
- Exports the [special variables](https://github.com/jarun/nnn/wiki/Concepts#special-variables).
|
||||
|
||||
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.
|
||||
|
||||
**Make the file executable**. Drop it in the plugin directory. Optionally add a hotkey in `$NNN_PLUG` for frequent usage.
|
||||
|
||||
#### Send data to `nnn`
|
||||
`nnn` provides a mechanism for plugins to send data to `nnn` to control its active directory or invoke the list mode.
|
||||
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 `(<->)<ctxcode><opcode><data>` without a newline at the end. For example, `1c/etc`.
|
||||
|
||||
The optional `-` at the **beginning of the stream** instructs `nnn` to clear the selection.
|
||||
In cases where the data transfer to `nnn` has to happen while the selection file is being read (e.g. in a loop), the plugin should
|
||||
create a tmp copy of the selection file, inform `nnn` to clear the selection and then do the subsequent processing with the tmp file.
|
||||
A paged [`|`] or GUI [`&`] cmd run as plugin cannot clear selection.
|
||||
|
||||
The `ctxcode` indicates the context to change the active directory of.
|
||||
|
||||
| Context code | Meaning |
|
||||
|:---:| --- |
|
||||
| `+` | smart context (next inactive else current) |
|
||||
| `0` | current context |
|
||||
| `1`-`4` | context number |
|
||||
|
||||
The `opcode` indicates the operation type.
|
||||
|
||||
| Opcode | Operation |
|
||||
|:---:| --- |
|
||||
| `c` | change directory |
|
||||
| `l` | list files in list mode |
|
||||
| `p` | picker file overwritten |
|
||||
|
||||
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. To skip this and choose the current context, set the `CUR_CTX` variable in `.nnn-plugin-helper` (or in the specific plugin after sourcing `.nnn-plugin-helper`) to 1.
|
||||
Usage examples can be found in the Examples section below.
|
||||
|
||||
#### Get notified on file hover
|
||||
|
||||
If `NNN_FIFO` is set, `nnn` will open it and write every hovered files. This can be used in plugins and external scripts, e.g. to implement file previews.
|
||||
|
||||
Don't forget to fork in the background to avoid blocking `nnn`.
|
||||
|
||||
For more details on configuration and usage of the preview plugins, visit [Live Previews](https://github.com/jarun/nnn/wiki/Live-previews).
|
||||
|
||||
## 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" "0c$dir" > "$NNN_PIPE"
|
||||
```
|
||||
|
||||
#### Send every hovered file to X selection
|
||||
|
||||
```sh
|
||||
#!/usr/bin/env sh
|
||||
|
||||
if [ -z "$NNN_FIFO" ] ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while read FILE ; do
|
||||
printf "%s" "$FILE" | xsel
|
||||
done < "$NNN_FIFO" &
|
||||
disown
|
||||
```
|
||||
|
||||
#### Quick `find` the first match in subtree and open in `nuke`
|
||||
|
||||
```sh
|
||||
#!/usr/bin/env sh
|
||||
|
||||
NUKE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins/nuke"
|
||||
|
||||
printf "file name: "
|
||||
read -r pattern
|
||||
|
||||
entry=$(find . -type f -iname "$pattern" -print -quit 2>/dev/null)
|
||||
|
||||
if [ -n "$entry" ]; then
|
||||
"$NUKE" "$entry"
|
||||
fi
|
||||
```
|
||||
|
||||
#### Quick find (using `fd`)
|
||||
|
||||
```sh
|
||||
#!/usr/bin/env sh
|
||||
|
||||
. "$(dirname "$0")"/.nnn-plugin-helper
|
||||
|
||||
printf "pattern: "
|
||||
read -r pattern
|
||||
|
||||
if [ -n "$pattern" ]; then
|
||||
printf "%s" "+l" > "$NNN_PIPE"
|
||||
eval "fd -HI $pattern -0" > "$NNN_PIPE"
|
||||
fi
|
||||
```
|
||||
|
||||
#### Quick grep (using `rg`)
|
||||
|
||||
```sh
|
||||
#!/usr/bin/env sh
|
||||
|
||||
. "$(dirname "$0")"/.nnn-plugin-helper
|
||||
|
||||
printf "pattern: "
|
||||
read -r pattern
|
||||
|
||||
if [ -n "$pattern" ]; then
|
||||
printf "%s" "+l" > "$NNN_PIPE"
|
||||
eval "rg -l0 --hidden -S $pattern" > "$NNN_PIPE"
|
||||
fi
|
||||
```
|
||||
|
||||
## Contributing plugins
|
||||
|
||||
1. Add informative sections like _Description_, _Notes_, _Dependencies_, _Shell_, _Author_ etc. in the plugin.
|
||||
2. Add an entry in the table above. Note that the list is alphabetically ordered by plugin name.
|
||||
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.
|
||||
5. If your plugin stores data, use `${XDG_CACHE_HOME:-$HOME/.cache}/nnn`. Document it _in-file_.
|
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Navigate to directory using jump/autojump/zoxide/z
|
||||
#
|
||||
# Dependencies:
|
||||
# - jump - https://github.com/gsamokovarov/jump
|
||||
# - OR autojump - https://github.com/wting/autojump
|
||||
# - OR zoxide - https://github.com/ajeetdsouza/zoxide
|
||||
# - OR z - https://github.com/rupa/z (z requires fzf)
|
||||
# - OR z (fish) - https://github.com/jethrokuan/z (z requires fzf)
|
||||
# - OR z.lua - https://github.com/skywind3000/z.lua (z.lua can enhanced with fzf)
|
||||
#
|
||||
# Note: The dependencies STORE NAVIGATION PATTERNS
|
||||
#
|
||||
# to make z.lua work, you need to set $NNN_ZLUA to the path of script z.lua
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Authors: Marty Buchaus, Dave Snider, Tim Adler, Nick Waywood
|
||||
|
||||
if [ ! -p "$NNN_PIPE" ]; then
|
||||
printf 'ERROR: NNN_PIPE is not set!'
|
||||
read -r _
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if type jump >/dev/null 2>&1; then
|
||||
printf "jump to : "
|
||||
IFS= read -r line
|
||||
# shellcheck disable=SC2086
|
||||
odir="$(jump cd ${line})"
|
||||
printf "%s" "0c$odir" > "$NNN_PIPE"
|
||||
elif type autojump >/dev/null 2>&1; then
|
||||
printf "jump to : "
|
||||
read -r dir
|
||||
odir="$(autojump "$dir")"
|
||||
printf "%s" "0c$odir" > "$NNN_PIPE"
|
||||
elif type zoxide >/dev/null 2>&1; then
|
||||
if type fzf >/dev/null 2>&1; then
|
||||
odir="$(zoxide query -i --)"
|
||||
printf "%s" "0c$odir" > "$NNN_PIPE"
|
||||
else
|
||||
printf "jump to : "
|
||||
read -r dir
|
||||
odir="$(zoxide query -- "$dir")"
|
||||
printf "%s" "0c$odir" > "$NNN_PIPE"
|
||||
fi
|
||||
elif type lua >/dev/null 2>&1 && [ -n "$NNN_ZLUA" ]; then
|
||||
printf "jump to : "
|
||||
read -r line
|
||||
if type fzf >/dev/null 2>&1; then
|
||||
odir="$(lua "$NNN_ZLUA" -l "$line" | fzf --nth 2.. --reverse --inline-info --tac +s -e --height 35%)"
|
||||
printf "%s" "0c$(echo "$odir" | awk '{print $2}')" > "$NNN_PIPE"
|
||||
else
|
||||
odir="$(lua "$NNN_ZLUA" -e "$line")"
|
||||
printf "%s" "0c$odir" > "$NNN_PIPE"
|
||||
fi
|
||||
else
|
||||
# rupa/z uses $_Z_DATA, jethrokuan/z (=port of z for fish) uses $Z_DATA
|
||||
datafile="${_Z_DATA:-${Z_DATA:-$HOME/.z}}"
|
||||
if type fzf >/dev/null 2>&1 && [ -f "$datafile" ]; then
|
||||
# Read the data from z's file instead of calling
|
||||
# z so the data doesn't need to be processed twice
|
||||
sel=$(awk -F "|" '{print $1}' "$datafile" | fzf | awk '{$1=$1};1')
|
||||
|
||||
# NOTE: Uncomment this line and comment out the line above if
|
||||
# you want to see the weightings of the dir's in the fzf pane
|
||||
# sel=$(awk -F "|" '{printf "%s %s\n", $2, $1}' "$datafile" | fzf | sed 's/^[0-9,.]* *//' | awk '{$1=$1};1')
|
||||
|
||||
printf "%s" "0c$sel" > "$NNN_PIPE"
|
||||
else
|
||||
printf "No supported autojump script [jump/autojump/zoxide/z (needs fzf)] found"
|
||||
read -r _
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Play random music (MP3, FLAC, M4A, WEBM, WMA) from current dir.
|
||||
#
|
||||
# Dependencies: mocp (or custom)
|
||||
#
|
||||
# Note: You may want to set GUIPLAYER.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
GUIPLAYER="${GUIPLAYER:-""}"
|
||||
NUMTRACKS="${NUMTRACKS:-100}"
|
||||
|
||||
if [ -n "$GUIPLAYER" ]; then
|
||||
find . -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.m4a" -o -iname "*.webm" -o -iname "*.wma" \) | shuf -n "$NUMTRACKS" | xargs -d "\n" "$GUIPLAYER" > /dev/null 2>&1 &
|
||||
|
||||
# detach the player
|
||||
sleep 1
|
||||
elif type mocp >/dev/null 2>&1; then
|
||||
cmd=$(pgrep -x mocp 2>/dev/null)
|
||||
ret=$cmd
|
||||
|
||||
if [ -z "$ret" ]; then
|
||||
# start MOC server
|
||||
mocp -S
|
||||
mocp -o shuffle
|
||||
else
|
||||
# mocp running, check if it's playing
|
||||
state=$(mocp -i | grep "State:" | cut -d' ' -f2)
|
||||
if [ "$state" = 'PLAY' ]; then
|
||||
# add up to 100 random audio files
|
||||
find . -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.m4a" -o -iname "*.webm" -o -iname "*.wma" \) | head -n "$NUMTRACKS" | xargs -d "\n" mocp -a
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
# clear MOC playlist
|
||||
mocp -c
|
||||
mocp -o shuffle
|
||||
|
||||
# add up to 100 random audio files
|
||||
find . -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.m4a" -o -iname "*.webm" -o -iname "*.wma" \) | head -n "$NUMTRACKS" | xargs -d "\n" mocp -a
|
||||
|
||||
# start playing
|
||||
mocp -p
|
||||
else
|
||||
printf "moc missing"
|
||||
read -r _
|
||||
fi
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Allows for creation of multiple files/dirs simultaneously
|
||||
# Creates a tmp file to write each entry in a separate line
|
||||
#
|
||||
# Note: Only relative paths are supported. Absolute paths are ignored
|
||||
# Leading and trailing whitespace in path names is also ignored
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: KlzXS
|
||||
|
||||
EDITOR="${EDITOR:-vi}"
|
||||
TMPDIR="${TMPDIR:-/tmp}"
|
||||
|
||||
printf "'f'ile / 'd'ir? "
|
||||
read -r resp
|
||||
|
||||
if [ "$resp" = "f" ]; then
|
||||
#shellcheck disable=SC2016
|
||||
cmd='mkdir -p "$(dirname "{}")" && touch "{}"'
|
||||
elif [ "$resp" = "d" ]; then
|
||||
cmd='mkdir -p {}'
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tmpfile=$(mktemp "$TMPDIR/.nnnXXXXXX")
|
||||
$EDITOR "$tmpfile"
|
||||
|
||||
sed "/^\//d" "$tmpfile" | xargs -n1 -I{} sh -c "$cmd"
|
||||
|
||||
rm "$tmpfile"
|
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: 'cd' to the directory from CDPATH
|
||||
#
|
||||
# Details: If the CDPATH environmet variable is not set, the default value of
|
||||
# ${XDG_CONFIG_HOME:-$HOME/.config}/nnn/bookmarks will be used.
|
||||
# You can create this directory and fill it with symbolic links to your
|
||||
# favorite directories. It's a good idea to add it to CDPATH so that it
|
||||
# could also be used from the command line outside of nnn.
|
||||
# The fzf search is done on the directory basename (the first column).
|
||||
#
|
||||
# This plugin is an extended version of the bookmarks plugin.
|
||||
# If you set your CDPATH to ${XDG_CACHE_HOME:-$HOME/.cache}/nnn/bookmarks
|
||||
# or to the value of BOOKMARKS_DIR, you can use it as a bookmarks replacement.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Yuri Kloubakov
|
||||
|
||||
# shellcheck disable=SC1090,SC1091
|
||||
. "$(dirname "$0")"/.nnn-plugin-helper
|
||||
|
||||
# Get a list of (symbolic links to) directories for every element of CDPATH
|
||||
get_dirs() {
|
||||
IFS=':'
|
||||
for path in $CDPATH; do
|
||||
for entry in "$path"/*; do
|
||||
if [ -d "$entry" ]; then
|
||||
name=$(basename "$entry" | grep -o '^.\{1,24\}')
|
||||
if [ -h "$entry" ]; then
|
||||
slink=$(ls -dl -- "$entry")
|
||||
entry=${slink#*" $entry -> "}
|
||||
fi
|
||||
printf "%-24s :%s\n" "${name}" "$entry"
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
abort() {
|
||||
echo "$1"
|
||||
read -r _
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ -z "$CDPATH" ]; then
|
||||
CDPATH="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/bookmarks"
|
||||
[ -d "$CDPATH" ] || abort "CDPATH is not set and there is no \"$CDPATH\" directory"
|
||||
fi
|
||||
|
||||
dir_list=$(get_dirs)
|
||||
[ -n "$dir_list" ] || abort "There are no directories to choose from. Check your \"$CDPATH\"."
|
||||
|
||||
dir=$(echo "$dir_list" | fzf --nth=1 --delimiter=':' | awk -F: 'END { print $2 }')
|
||||
if [ -n "$dir" ]; then
|
||||
nnn_cd "$dir" 0
|
||||
fi
|
|
@ -0,0 +1,75 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Create and verify checksums
|
||||
#
|
||||
# Note: On macOS, install the relevant checksum packages from Homebrew with:
|
||||
# brew install coreutils
|
||||
#
|
||||
# Details:
|
||||
# - selection: it will generate one file with the checksums and filenames
|
||||
# (and with paths if they are in another directory)
|
||||
# output checksum filename format: checksum_timestamp.checksum_type
|
||||
# - file: if the file is a checksum, the plugin does the verification
|
||||
# if the file is not a checksum, checksum will be generated for it
|
||||
# the output checksum filename will be filename.checksum_type
|
||||
# - directory: recursively calculates checksum for all the files in the dir
|
||||
# the output checksum filename will be directory.checksum_type
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Authors: ath3, Arun Prakash Jana
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
resp=f
|
||||
chsum=md5
|
||||
|
||||
checksum_type()
|
||||
{
|
||||
echo "possible checksums: md5, sha1, sha224, sha256, sha384, sha512"
|
||||
printf "create md5 (m), sha256 (s), sha512 (S) (or type one of the above checksums) [default=m]: "
|
||||
read -r chsum_resp
|
||||
for chks in md5 sha1 sha224 sha256 sha384 sha512
|
||||
do
|
||||
if [ "$chsum_resp" = "$chks" ]; then
|
||||
chsum=$chsum_resp
|
||||
return
|
||||
fi
|
||||
done
|
||||
if [ "$chsum_resp" = "s" ]; then
|
||||
chsum=sha256
|
||||
elif [ "$chsum_resp" = "S" ]; then
|
||||
chsum=sha512
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -s "$selection" ]; then
|
||||
printf "work with selection (s) or current file (f) [default=f]: "
|
||||
read -r resp
|
||||
fi
|
||||
|
||||
if [ "$resp" = "s" ]; then
|
||||
checksum_type
|
||||
sed 's|'"$PWD/"'||g' < "$selection" | xargs -0 -I{} ${chsum}sum {} > "checksum_$(date '+%Y%m%d%H%M').$chsum"
|
||||
|
||||
# Clear selection
|
||||
if [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
||||
elif [ -n "$1" ]; then
|
||||
if [ -f "$1" ]; then
|
||||
for chks in md5 sha1 sha224 sha256 sha384 sha512
|
||||
do
|
||||
if echo "$1" | grep -q \.${chks}$; then
|
||||
${chks}sum -c < "$1"
|
||||
read -r _
|
||||
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
|
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Add selection or hovered file/directory to cmus queue
|
||||
#
|
||||
# Dependencies: cmus, pgrep, xdotool (optional)
|
||||
#
|
||||
# Notes:
|
||||
# 1. If adding selection, files/dirs are added in the same order they were selected in nnn
|
||||
# 2. A new window will be opened if cmus is not running already, playback will start immediately
|
||||
# 3. If cmus is already running, files will be appended to the queue with no forced playback
|
||||
#
|
||||
# TODO:
|
||||
# 1. Add cava and cmus-lyrics as optional dependencies
|
||||
# 2. Start cava and/or cmus-lyrics in tmux or kitty panes next to cmus
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Kabouik
|
||||
|
||||
# (Optional) Set preferred terminal emulator for cmus if not set in your env,
|
||||
# or leave commented out to use OS default
|
||||
#TERMINAL="kitty"
|
||||
|
||||
if ! type cmus >/dev/null; then
|
||||
printf "cmus missing"
|
||||
read -r _
|
||||
exit 1
|
||||
fi
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
|
||||
start_cmus() {
|
||||
type xdotool >/dev/null && nnnwindow="$(xdotool getactivewindow)"
|
||||
case "$TERMINAL" in
|
||||
kitty | gnome-terminal | st)
|
||||
nohup "$TERMINAL" -- cmus & ;;
|
||||
havoc)
|
||||
nohup "$TERMINAL" cmus & ;;
|
||||
"")
|
||||
nohup x-terminal-emulator -e cmus & ;;
|
||||
*)
|
||||
nohup "$TERMINAL" -e cmus & ;;
|
||||
esac
|
||||
# Give the new terminal some time to open
|
||||
until cmus-remote -C; do sleep 0.1; done
|
||||
[ -n "$nnnwindow" ] && xdotool windowactivate "$nnnwindow"
|
||||
} >/dev/null 2>&1
|
||||
|
||||
fill_queue() {
|
||||
if [ "$REPLY" = "s" ]; then
|
||||
xargs < "$selection" -0 cmus-remote -q
|
||||
elif [ -n "$1" ]; then
|
||||
cmus-remote -q "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# If active selection,then ask what to do
|
||||
if [ -s "$selection" ]; then
|
||||
printf "Queue [s]election or [c]urrently hovered? [default=c]: "
|
||||
read -r REPLY
|
||||
fi
|
||||
|
||||
# If cmus is not running, start and play queue
|
||||
if ! pgrep cmus >/dev/null; then
|
||||
printf "cmus is not running, starting it in a new %s window.\n" "$TERMINAL"
|
||||
start_cmus
|
||||
fill_queue "$1"
|
||||
cmus-remote -p
|
||||
printf "Files added to cmus queue.\n"
|
||||
else # Append to existing queue if cmus is already running
|
||||
fill_queue "$1"
|
||||
printf "Files appended to current cmus queue.\n"
|
||||
fi
|
||||
|
||||
# Change view
|
||||
cmus-remote -C "view 4"
|
||||
|
||||
# Clear selection
|
||||
if [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Show diff of 2 directories or multiple files in vimdiff
|
||||
#
|
||||
# Notes:
|
||||
# 1. vim may show the warning: 'Vim: Warning: Input is not from a terminal'
|
||||
# press 'Enter' to ignore and proceed.
|
||||
# 2. if only one file is in selection, the hovered file is considered as the
|
||||
# second file to diff with
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Authors: Arun Prakash Jana, ath3
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
|
||||
if type nvim >/dev/null 2>&1; then
|
||||
diffcmd="nvim -d"
|
||||
else
|
||||
diffcmd="vimdiff +0"
|
||||
fi
|
||||
|
||||
dirdiff() {
|
||||
dir1=$(mktemp "${TMPDIR:-/tmp}"/nnn-"$(basename "$1")".XXXXXXXX)
|
||||
dir2=$(mktemp "${TMPDIR:-/tmp}"/nnn-"$(basename "$2")".XXXXXXXX)
|
||||
ls -A1 "$1" > "$dir1"
|
||||
ls -A1 "$2" > "$dir2"
|
||||
$diffcmd "$dir1" "$dir2"
|
||||
rm "$dir1" "$dir2"
|
||||
}
|
||||
|
||||
if [ -s "$selection" ]; then
|
||||
arr=$(tr '\0' '\n' < "$selection")
|
||||
if [ "$(echo "$arr" | wc -l)" -gt 1 ]; then
|
||||
f1="$(echo "$arr" | sed -n '1p')"
|
||||
f2="$(echo "$arr" | sed -n '2p')"
|
||||
if [ -d "$f1" ] && [ -d "$f2" ]; then
|
||||
dirdiff "$f1" "$f2"
|
||||
else
|
||||
# If xargs supports the -o option, use it to get rid of:
|
||||
# Vim: Warning: Input is not from a terminal
|
||||
# xargs -0 -o vimdiff < $selection
|
||||
|
||||
eval xargs -0 "$diffcmd" < "$selection"
|
||||
fi
|
||||
elif [ -n "$1" ]; then
|
||||
f1="$(echo "$arr" | sed -n '1p')"
|
||||
if [ -d "$f1" ] && [ -d "$1" ]; then
|
||||
dirdiff "$f1" "$1"
|
||||
elif [ -f "$f1" ] && [ -f "$1" ]; then
|
||||
$diffcmd "$f1" "$1"
|
||||
else
|
||||
echo "cannot compare file with directory"
|
||||
fi
|
||||
else
|
||||
echo "needs at least 2 files or directories selected for comparison"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clear selection
|
||||
if [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Open a Drag and drop window, to drop files onto other programs.
|
||||
# Also provides drag and drop window for files.
|
||||
#
|
||||
# Dependencies: dragon - https://github.com/mwh/dragon
|
||||
#
|
||||
# Notes:
|
||||
# 1. Files that are dropped will be added to nnn's selection
|
||||
# Some web-based files will be downloaded to current dir
|
||||
# with curl and it may overwrite some existing files
|
||||
# 2. The user has to mm to clear nnn's selection first
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: 0xACE
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
resp=f
|
||||
all=
|
||||
if type dragon-drag-and-drop >/dev/null 2>&1; then
|
||||
dnd="dragon-drag-and-drop"
|
||||
elif type dragon-drop >/dev/null 2>&1; then
|
||||
dnd="dragon-drop"
|
||||
else
|
||||
dnd="dragon"
|
||||
fi
|
||||
|
||||
add_file ()
|
||||
{
|
||||
printf '%s\0' "$@" >> "$selection"
|
||||
}
|
||||
|
||||
use_all ()
|
||||
{
|
||||
printf "mark --all (a) [default=none]: "
|
||||
read -r resp
|
||||
if [ "$resp" = "a" ]; then
|
||||
all="--all"
|
||||
else
|
||||
all=""
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -s "$selection" ]; then
|
||||
printf "Drop file (r). Drag selection (s), Drag current directory (d) or drag current file (f) [default=f]: "
|
||||
read -r resp
|
||||
else
|
||||
printf "Drop file (r). Drag current directory (d) or drag current file (f) [default=f]: "
|
||||
read -r resp
|
||||
if [ "$resp" = "s" ]; then
|
||||
resp=f
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$resp" = "s" ]; then
|
||||
use_all
|
||||
sed -z 's|'"$PWD/"'||g' < "$selection" | xargs -0 "$dnd" "$all" &
|
||||
elif [ "$resp" = "d" ]; then
|
||||
use_all
|
||||
"$dnd" "$all" "$PWD/"* &
|
||||
elif [ "$resp" = "r" ]; then
|
||||
true > "$selection"
|
||||
"$dnd" --print-path --target | while read -r f
|
||||
do
|
||||
if printf "%s" "$f" | grep '^\(https\?\|ftps\?\|s\?ftp\):\/\/' ; then
|
||||
curl -LJO "$f"
|
||||
add_file "$PWD/$(basename "$f")"
|
||||
elif [ -e "$f" ]; then
|
||||
add_file "$f"
|
||||
fi
|
||||
done &
|
||||
else
|
||||
if [ -n "$1" ] && [ -e "$1" ]; then
|
||||
"$dnd" "$1" &
|
||||
fi
|
||||
fi
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: List non-empty duplicates in the current dir (based on size followed by MD5)
|
||||
#
|
||||
# Source: https://www.commandlinefu.com/commands/view/3555/find-duplicate-files-based-on-size-first-then-md5-hash
|
||||
#
|
||||
# Dependencies: find md5sum sort uniq xargs gsed
|
||||
#
|
||||
# Notes:
|
||||
# 1. If the file size exceeds $size_digits digits the file will be misplaced
|
||||
# 12 digits fit files up to 931GiB
|
||||
# 2. Bash compatible required for mktemp
|
||||
#
|
||||
# Shell: Bash
|
||||
# Authors: syssyphus, KlzXS
|
||||
|
||||
EDITOR="${EDITOR:-vi}"
|
||||
TMPDIR="${TMPDIR:-/tmp}"
|
||||
|
||||
size_digits=12
|
||||
tmpfile=$(mktemp "$TMPDIR/.nnnXXXXXX")
|
||||
|
||||
printf "\
|
||||
## This is an overview of all duplicate files found.
|
||||
## Comment out the files you wish to remove. You will be given an option to cancel.
|
||||
## Lines with double comments (##) are ignored.
|
||||
## You will have the option to remove the files with force or interactively.\n
|
||||
" > "$tmpfile"
|
||||
|
||||
# shellcheck disable=SC2016
|
||||
find . -size +0 -type f -printf "%${size_digits}s %p\n" | sort -rn | uniq -w"${size_digits}" -D | sed -e '
|
||||
s/^ \{0,12\}\([0-9]\{0,12\}\) \(.*\)$/printf "%s %s\\n" "$(md5sum "\2")" "d\1"/
|
||||
' | tr '\n' '\0' | xargs -0 -n1 sh -c | sort | { uniq -w32 --all-repeated=separate; echo; } | sed -ne '
|
||||
h
|
||||
s/^\(.\{32\}\).* d\([0-9]*\)$/## md5sum: \1 size: \2 bytes/p
|
||||
g
|
||||
|
||||
:loop
|
||||
N
|
||||
/.*\n$/!b loop
|
||||
p' | sed -e 's/^.\{32\} \(.*\) d[0-9]*$/\1/' >> "$tmpfile"
|
||||
|
||||
"$EDITOR" "$tmpfile"
|
||||
|
||||
printf "Remove commented files? (yes/no) [default=n]: "
|
||||
read -r commented
|
||||
|
||||
if [ "$commented" = "y" ]; then
|
||||
sedcmd="/^##.*/d; /^[^#].*/d; /^$/d; s/^# *\(.*\)$/\1/"
|
||||
else
|
||||
printf "Press any key to exit"
|
||||
read -r _
|
||||
exit
|
||||
fi
|
||||
|
||||
printf "Remove with force or interactive? (f/i) [default=i]: "
|
||||
read -r force
|
||||
|
||||
if [ "$force" = "f" ]; then
|
||||
#shellcheck disable=SC2016
|
||||
sed -e "$sedcmd" "$tmpfile" | tr '\n' '\0' | xargs -0 -r sh -c 'rm -f "$0" "$@" </dev/tty'
|
||||
else
|
||||
#shellcheck disable=SC2016
|
||||
sed -e "$sedcmd" "$tmpfile" | tr '\n' '\0' | xargs -0 -r sh -c 'rm -i "$0" "$@" </dev/tty'
|
||||
fi
|
||||
|
||||
rm "$tmpfile"
|
||||
|
||||
printf "Press any key to exit"
|
||||
read -r _
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Description: Run custom search and list results in smart context
|
||||
#
|
||||
# Note: This plugin retains search history
|
||||
#
|
||||
# Usage:
|
||||
# Run plugin and enter e.g. "-size +10M" to list files in current
|
||||
# directory larger than 10M. By default entered expressions are
|
||||
# interpreted as arguments to find. Results have to be NUL
|
||||
# terminated which is done by default for find. Alternatively one
|
||||
# can prepend a '$' to run a custom search program such as fd or
|
||||
# ripgrep. Entered expressions will be saved in history file to
|
||||
# be listed as bookmarks and and can be entered by index and edited.
|
||||
#
|
||||
# Shell: Bash
|
||||
# Author: Arun Prakash Jana, Luuk van Baal
|
||||
TMPDIR="${TMPDIR:-/tmp}"
|
||||
NNN_FINDHIST="${NNN_FINDHIST:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/finderbms}"
|
||||
NNN_FINDHISTLEN="${NNN_FINDHISTLEN:-10000}"
|
||||
|
||||
printexamples() {
|
||||
printf -- "-maxdepth 1 -name pattern
|
||||
-maxdepth 1 -size +100M
|
||||
\$fd -0 pattern
|
||||
\$fd -0 -d 2 -S +100M
|
||||
\$grep -rlZ pattern
|
||||
\$rg -l0 pattern
|
||||
\$fzf -m | tr '\\\n' '\\\0'\n"
|
||||
}
|
||||
|
||||
printexprs() {
|
||||
for ((i = "$1"; i < ${#fexprs[@]}; i++)); do
|
||||
printf '%s\t%s\n' "$((i + 1))" "${fexprs[$i]}"
|
||||
done
|
||||
}
|
||||
|
||||
mapexpr() {
|
||||
if [ "$fexpr" -eq "$fexpr" ] 2>/dev/null; then
|
||||
fexpr=${fexprs[$((fexpr - 1))]}
|
||||
read -r -e -p "Search expression: " -i "$fexpr" fexpr
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
readexpr() {
|
||||
case "$fexpr" in
|
||||
h) clear
|
||||
printf "Examples:\n"
|
||||
mapfile -t fexprs < <(printexamples)
|
||||
printexprs 0
|
||||
read -r -p "Search expression or index: " fexpr
|
||||
mapexpr
|
||||
[ -n "$fexpr" ] && readexpr ;;
|
||||
\$*) cmd="${fexpr:1}" ;;
|
||||
*) mapexpr && readexpr
|
||||
cmd="find $fexpr -print0" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
clear
|
||||
[ -f "$NNN_FINDHIST" ] || printexamples > "$NNN_FINDHIST"
|
||||
|
||||
mapfile -t fexprs < <(sort "$NNN_FINDHIST" | uniq -c | sort -nr | head -n5 |\
|
||||
awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}')
|
||||
printf "Most used search expressions:\n"
|
||||
printexprs 0
|
||||
|
||||
mapfile -t -O"$i" fexprs < <(tac "$NNN_FINDHIST" | awk '!a[$0]++' | head -n5)
|
||||
printf "Most recently used search expressions:\n"
|
||||
printexprs "$i"
|
||||
read -r -p "Search expression or index (h for help): " fexpr
|
||||
|
||||
mapexpr
|
||||
|
||||
if [ -n "$fexpr" ]; then
|
||||
printf "+l" > "$NNN_PIPE"
|
||||
while :; do
|
||||
readexpr
|
||||
eval "$cmd" > "$NNN_PIPE" && break
|
||||
read -r -e -p "Search expression: " -i "$fexpr" fexpr
|
||||
done
|
||||
if [ -n "$fexpr" ]; then
|
||||
tail -n"$NNN_FINDHISTLEN" "$NNN_FINDHIST" > "$TMPDIR/finderbms"
|
||||
printf "%s\n" "$fexpr" >> "$TMPDIR/finderbms"
|
||||
mv "$TMPDIR/finderbms" "$NNN_FINDHIST"
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,75 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Description: Clean filename or dirname (either hovered or selections)
|
||||
# to be more shell-friendly. This script cleans
|
||||
# non A-Za-z0-9._- characters.
|
||||
# and replaces it with underscore (_).
|
||||
#
|
||||
# It supports cleaning single/double quote, newline,
|
||||
# leading, trailing spaces.
|
||||
#
|
||||
# eg.
|
||||
# to be continued (つづく).mp4 -> to_be_continued______.mp4
|
||||
# [work] stuff.txt -> _work__stuff.txt
|
||||
# home's server -> home_s_server
|
||||
# qwe\trty -> __qwe_rty
|
||||
#
|
||||
# And if there are two almost similar filenames
|
||||
# like: 'asd]f' and 'asd f' both will be renamed to 'asd_f',
|
||||
# to avoid overwriting, the last file will be prepended by _.
|
||||
# So they will be: 'asd_f' and '_asd_f'
|
||||
#
|
||||
# Dependencies: sed
|
||||
#
|
||||
# Shell: Bash
|
||||
# Author: Benawi Adha
|
||||
|
||||
prompt=true
|
||||
sel=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
|
||||
cleanup() {
|
||||
# printf "%s" "$1" | sed -e 's/[^A-Za-z0-9._-]/_/g'
|
||||
printf "%s" "$1" | sed 's/[^A-Za-z0-9._-]/_/g' | sed ':a;N;$!ba;s/\n/_/g'
|
||||
}
|
||||
|
||||
if [ -s "$sel" ]; then
|
||||
targets=()
|
||||
while IFS= read -r -d '' i || [ -n "$i" ]; do
|
||||
targets+=( "$(basename "$i")" )
|
||||
done < "$sel"
|
||||
else
|
||||
targets=("$1")
|
||||
fi
|
||||
|
||||
for i in "${targets[@]}"; do
|
||||
printf "%s -> %s\n" "$i" "$(cleanup "$i")";
|
||||
done
|
||||
|
||||
if $prompt; then
|
||||
echo
|
||||
printf "Proceed [Yn]? "
|
||||
read -r input
|
||||
case "$input" in
|
||||
y|Y|'')
|
||||
;;
|
||||
*)
|
||||
echo "Canceled"
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for i in "${targets[@]}"; do
|
||||
if [ "$i" != "$(cleanup "$i")" ]; then
|
||||
tmp=''
|
||||
if [ -e "$(cleanup "$i")" ]; then
|
||||
tmp='_'
|
||||
fi
|
||||
mv "$i" "$tmp$(cleanup "$i")";
|
||||
fi
|
||||
done
|
||||
|
||||
# Clear selection
|
||||
if [ -s "$sel" ] && [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Fuzzy search multiple locations read-in from a path-list file
|
||||
# (or $PWD) and open the selected file's dir in a smart context.
|
||||
# Dependencies: fzf, find (only for multi-location search)
|
||||
#
|
||||
# Details: Paths in list file should be newline-separated absolute paths.
|
||||
# Paths can be file paths; the script will scan the parent dirs.
|
||||
#
|
||||
# The path-list file precedence is:
|
||||
# - "$1" (the hovered file) if it exists, is plain-text and the
|
||||
# first line points to an existing file
|
||||
# - "$LIST" if set below
|
||||
# - "$2" (the current directory) [mimics plugin fzcd behaviour]
|
||||
#
|
||||
# The path-list file can be generated easily:
|
||||
# - pick the (file)paths in picker mode to path-list file
|
||||
# - OR, edit selection in nnn and save as path-list file
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Anna Arad, Arun Prakash Jana, KlzXS
|
||||
|
||||
IFS="$(printf '\n\r')"
|
||||
|
||||
# shellcheck disable=SC1090,SC1091
|
||||
. "$(dirname "$0")"/.nnn-plugin-helper
|
||||
|
||||
CTX=+
|
||||
LIST="${LIST:-""}"
|
||||
|
||||
if ! type fzf >/dev/null 2>&1; then
|
||||
printf "fzf missing"
|
||||
read -r _
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$1" ] && [ "$(file -b --mime-type "$1")" = 'text/plain' ] && [ -e "$(head -1 "$1")" ]; then
|
||||
LIST="$1"
|
||||
elif ! [ -s "$LIST" ]; then
|
||||
sel=$(fzf)
|
||||
# Show only the file and parent dir
|
||||
# sel=$(fzf --delimiter / --with-nth=-2,-1 --tiebreak=begin --info=hidden)
|
||||
|
||||
LIST=''
|
||||
fi
|
||||
|
||||
if [ -n "$LIST" ]; then
|
||||
if type find >/dev/null 2>&1; then
|
||||
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
|
||||
|
||||
while IFS= read -r path; do
|
||||
if [ -d "$path" ]; then
|
||||
printf "%s\n" "$path" >> "$tmpfile"
|
||||
elif [ -f "$path" ]; then
|
||||
printf "%s\n" "$(dirname "$path")" >> "$tmpfile"
|
||||
fi
|
||||
done < "$LIST"
|
||||
|
||||
sel=$(xargs -d '\n' < "$tmpfile" -I{} find {} -type f -printf "%H//%P\n" | sed '/.*\/\/\(\..*\|.*\/\..*\)/d; s:/\+:/:g' | fzf --delimiter / --tiebreak=begin --info=hidden)
|
||||
# Alternative for 'fd'
|
||||
# sel=$(xargs -d '\n' < "$tmpfile" fd . | fzf --delimiter / --tiebreak=begin --info=hidden)
|
||||
|
||||
rm "$tmpfile"
|
||||
else
|
||||
printf "find missing"
|
||||
read -r _
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$sel" ]; then
|
||||
if [ "$sel" = "." ] || { ! [ -d "$sel" ] && ! [ -f "$sel" ]; }; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if the selected path returned by fzf command is absolute
|
||||
case $sel in
|
||||
/*) nnn_cd "$sel" "$CTX" ;;
|
||||
*)
|
||||
# Remove "./" prefix if it exists
|
||||
sel="${sel#./}"
|
||||
|
||||
if [ "$PWD" = "/" ]; then
|
||||
nnn_cd "/$sel" "$CTX"
|
||||
else
|
||||
nnn_cd "$PWD/$sel" "$CTX"
|
||||
fi;;
|
||||
esac
|
||||
fi
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Fuzzy find a command from history,
|
||||
# edit in $EDITOR and run as a command
|
||||
#
|
||||
# Note: Supports only bash and fish history
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
if type fzf >/dev/null 2>&1; then
|
||||
fuzzy=fzf
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
shellname="$(basename "$SHELL")"
|
||||
|
||||
if [ "$shellname" = "bash" ]; then
|
||||
hist_file="$HOME/.bash_history"
|
||||
entry="$("$fuzzy" < "$hist_file")"
|
||||
elif [ "$shellname" = "fish" ]; then
|
||||
hist_file="$HOME/.local/share/fish/fish_history"
|
||||
entry="$(grep "\- cmd: " "$hist_file" | cut -c 8- | "$fuzzy")"
|
||||
fi
|
||||
|
||||
if [ -n "$entry" ]; then
|
||||
tmpfile=$(mktemp)
|
||||
echo "$entry" >> "$tmpfile"
|
||||
$EDITOR "$tmpfile"
|
||||
|
||||
if [ -s "$tmpfile" ]; then
|
||||
$SHELL -c "$(cat "$tmpfile")"
|
||||
fi
|
||||
|
||||
rm "$tmpfile"
|
||||
|
||||
printf "Press any key to exit"
|
||||
read -r _
|
||||
fi
|
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Regular mode:
|
||||
# Fuzzy find a file in directory subtree.
|
||||
# Opens in $VISUAL or $EDITOR if text.
|
||||
# Opens other type of files with xdg-open.
|
||||
# Work only with a single file selected.
|
||||
#
|
||||
# Picker mode:
|
||||
# If picker mode output file is passed, it
|
||||
# will be overwritten with any picked files.
|
||||
# Leaves untouched if no file is picked.
|
||||
# Works with single/multiple files selected.
|
||||
#
|
||||
# Dependencies: fd/find, fzf/skim, xdg-open/open (on macOS)
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
NUKE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins/nuke"
|
||||
USE_NUKE=0
|
||||
|
||||
# shellcheck disable=SC1090,SC1091
|
||||
. "$(dirname "$0")"/.nnn-plugin-helper
|
||||
|
||||
if type fzf >/dev/null 2>&1; then
|
||||
cmd="$FZF_DEFAULT_COMMAND"
|
||||
if type fd >/dev/null 2>&1; then
|
||||
[ -z "$cmd" ] && cmd="fd -t f 2>/dev/null"
|
||||
else
|
||||
[ -z "$cmd" ] && cmd="find . -type f 2>/dev/null"
|
||||
fi
|
||||
entry="$(eval "$cmd" | fzf -m)"
|
||||
# To show only the file name
|
||||
# entry=$(find . -type f 2>/dev/null | fzf --delimiter / --with-nth=-1 --tiebreak=begin --info=hidden)
|
||||
elif type sk >/dev/null 2>&1; then
|
||||
entry=$(find . -type f 2>/dev/null | sk)
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for picker mode
|
||||
if [ "$3" ]; then
|
||||
if [ "$entry" ]; then
|
||||
case "$entry" in
|
||||
/*) fullpath="$entry" ;;
|
||||
*) fullpath="$PWD/$entry" ;;
|
||||
esac
|
||||
if [ "-" = "$3" ]; then
|
||||
printf "%s\n" "$fullpath"
|
||||
else
|
||||
printf "%s\n" "$fullpath" > "$3"
|
||||
fi
|
||||
|
||||
# Tell `nnn` to clear its internal selection
|
||||
printf "%s" "0p" > "$NNN_PIPE"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$USE_NUKE" -ne 0 ]; then
|
||||
"$NUKE" "$entry"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Open the file (works for a single file only)
|
||||
cmd_file=""
|
||||
cmd_open=""
|
||||
if uname | grep -q "Darwin"; then
|
||||
cmd_file="file -bIL"
|
||||
cmd_open="open"
|
||||
else
|
||||
cmd_file="file -biL"
|
||||
cmd_open="xdg-open"
|
||||
fi
|
||||
|
||||
case "$($cmd_file "$entry")" in
|
||||
*text*)
|
||||
"${VISUAL:-$EDITOR}" "$entry" ;;
|
||||
*)
|
||||
$cmd_open "$entry" >/dev/null 2>&1 ;;
|
||||
esac
|
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Fuzzy find and execute nnn plugins (and optionally,
|
||||
# custom scripts located elsewhere).
|
||||
# Description and details of plugins can be previewed
|
||||
# from the fzf interface. Use `?` to toggle preview
|
||||
# pane on and off, ^Up/^Dn to scroll.
|
||||
#
|
||||
# Dependencies: find, fzf, cat (or bat, if installed)
|
||||
#
|
||||
# Note: For better compatibility with as many nnn plugins as possible,
|
||||
# fzplug will first execute the chosen script on the file hovered
|
||||
# in nnn, and upon failure, try to run it with no target (i.e on
|
||||
# an active selection, if present).
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Kabouik
|
||||
|
||||
# Optional scripts sources
|
||||
|
||||
# Leave blank or fill with the absolute path of a folder containing executable
|
||||
# scripts other than nnn plugins (e.g., "$HOME/.local/share/nautilus/scripts",
|
||||
# since there are numerous Nautilus script git repositories).
|
||||
# Add extra variables if needed, make sure you call them in the find command.
|
||||
|
||||
#CUSTOMDIR1="$HOME/.local/share/nautilus/scripts"
|
||||
CUSTOMDIR1=""
|
||||
CUSTOMDIR2=""
|
||||
|
||||
nnnpluginsdir="$HOME/.config/nnn/plugins"
|
||||
|
||||
# Preview with bat if installed
|
||||
if type bat >/dev/null; then
|
||||
BAT="bat --terminal-width='$(tput cols)' --decorations=always --color=always --style='${BAT_STYLE:-header,numbers}'"
|
||||
fi
|
||||
|
||||
plugin=$(find "$nnnpluginsdir" "$CUSTOMDIR1" "$CUSTOMDIR2" \
|
||||
-maxdepth 3 -perm -111 -type f 2>/dev/null | fzf --ansi --preview \
|
||||
"${BAT:-cat} {}" --preview-window="right:66%:wrap" --delimiter / \
|
||||
--with-nth -1 --bind="?:toggle-preview")
|
||||
|
||||
# Try running the script on the hovered file, and abort
|
||||
# abort if no plugin was selected (ESC or ^C pressed).
|
||||
err=0
|
||||
if ! [ "$plugin" = "" ]; then
|
||||
"$plugin" "$1" || err=1
|
||||
fi
|
||||
|
||||
# If attempt with hovered file fails, try without any target
|
||||
# (nnn selections should still be passed to the script in that case)
|
||||
if [ "$err" -eq "1" ]; then
|
||||
clear && "$plugin" || err=2
|
||||
fi
|
||||
|
||||
# Abort and show error if both fail
|
||||
if [ "$err" -eq "2" ]; then
|
||||
sep="\n---\n"
|
||||
printf "$sep""Failed to execute '%s'. See error above or try without fzfplug. Press return to continue. " "$plugin" && read -r _ && clear
|
||||
fi
|
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Update nnn plugins to installed nnn version
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Authors: Arun Prakash Jana, KlzXS
|
||||
|
||||
CONFIG_DIR=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/
|
||||
PLUGIN_DIR=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins
|
||||
|
||||
merge () {
|
||||
if type nvim >/dev/null 2>&1; then
|
||||
nvim -d "$1" "$2"
|
||||
else
|
||||
vimdiff +0 "$1" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
prompt () {
|
||||
printf "%s\n" "Plugin $1 already exists and is different."
|
||||
printf "Keep (k), merge (m), overwrite (o) [default: k]? "
|
||||
read -r operation
|
||||
|
||||
if [ "$operation" = "m" ]; then
|
||||
op="merge"
|
||||
elif [ "$operation" = "o" ]; then
|
||||
op="cp -vRf"
|
||||
else
|
||||
op="true"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$1" = "master" ] ; then
|
||||
VER="master"
|
||||
ARCHIVE_URL=https://github.com/jarun/nnn/archive/master.tar.gz
|
||||
elif type nnn >/dev/null 2>&1; then
|
||||
VER=$(nnn -V)
|
||||
ARCHIVE_URL=https://github.com/jarun/nnn/releases/download/v"$VER"/nnn-v"$VER".tar.gz
|
||||
else
|
||||
echo "nnn is not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# backup any earlier plugins
|
||||
if [ -d "$PLUGIN_DIR" ]; then
|
||||
tar -C "$CONFIG_DIR" -czf "$CONFIG_DIR""plugins-$(date '+%Y%m%d%H%M').tar.gz" plugins/
|
||||
fi
|
||||
|
||||
mkdir -p "$PLUGIN_DIR"
|
||||
cd "$CONFIG_DIR" || exit 1
|
||||
curl -Ls "$ARCHIVE_URL" -o nnn-"$VER".tar.gz
|
||||
tar -zxf nnn-"$VER".tar.gz
|
||||
|
||||
cd nnn-"$VER"/plugins || exit 1
|
||||
|
||||
# shellcheck disable=SC2044
|
||||
# We do not use obnoxious names for plugins
|
||||
for f in $(find . -maxdepth 1 \( ! -iname "." ! -iname "*.md" \)); do
|
||||
if [ -f ../../plugins/"$f" ]; then
|
||||
if [ "$(diff --brief "$f" ../../plugins/"$f")" ]; then
|
||||
prompt "$f"
|
||||
$op "$f" ../../plugins/
|
||||
fi
|
||||
else
|
||||
cp -vRf "$f" ../../plugins/
|
||||
fi
|
||||
done
|
||||
cd ../.. || exit 1
|
||||
|
||||
rm -rf nnn-"$VER"/ nnn-"$VER".tar.gz
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: cd to the top level of the current git repository in the current context
|
||||
# Dependencies: git
|
||||
# Shell: sh
|
||||
# Author: https://github.com/PatrickF1
|
||||
|
||||
root="$(git rev-parse --show-toplevel 2>/dev/null)"
|
||||
if [ -n "$root" ]; then
|
||||
printf "%s" "0c$root" > "$NNN_PIPE"
|
||||
else
|
||||
printf "Not in a git repository"
|
||||
read -r _
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Decrypts selected files using gpg. The contents of the
|
||||
# decrypted file are stored in a file with extension .dec
|
||||
#
|
||||
# Note: If an appropriate private key cannot be found gpg silently
|
||||
# prints a message in the background and no files are written.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: KlzXS
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
|
||||
printf "(s)election/(c)urrent? [default=c] "
|
||||
read -r resp
|
||||
|
||||
if [ "$resp" = "s" ]; then
|
||||
files=$(tr '\0' '\n' < "$selection")
|
||||
else
|
||||
files=$1
|
||||
fi
|
||||
|
||||
printf "%s" "$files" | xargs -n1 -I{} gpg --decrypt --output "{}.dec" {}
|
||||
|
||||
# Clear selection
|
||||
if [ "$resp" = "s" ] && [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Encrypts selected files using gpg. Can encrypt
|
||||
# asymmetrically (key) or symmetrically (passphrase).
|
||||
# If asymmetric encryption is chosen a key can be
|
||||
# chosen from the list of capable public keys using fzf.
|
||||
#
|
||||
# Note: Symmetric encryption only works for a single (current) file as per gpg limitations
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: KlzXS
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
|
||||
printf "(s)ymmetric, (a)symmetric? [default=a] "
|
||||
read -r symmetry
|
||||
|
||||
if [ "$symmetry" = "s" ]; then
|
||||
gpg --symmetric "$1"
|
||||
else
|
||||
printf "(s)election/(c)urrent? [default=c] "
|
||||
read -r resp
|
||||
|
||||
if [ "$resp" = "s" ]; then
|
||||
files=$(tr '\0' '\n' < "$selection")
|
||||
else
|
||||
files=$1
|
||||
fi
|
||||
|
||||
keyids=$(gpg --list-public-keys --with-colons | grep -E "pub:(.*:){10}.*[eE].*:" | awk -F ":" '{print $5}')
|
||||
|
||||
#awk needs literal $10
|
||||
#shellcheck disable=SC2016
|
||||
keyuids=$(printf "%s" "$keyids" | xargs -n1 -I{} sh -c 'gpg --list-key --with-colons "{}" | grep "uid" | awk -F ":" '\''{printf "%s %s\n", "{}", $10}'\''')
|
||||
|
||||
recipient=$(printf "%s" "$keyuids" | fzf | awk '{print $1}')
|
||||
|
||||
printf "%s" "$files" | xargs -n1 gpg --encrypt --recipient "$recipient"
|
||||
|
||||
# Clear selection
|
||||
if [ "$resp" = "s" ] && [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
#set -x
|
||||
# Description: Send the selected (or hovered) files to your Android device using gsconnect daemon.js.
|
||||
# GSConnect must be configured on the Android device and the PC.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Darukutsu
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
gsconnect=$HOME/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/daemon.js
|
||||
ids=$($gsconnect -l)
|
||||
|
||||
for id in $ids; do
|
||||
if [ -s "$selection" ]; then
|
||||
xargs -0 < "$selection" -I{} "$gsconnect" -d "$id" --share-file="{}"
|
||||
# Clear selection
|
||||
printf "-" > "$NNN_PIPE"
|
||||
else
|
||||
"$gsconnect" -d "$id" --share-file="$2/$1"
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Browse Project Gutenberg catalogue by popularity, then download
|
||||
# and read a book of your choice.
|
||||
#
|
||||
# Details: Set the variable EBOOK_ID to download in html format and read in w3m.
|
||||
# Clear EBOOK_ID to browse available ebooks by popularity and set it to
|
||||
# the ID once you find an interesting one.
|
||||
# To download and read in epub format set READER to an epub reader like
|
||||
# epr: https://github.com/wustho/epr
|
||||
#
|
||||
# More on EBOOK_ID:
|
||||
# Wuthering Heights by Emily Brontë is at https://www.gutenberg.org/ebooks/768
|
||||
# So EBOOK_ID would be 768
|
||||
#
|
||||
# Downloaded ebooks are at ${XDG_CACHE_HOME:-$HOME/.cache}/nnn/gutenbooks/
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
EBOOK_ID="${EBOOK_ID:-""}"
|
||||
DIR="${XDG_CACHE_HOME:-$HOME/.cache}/nnn/gutenbooks/$EBOOK_ID"
|
||||
BROWSE_LINK="https://www.gutenberg.org/ebooks/search/?sort_order=downloads"
|
||||
BROWSER="${BROWSER:-w3m}"
|
||||
READER="${READER:-""}"
|
||||
|
||||
if [ -n "$EBOOK_ID" ]; then
|
||||
if [ ! -e "$DIR" ]; then
|
||||
mkdir -p "$DIR"
|
||||
cd "$DIR" || exit 1
|
||||
|
||||
if [ -z "$READER" ]; then
|
||||
curl -L -O "https://www.gutenberg.org/files/$EBOOK_ID/$EBOOK_ID-h.zip"
|
||||
unzip "$EBOOK_ID"-h.zip
|
||||
else
|
||||
curl -L -o "$EBOOK_ID".epub "https://www.gutenberg.org/ebooks/$EBOOK_ID.epub.noimages"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -d "$DIR" ]; then
|
||||
if [ -z "$READER" ]; then
|
||||
"$BROWSER" "$DIR/$EBOOK_ID-h/$EBOOK_ID-h.htm"
|
||||
else
|
||||
"$READER" "$DIR/$EBOOK_ID.epub"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
"$BROWSER" "$BROWSE_LINK"
|
||||
fi
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Resize images in a directory to screen resolution with imgp
|
||||
#
|
||||
# Dependencipes: imgp - https://github.com/jarun/imgp
|
||||
#
|
||||
# Notes:
|
||||
# 1. Set res to avoid the desktop resolution prompt each time
|
||||
# 2. MINSIZE is set to 1MB by default, adjust it if you want
|
||||
# 3. imgp options used:
|
||||
# a - adaptive mode
|
||||
# c - convert PNG to JPG
|
||||
# k - skip images matching specified hres/vres
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
# set resolution (e.g. 1920x1080)
|
||||
res="${RESOLUTION}"
|
||||
|
||||
# set minimum image size (in bytes) to resize (default: 1MB)
|
||||
MINSIZE="${MINSIZE:-1048576}"
|
||||
|
||||
if [ -z "$res" ]; then
|
||||
printf "desktop resolution (hxv): "
|
||||
read -r res
|
||||
fi
|
||||
|
||||
if [ -n "$res" ] && [ -n "$MINSIZE" ]; then
|
||||
imgp -ackx "$res" -s "$MINSIZE"
|
||||
fi
|
|
@ -0,0 +1,597 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
##########################################################################
|
||||
# The MIT License
|
||||
#
|
||||
# Copyright (c) jomo
|
||||
#
|
||||
# Permission is hereby granted, free of charge,
|
||||
# to any person obtaining a copy of this software and
|
||||
# associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify,
|
||||
# merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom
|
||||
# the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice
|
||||
# shall be included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
##########################################################################
|
||||
|
||||
# https://github.com/jomo/imgur-screenshot
|
||||
# https://help.imgur.com/hc/en-us/articles/209592766-Tools-for-Imgur
|
||||
#
|
||||
# Slightly modified for `nnn` integration
|
||||
#
|
||||
# Shell: Bash
|
||||
# Description: Upload an image file to imgur
|
||||
|
||||
if [ "${1}" = "--debug" ]; then
|
||||
echo "########################################"
|
||||
echo "Enabling debug mode"
|
||||
echo "Please remove credentials before pasting"
|
||||
echo "########################################"
|
||||
echo ""
|
||||
uname -a
|
||||
for arg in ${0} "${@}"; do
|
||||
echo -n "'${arg}' "
|
||||
done
|
||||
echo -e "\n"
|
||||
shift
|
||||
set -x
|
||||
fi
|
||||
|
||||
current_version="v1.7.4"
|
||||
|
||||
function is_mac() {
|
||||
uname | grep -q "Darwin"
|
||||
}
|
||||
|
||||
### IMGUR-SCREENSHOT DEFAULT CONFIG ####
|
||||
|
||||
# You can override the config in ~/.config/imgur-screenshot/settings.conf
|
||||
|
||||
imgur_anon_id="ea6c0ef2987808e"
|
||||
imgur_icon_path="${HOME}/Pictures/imgur.png"
|
||||
|
||||
imgur_acct_key=""
|
||||
imgur_secret=""
|
||||
login="false"
|
||||
album_title=""
|
||||
album_id=""
|
||||
credentials_file="${HOME}/.config/imgur-screenshot/credentials.conf"
|
||||
|
||||
file_name_format="imgur-%Y_%m_%d-%H:%M:%S.png" # when using scrot, must end with .png!
|
||||
file_dir="${HOME}/Pictures"
|
||||
|
||||
upload_connect_timeout="5"
|
||||
upload_timeout="120"
|
||||
upload_retries="1"
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
if is_mac; then
|
||||
screenshot_select_command="screencapture -i %img"
|
||||
screenshot_window_command="screencapture -iWa %img"
|
||||
screenshot_full_command="screencapture %img"
|
||||
open_command="open %url"
|
||||
else
|
||||
screenshot_select_command="scrot -s %img"
|
||||
screenshot_window_command="scrot %img"
|
||||
screenshot_full_command="scrot %img"
|
||||
open_command="xdg-open %url"
|
||||
fi
|
||||
open="true"
|
||||
|
||||
mode="select"
|
||||
edit_command="gimp %img"
|
||||
edit="false"
|
||||
exit_on_album_creation_fail="true"
|
||||
|
||||
log_file="${HOME}/.imgur-screenshot.log"
|
||||
|
||||
auto_delete=""
|
||||
copy_url="true"
|
||||
keep_file="true"
|
||||
check_update="true"
|
||||
|
||||
# NOTICE: if you make changes here, also edit the docs at
|
||||
# https://github.com/jomo/imgur-screenshot/wiki/Config
|
||||
|
||||
# You can override the config in ~/.config/imgur-screenshot/settings.conf
|
||||
|
||||
############## END CONFIG ##############
|
||||
|
||||
settings_path="${HOME}/.config/imgur-screenshot/settings.conf"
|
||||
if [ -f "${settings_path}" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "${settings_path}"
|
||||
fi
|
||||
|
||||
# dependency check
|
||||
if [ "${1}" = "--check" ]; then
|
||||
(type grep &>/dev/null && echo "OK: found grep") || echo "ERROR: grep not found"
|
||||
if is_mac; then
|
||||
if type growlnotify &>/dev/null; then
|
||||
echo "OK: found growlnotify"
|
||||
elif type terminal-notifier &>/dev/null; then
|
||||
echo "OK: found terminal-notifier"
|
||||
else
|
||||
echo "ERROR: growlnotify nor terminal-notifier found"
|
||||
fi
|
||||
(type screencapture &>/dev/null && echo "OK: found screencapture") || echo "ERROR: screencapture not found"
|
||||
(type pbcopy &>/dev/null && echo "OK: found pbcopy") || echo "ERROR: pbcopy not found"
|
||||
else
|
||||
(type notify-send &>/dev/null && echo "OK: found notify-send") || echo "ERROR: notify-send (from libnotify-bin) not found"
|
||||
(type scrot &>/dev/null && echo "OK: found scrot") || echo "ERROR: scrot not found"
|
||||
(type xclip &>/dev/null && echo "OK: found xclip") || echo "ERROR: xclip not found"
|
||||
fi
|
||||
(type curl &>/dev/null && echo "OK: found curl") || echo "ERROR: curl not found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
# notify <'ok'|'error'> <title> <text>
|
||||
function notify() {
|
||||
if is_mac; then
|
||||
if type growlnotify &>/dev/null; then
|
||||
growlnotify --icon "${imgur_icon_path}" --iconpath "${imgur_icon_path}" --title "${2}" --message "${3}"
|
||||
else
|
||||
terminal-notifier -appIcon "${imgur_icon_path}" -contentImage "${imgur_icon_path}" -title "imgur: ${2}" -message "${3}"
|
||||
fi
|
||||
else
|
||||
if [ "${1}" = "error" ]; then
|
||||
notify-send -a ImgurScreenshot -u critical -c "im.error" -i "${imgur_icon_path}" -t 500 "imgur: ${2}" "${3}"
|
||||
else
|
||||
notify-send -a ImgurScreenshot -u low -c "transfer.complete" -i "${imgur_icon_path}" -t 500 "imgur: ${2}" "${3}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function take_screenshot() {
|
||||
echo "Please select area"
|
||||
is_mac || sleep 0.1 # https://bbs.archlinux.org/viewtopic.php?pid=1246173#p1246173
|
||||
|
||||
cmd="screenshot_${mode}_command"
|
||||
cmd=${!cmd//\%img/${1}}
|
||||
|
||||
if ! shot_err="$(${cmd} &>/dev/null)"; then #takes a screenshot with selection
|
||||
echo "Failed to take screenshot '${1}': '${shot_err}'. For more information visit https://github.com/jomo/imgur-screenshot/wiki/Troubleshooting" | tee -a "${log_file}"
|
||||
notify error "Something went wrong :(" "Information has been logged"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function check_for_update() {
|
||||
# exit non-zero on HTTP error, output only the body (no stats) but output errors, follow redirects, output everything to stdout
|
||||
remote_version="$(curl --compressed -fsSL --stderr - "https://api.github.com/repos/jomo/imgur-screenshot/releases" | grep -Em 1 --color 'tag_name":\s*".*"' | cut -d '"' -f 4)"
|
||||
if [ -n "$remote_version" ]; then
|
||||
if [ ! "${current_version}" = "${remote_version}" ] && [ -n "${current_version}" ] && [ -n "${remote_version}" ]; then
|
||||
echo "Update found!"
|
||||
echo "Version ${remote_version} is available (You have ${current_version})"
|
||||
notify ok "Update found" "Version ${remote_version} is available (You have ${current_version}). https://github.com/jomo/imgur-screenshot"
|
||||
echo "Check https://github.com/jomo/imgur-screenshot/releases/${remote_version} for more info."
|
||||
elif [ -z "${current_version}" ] || [ -z "${remote_version}" ]; then
|
||||
echo "Invalid empty version string"
|
||||
echo "Current (local) version: '${current_version}'"
|
||||
echo "Latest (remote) version: '${remote_version}'"
|
||||
else
|
||||
echo "Version ${current_version} is up to date."
|
||||
fi
|
||||
else
|
||||
echo "Failed to check for latest version: ${remote_version}"
|
||||
fi
|
||||
}
|
||||
|
||||
function check_oauth2_client_secrets() {
|
||||
if [ -z "${imgur_acct_key}" ] || [ -z "${imgur_secret}" ]; then
|
||||
echo "In order to upload to your account, register a new application at:"
|
||||
echo "https://api.imgur.com/oauth2/addclient"
|
||||
echo "Select 'OAuth 2 authorization without a callback URL'"
|
||||
echo "Then, set the imgur_acct_key (Client ID) and imgur_secret in your config."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function load_access_token() {
|
||||
token_expire_time=0
|
||||
# check for saved access_token and its expiration date
|
||||
if [ -f "${credentials_file}" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "${credentials_file}"
|
||||
fi
|
||||
current_time="$(date +%s)"
|
||||
preemptive_refresh_time="$((10*60))"
|
||||
expired="$((current_time > (token_expire_time - preemptive_refresh_time)))"
|
||||
if [ -n "${refresh_token}" ]; then
|
||||
# token already set
|
||||
if [ "${expired}" -eq "0" ]; then
|
||||
# token expired
|
||||
refresh_access_token "${credentials_file}"
|
||||
fi
|
||||
else
|
||||
acquire_access_token "${credentials_file}"
|
||||
fi
|
||||
}
|
||||
|
||||
function acquire_access_token() {
|
||||
check_oauth2_client_secrets
|
||||
# prompt for a PIN
|
||||
authorize_url="https://api.imgur.com/oauth2/authorize?client_id=${imgur_acct_key}&response_type=pin"
|
||||
echo "Go to"
|
||||
echo "${authorize_url}"
|
||||
echo "and grant access to this application."
|
||||
read -rp "Enter the PIN: " imgur_pin
|
||||
|
||||
if [ -z "${imgur_pin}" ]; then
|
||||
echo "PIN not entered, exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# exchange the PIN for access token and refresh token
|
||||
response="$(curl --compressed -fsSL --stderr - \
|
||||
-F "client_id=${imgur_acct_key}" \
|
||||
-F "client_secret=${imgur_secret}" \
|
||||
-F "grant_type=pin" \
|
||||
-F "pin=${imgur_pin}" \
|
||||
https://api.imgur.com/oauth2/token)"
|
||||
save_access_token "${response}" "${1}"
|
||||
}
|
||||
|
||||
function refresh_access_token() {
|
||||
check_oauth2_client_secrets
|
||||
token_url="https://api.imgur.com/oauth2/token"
|
||||
# exchange the refresh token for access_token and refresh_token
|
||||
if ! response="$(curl --compressed -fsSL --stderr - \
|
||||
-F "client_id=${imgur_acct_key}" \
|
||||
-F "client_secret=${imgur_secret}" \
|
||||
-F "grant_type=refresh_token" \
|
||||
-F "refresh_token=${refresh_token}" \
|
||||
"${token_url}"
|
||||
)"; then
|
||||
# curl failed
|
||||
handle_upload_error "${response}" "${token_url}"
|
||||
exit 1
|
||||
fi
|
||||
save_access_token "${response}" "${1}"
|
||||
}
|
||||
|
||||
function save_access_token() {
|
||||
if ! grep -q "access_token" <<<"${1}"; then
|
||||
# server did not send access_token
|
||||
echo "Error: Something is wrong with your credentials:"
|
||||
echo "${1}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
access_token="$(grep -Eo 'access_token":".*"' <<<"${1}" | cut -d '"' -f 3)"
|
||||
refresh_token="$(grep -Eo 'refresh_token":".*"' <<<"${1}" | cut -d '"' -f 3)"
|
||||
expires_in="$(grep -Eo 'expires_in":[0-9]*' <<<"${1}" | cut -d ':' -f 2)"
|
||||
token_expire_time="$(( $(date +%s) + expires_in ))"
|
||||
|
||||
# create dir if not exist
|
||||
mkdir -p "$(dirname "${2}")" 2>/dev/null
|
||||
touch "${2}" && chmod 600 "${2}"
|
||||
cat <<EOF > "${2}"
|
||||
access_token="${access_token}"
|
||||
refresh_token="${refresh_token}"
|
||||
token_expire_time="${token_expire_time}"
|
||||
EOF
|
||||
}
|
||||
|
||||
function fetch_account_info() {
|
||||
response="$(curl --compressed --connect-timeout "${upload_connect_timeout}" -m "${upload_timeout}" --retry "${upload_retries}" -fsSL --stderr - -H "Authorization: Bearer ${access_token}" https://api.imgur.com/3/account/me)"
|
||||
if grep -Eq '"success":\s*true' <<<"${response}"; then
|
||||
username="$(grep -Eo '"url":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
|
||||
echo "Logged in as ${username}."
|
||||
echo "https://${username}.imgur.com"
|
||||
else
|
||||
echo "Failed to fetch info: ${response}"
|
||||
fi
|
||||
}
|
||||
|
||||
function delete_image() {
|
||||
response="$(curl --compressed -X DELETE -fsSL --stderr - -H "Authorization: Client-ID ${1}" "https://api.imgur.com/3/image/${2}")"
|
||||
if grep -Eq '"success":\s*true' <<<"${response}"; then
|
||||
echo "Image successfully deleted (delete hash: ${2})." >> "${3}"
|
||||
else
|
||||
echo "The Image could not be deleted: ${response}." >> "${3}"
|
||||
fi
|
||||
}
|
||||
|
||||
function upload_authenticated_image() {
|
||||
echo "Uploading '${1}'..."
|
||||
title="$(echo "${1}" | rev | cut -d "/" -f 1 | cut -d "." -f 2- | rev)"
|
||||
if [ -n "${album_id}" ]; then
|
||||
response="$(curl --compressed --connect-timeout "${upload_connect_timeout}" -m "${upload_timeout}" --retry "${upload_retries}" -fsSL --stderr - -F "title=${title}" -F "image=@\"${1}\"" -F "album=${album_id}" -H "Authorization: Bearer ${access_token}" https://api.imgur.com/3/image)"
|
||||
else
|
||||
response="$(curl --compressed --connect-timeout "${upload_connect_timeout}" -m "${upload_timeout}" --retry "${upload_retries}" -fsSL --stderr - -F "title=${title}" -F "image=@\"${1}\"" -H "Authorization: Bearer ${access_token}" https://api.imgur.com/3/image)"
|
||||
fi
|
||||
|
||||
# JSON parser premium edition (not really)
|
||||
if grep -Eq '"success":\s*true' <<<"${response}"; then
|
||||
img_id="$(grep -Eo '"id":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
|
||||
img_ext="$(grep -Eo '"link":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4 | rev | cut -d "." -f 1 | rev)" # "link" itself has ugly '\/' escaping and no https!
|
||||
del_id="$(grep -Eo '"deletehash":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
|
||||
|
||||
if [ -n "${auto_delete}" ]; then
|
||||
export -f delete_image
|
||||
echo "Deleting image in ${auto_delete} seconds."
|
||||
nohup /bin/bash -c "sleep ${auto_delete} && delete_image ${imgur_anon_id} ${del_id} ${log_file}" &
|
||||
fi
|
||||
|
||||
handle_upload_success "https://i.imgur.com/${img_id}.${img_ext}" "https://imgur.com/delete/${del_id}" "${1}"
|
||||
else # upload failed
|
||||
err_msg="$(grep -Eo '"error":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
|
||||
test -z "${err_msg}" && err_msg="${response}"
|
||||
handle_upload_error "${err_msg}" "${1}"
|
||||
fi
|
||||
}
|
||||
|
||||
function upload_anonymous_image() {
|
||||
echo "Uploading '${1}'..."
|
||||
title="$(echo "${1}" | rev | cut -d "/" -f 1 | cut -d "." -f 2- | rev)"
|
||||
if [ -n "${album_id}" ]; then
|
||||
response="$(curl --compressed --connect-timeout "${upload_connect_timeout}" -m "${upload_timeout}" --retry "${upload_retries}" -fsSL --stderr - -H "Authorization: Client-ID ${imgur_anon_id}" -F "title=${title}" -F "image=@\"${1}\"" -F "album=${album_id}" https://api.imgur.com/3/image)"
|
||||
else
|
||||
response="$(curl --compressed --connect-timeout "${upload_connect_timeout}" -m "${upload_timeout}" --retry "${upload_retries}" -fsSL --stderr - -H "Authorization: Client-ID ${imgur_anon_id}" -F "title=${title}" -F "image=@\"${1}\"" https://api.imgur.com/3/image)"
|
||||
fi
|
||||
# JSON parser premium edition (not really)
|
||||
if grep -Eq '"success":\s*true' <<<"${response}"; then
|
||||
img_id="$(grep -Eo '"id":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
|
||||
img_ext="$(grep -Eo '"link":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4 | rev | cut -d "." -f 1 | rev)" # "link" itself has ugly '\/' escaping and no https!
|
||||
del_id="$(grep -Eo '"deletehash":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
|
||||
|
||||
if [ -n "${auto_delete}" ]; then
|
||||
export -f delete_image
|
||||
echo "Deleting image in ${auto_delete} seconds."
|
||||
nohup /bin/bash -c "sleep ${auto_delete} && delete_image ${imgur_anon_id} ${del_id} ${log_file}" &
|
||||
fi
|
||||
|
||||
handle_upload_success "https://i.imgur.com/${img_id}.${img_ext}" "https://imgur.com/delete/${del_id}" "${1}"
|
||||
else # upload failed
|
||||
err_msg="$(grep -Eo '"error":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
|
||||
test -z "${err_msg}" && err_msg="${response}"
|
||||
handle_upload_error "${err_msg}" "${1}"
|
||||
fi
|
||||
}
|
||||
|
||||
function handle_upload_success() {
|
||||
echo ""
|
||||
echo "image link: ${1}"
|
||||
echo "delete link: ${2}"
|
||||
|
||||
if [ "${copy_url}" = "true" ] && [ -z "${album_title}" ]; then
|
||||
if is_mac; then
|
||||
echo -n "${1}" | pbcopy
|
||||
else
|
||||
echo -n "${1}" | xclip -selection clipboard
|
||||
fi
|
||||
echo "URL copied to clipboard"
|
||||
fi
|
||||
|
||||
# print to log file: image link, image location, delete link
|
||||
echo -e "${1}\t${3}\t${2}" >> "${log_file}"
|
||||
|
||||
notify ok "Upload done!" "${1}"
|
||||
|
||||
# if [ ! -z "${open_command}" ] && [ "${open}" = "true" ]; then
|
||||
# open_cmd=${open_command//\%url/${1}}
|
||||
# open_cmd=${open_cmd//\%img/${2}}
|
||||
# echo "Opening '${open_cmd}'"
|
||||
# eval "${open_cmd}"
|
||||
# fi
|
||||
}
|
||||
|
||||
function handle_upload_error() {
|
||||
error="Upload failed: \"${1}\""
|
||||
echo "${error}"
|
||||
echo -e "Error\t${2}\t${error}" >> "${log_file}"
|
||||
notify error "Upload failed :(" "${1}"
|
||||
}
|
||||
|
||||
function handle_album_creation_success() {
|
||||
echo ""
|
||||
echo "Album link: ${1}"
|
||||
echo "Delete hash: ${2}"
|
||||
echo ""
|
||||
|
||||
notify ok "Album created!" "${1}"
|
||||
|
||||
if [ "${copy_url}" = "true" ]; then
|
||||
if is_mac; then
|
||||
echo -n "${1}" | pbcopy
|
||||
else
|
||||
echo -n "${1}" | xclip -selection clipboard
|
||||
fi
|
||||
echo "URL copied to clipboard"
|
||||
fi
|
||||
|
||||
# print to log file: album link, album title, delete hash
|
||||
echo -e "${1}\t\"${3}\"\t${2}" >> "${log_file}"
|
||||
}
|
||||
|
||||
function handle_album_creation_error() {
|
||||
error="Album creation failed: \"${1}\""
|
||||
echo -e "Error\t${2}\t${error}" >> "${log_file}"
|
||||
notify error "Album creation failed :(" "${1}"
|
||||
if [ ${exit_on_album_creation_fail} ]; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
while [ ${#} != 0 ]; do
|
||||
case "${1}" in
|
||||
-h | --help)
|
||||
echo "usage: ${0} [--debug] [-c | --check | -v | -h | -u]"
|
||||
echo " ${0} [--debug] [option]... [file]..."
|
||||
echo ""
|
||||
echo " --debug Enable debugging, must be first option"
|
||||
echo " -h, --help Show this help, exit"
|
||||
echo " -v, --version Show current version, exit"
|
||||
echo " --check Check if all dependencies are installed, exit"
|
||||
echo " -c, --connect Show connected imgur account, exit"
|
||||
echo " -o, --open <true|false> Override 'open' config"
|
||||
echo " -e, --edit <true|false> Override 'edit' config"
|
||||
echo " -i, --edit-command <command> Override 'edit_command' config (include '%img'), sets --edit 'true'"
|
||||
echo " -l, --login <true|false> Override 'login' config"
|
||||
echo " -a, --album <album_title> Create new album and upload there"
|
||||
echo " -A, --album-id <album_id> Override 'album_id' config"
|
||||
echo " -k, --keep-file <true|false> Override 'keep_file' config"
|
||||
echo " -d, --auto-delete <s> Automatically delete image after <s> seconds"
|
||||
echo " -u, --update Check for updates, exit"
|
||||
echo " file Upload file instead of taking a screenshot"
|
||||
exit 0;;
|
||||
-v | --version)
|
||||
echo "${current_version}"
|
||||
exit 0;;
|
||||
-s | --select)
|
||||
mode="select"
|
||||
shift;;
|
||||
-w | --window)
|
||||
mode="window"
|
||||
shift;;
|
||||
-f | --full)
|
||||
mode="full"
|
||||
shift;;
|
||||
-o | --open)
|
||||
# shellcheck disable=SC2034
|
||||
open="${2}"
|
||||
shift 2;;
|
||||
-e | --edit)
|
||||
edit="${2}"
|
||||
shift 2;;
|
||||
-i | --edit-command)
|
||||
edit_command="${2}"
|
||||
edit="true"
|
||||
shift 2;;
|
||||
-l | --login)
|
||||
login="${2}"
|
||||
shift 2;;
|
||||
-c | --connect)
|
||||
load_access_token
|
||||
fetch_account_info
|
||||
exit 0;;
|
||||
-a | --album)
|
||||
album_title="${2}"
|
||||
shift 2;;
|
||||
-A | --album-id)
|
||||
album_id="${2}"
|
||||
shift 2;;
|
||||
-k | --keep-file)
|
||||
keep_file="${2}"
|
||||
shift 2;;
|
||||
-d | --auto-delete)
|
||||
auto_delete="${2}"
|
||||
shift 2;;
|
||||
-u | --update)
|
||||
check_for_update
|
||||
exit 0;;
|
||||
*)
|
||||
upload_files=("${@}")
|
||||
break;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "${login}" = "true" ]; then
|
||||
# load before changing directory
|
||||
load_access_token
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "${album_title}" ]; then
|
||||
if [ "${login}" = "true" ]; then
|
||||
response="$(curl -fsSL --stderr - \
|
||||
-F "title=${album_title}" \
|
||||
-H "Authorization: Bearer ${access_token}" \
|
||||
https://api.imgur.com/3/album)"
|
||||
else
|
||||
response="$(curl -fsSL --stderr - \
|
||||
-F "title=${album_title}" \
|
||||
-H "Authorization: Client-ID ${imgur_anon_id}" \
|
||||
https://api.imgur.com/3/album)"
|
||||
fi
|
||||
if grep -Eq '"success":\s*true' <<<"${response}"; then # Album creation successful
|
||||
echo "Album '${album_title}' successfully created"
|
||||
album_id="$(grep -Eo '"id":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
|
||||
del_id="$(grep -Eo '"deletehash":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
|
||||
handle_album_creation_success "https://imgur.com/a/${album_id}" "${del_id}" "${album_title}"
|
||||
|
||||
if [ "${login}" = "false" ]; then
|
||||
album_id="${del_id}"
|
||||
fi
|
||||
else # Album creation failed
|
||||
err_msg="$(grep -Eo '"error":\s*"[^"]+"' <<<"${response}" | cut -d "\"" -f 4)"
|
||||
test -z "${err_msg}" && err_msg="${response}"
|
||||
handle_album_creation_error "${err_msg}" "${album_title}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "${upload_files[*]}" ]; then
|
||||
upload_files[0]=""
|
||||
fi
|
||||
|
||||
for upload_file in "${upload_files[@]}"; do
|
||||
|
||||
if [ -z "${upload_file}" ]; then
|
||||
cd "${file_dir}" || exit 1
|
||||
|
||||
# new filename with date
|
||||
img_file="$(date +"${file_name_format}")"
|
||||
take_screenshot "${img_file}"
|
||||
else
|
||||
# upload file instead of screenshot
|
||||
img_file="${upload_file}"
|
||||
fi
|
||||
|
||||
# get full path
|
||||
#cd "$(dirname "$(realpath "${img_file}")")"
|
||||
#img_file="$(realpath "${img_file}")"
|
||||
|
||||
# check if file exists
|
||||
if ! [ -f "${img_file}" ]; then
|
||||
echo "file '${img_file}' doesn't exist !"
|
||||
read -r _
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# open image in editor if configured
|
||||
if [ "${edit}" = "true" ]; then
|
||||
edit_cmd=${edit_command//\%img/${img_file}}
|
||||
echo "Opening editor '${edit_cmd}'"
|
||||
if ! (eval "${edit_cmd}"); then
|
||||
echo "Error for image '${img_file}': command '${edit_cmd}' failed, not uploading. For more information visit https://github.com/jomo/imgur-screenshot/wiki/Troubleshooting" | tee -a "${log_file}"
|
||||
notify error "Something went wrong :(" "Information has been logged"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${login}" = "true" ]; then
|
||||
upload_authenticated_image "${img_file}"
|
||||
else
|
||||
upload_anonymous_image "${img_file}"
|
||||
fi
|
||||
|
||||
# delete file if configured
|
||||
if [ "${keep_file}" = "false" ] && [ -z "${1}" ]; then
|
||||
echo "Deleting temp file ${file_dir}/${img_file}"
|
||||
rm -rf "${img_file}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
|
||||
if [ "${check_update}" = "true" ]; then
|
||||
check_for_update
|
||||
fi
|
||||
|
||||
read -r _
|
|
@ -0,0 +1,113 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Open hovered or current directory in image viewer.
|
||||
# Generates media thumbnails with optional dependencies.
|
||||
#
|
||||
# Dependencies:
|
||||
# - imv (https://github.com/eXeC64/imv) or,
|
||||
# - sxiv (https://github.com/muennich/sxiv) or,
|
||||
# - nsxiv (https://codeberg.org/nsxiv/nsxiv) or,
|
||||
# - ucollage (https://github.com/ckardaris/ucollage) or,
|
||||
# - lsix (https://github.com/hackerb9/lsix), or
|
||||
# - viu (https://github.com/atanunq/viu), or
|
||||
# - catimg (https://github.com/posva/catimg), or
|
||||
# - optional: ffmpeg for audio thumbnails (album art)
|
||||
# - optional: ffmpegthumbnailer for video thumbnails
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana, Luuk van Baal
|
||||
#
|
||||
# Consider setting NNN_PREVIEWDIR to $XDG_CACHE_HOME/nnn/previews
|
||||
# if you want to keep media thumbnails on disk between reboots.
|
||||
NNN_PREVIEWDIR="${NNN_PREVIEWDIR:-${TMPDIR:-/tmp}/nnn/previews}"
|
||||
|
||||
exit_prompt() {
|
||||
[ -n "$1" ] && printf "%s\n" "$1"
|
||||
printf "%s" "Press any key to exit..."
|
||||
cfg=$(stty -g); stty raw -echo; head -c 1; stty "$cfg"
|
||||
clear
|
||||
exit
|
||||
}
|
||||
|
||||
make_thumbs() {
|
||||
mkdir -p "$NNN_PREVIEWDIR$dir" || return
|
||||
if [ "$1" = "viu" ] || [ "$1" = "catimg" ]; then
|
||||
[ -d "$target" ] && exit_prompt "$1 can only display a single image"
|
||||
mime="$(file -bL --mime-type -- "$target")"
|
||||
case "$mime" in
|
||||
audio/*) ffmpeg -i "$target" "$NNN_PREVIEWDIR$target.jpg" -y >/dev/null 2>&1
|
||||
ret="$NNN_PREVIEWDIR/$target.jpg" ;;
|
||||
video/*) ffmpegthumbnailer -i "$target" -o "$NNN_PREVIEWDIR$target.jpg" 2> /dev/null
|
||||
ret="$NNN_PREVIEWDIR/$target.jpg" ;;
|
||||
*) ret="$target" ;;
|
||||
esac
|
||||
fi
|
||||
for file in "$dir"/*; do
|
||||
if [ ! -f "$NNN_PREVIEWDIR$file.jpg" ]; then
|
||||
case "$(file -bL --mime-type -- "$file")" in
|
||||
audio/*) [ "$1" != "sxiv" ] &&
|
||||
ffmpeg -i "$file" "$NNN_PREVIEWDIR$file.jpg" -y >/dev/null 2>&1 ;;
|
||||
video/*) [ "$1" != "ucollage" ] &&
|
||||
ffmpegthumbnailer -i "$file" -o "$NNN_PREVIEWDIR$file.jpg" 2> /dev/null ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
for file in "$NNN_PREVIEWDIR$dir"/*; do
|
||||
filename="$(basename "$file" .jpg)"
|
||||
[ ! -e "$dir/$filename" ] && rm "$file" 2>/dev/null
|
||||
done
|
||||
}
|
||||
|
||||
listimages() {
|
||||
find -L "$dir" "$NNN_PREVIEWDIR$dir" -maxdepth 1 -type f -print0 2>/dev/null | sort -z
|
||||
}
|
||||
|
||||
view_files() {
|
||||
[ -f "$target" ] && count="-n $(listimages | grep -a -m 1 -ZznF "$target" | cut -d: -f1)"
|
||||
case "$1" in
|
||||
nsxiv) listimages | xargs -0 nsxiv -a "${count:--t}" -- ;;
|
||||
sxiv) listimages | xargs -0 sxiv -a "${count:--t}" -- ;;
|
||||
imv*) listimages | xargs -0 "$1" "${count:-}" -- ;;
|
||||
esac
|
||||
}
|
||||
|
||||
target="$(readlink -f "$1")"
|
||||
[ -d "$target" ] && dir="$target" || dir="${target%/*}"
|
||||
if uname | grep -q "Darwin"; then
|
||||
[ -f "$1" ] && open "$1" >/dev/null 2>&1 &
|
||||
elif type lsix >/dev/null 2>&1; then
|
||||
if [ -d "$target" ]; then
|
||||
cd "$target" || exit_prompt
|
||||
fi
|
||||
make_thumbs lsix
|
||||
clear
|
||||
lsix
|
||||
cd "$NNN_PREVIEWDIR$dir" && lsix
|
||||
exit_prompt
|
||||
elif type ucollage >/dev/null 2>&1; then
|
||||
type ffmpeg >/dev/null 2>&1 && make_thumbs ucollage
|
||||
UCOLLAGE_EXPAND_DIRS=1 ucollage "$dir" "$NNN_PREVIEWDIR$dir" || exit_prompt
|
||||
elif type sxiv >/dev/null 2>&1; then
|
||||
type ffmpegthumbnailer >/dev/null 2>&1 && make_thumbs sxiv
|
||||
view_files sxiv >/dev/null 2>&1 &
|
||||
elif type nsxiv >/dev/null 2>&1; then
|
||||
type ffmpegthumbnailer >/dev/null 2>&1 && make_thumbs sxiv
|
||||
view_files nsxiv >/dev/null 2>&1 &
|
||||
elif type imv >/dev/null 2>&1; then
|
||||
make_thumbs imv
|
||||
view_files imv >/dev/null 2>&1 &
|
||||
elif type imvr >/dev/null 2>&1; then
|
||||
make_thumbs imv
|
||||
view_files imvr >/dev/null 2>&1 &
|
||||
elif type viu >/dev/null 2>&1; then
|
||||
clear
|
||||
make_thumbs viu
|
||||
viu -n "$ret"
|
||||
exit_prompt
|
||||
elif type catimg >/dev/null 2>&1; then
|
||||
make_thumbs catimg
|
||||
catimg "$ret"
|
||||
exit_prompt
|
||||
else
|
||||
exit_prompt "Please install sxiv/nsxiv/imv/viu/catimg/lsix."
|
||||
fi
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Shows the external IP address and whois information. Useful over VPNs.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
IP=$(curl -s ifconfig.me)
|
||||
|
||||
whois "$IP"
|
||||
echo your external IP address is "$IP"
|
||||
|
||||
read -r _
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Send the selected files to your Android device using kdeconnect-cli.
|
||||
# kdeconnect must be configured on the Android device and the PC.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: juacq97
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
|
||||
id=$(kdeconnect-cli -a --id-only | awk '{print $1}')
|
||||
if [ -s "$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"
|
||||
|
||||
# Clear selection
|
||||
if [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Independent POSIX-compliant GUI application launcher.
|
||||
# Fuzzy find executables in $PATH and launch an application.
|
||||
# stdin, stdout, stderr are suppressed so CLI tools exit silently.
|
||||
#
|
||||
# To configure launch as an independent app launcher add a keybind
|
||||
# to open launch in a terminal e.g.,
|
||||
#
|
||||
# xfce4-terminal -e "${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins/launch
|
||||
#
|
||||
# Dependencies: fzf
|
||||
#
|
||||
# Usage: launch [delay]
|
||||
# delay is in seconds, if omitted launch waits for 1 sec
|
||||
#
|
||||
# Integration with nnn: launch is installed with other plugins, nnn picks it up.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
|
||||
IFS=':'
|
||||
|
||||
get_selection() {
|
||||
if type fzf >/dev/null 2>&1; then
|
||||
{ IFS=':'; ls -H $PATH; } | sort | fzf
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
if selection=$( get_selection ); then
|
||||
setsid "$selection" 2>/dev/null 1>/dev/null &
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
sleep "$1"
|
||||
else
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Find and list files by mime type in smart context
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
# shellcheck disable=SC1090,SC1091
|
||||
. "$(dirname "$0")"/.nnn-plugin-helper
|
||||
|
||||
printf "mime (e.g., video/audio/image): "
|
||||
read -r mime
|
||||
|
||||
printf "%s" "+l" > "$NNN_PIPE"
|
||||
find . | file -if- | grep "$mime" | awk -F: '{printf "%s\0", $1}' > "$NNN_PIPE"
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Fetches the lyrics of the track currently playing in MOC
|
||||
#
|
||||
# Dependencies: ddgr (https://github.com/jarun/ddgr)
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
# Check if MOC server is running
|
||||
cmd=$(pgrep -x mocp 2>/dev/null)
|
||||
ret=$cmd
|
||||
if [ -z "$ret" ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
# Grab the output
|
||||
out="$(mocp -i)"
|
||||
|
||||
# Check if anything is playing
|
||||
state=$(echo "$out" | grep "State:" | cut -d' ' -f2)
|
||||
if ! [ "$state" = 'PLAY' ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
# Try by Artist and Song Title first
|
||||
ARTIST="$(echo "$out" | grep 'Artist:' | cut -d':' -f2 | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//')"
|
||||
TITLE="$(echo "$out" | grep 'SongTitle:' | cut -d':' -f2 | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//')"
|
||||
|
||||
if [ -n "$ARTIST" ] && [ -n "$TITLE" ]; then
|
||||
ddgr -w azlyrics.com --ducky "$ARTIST" "$TITLE"
|
||||
else
|
||||
# Try by file name
|
||||
FILENAME="$(basename "$(echo "$out" | grep 'File:' | cut -d':' -f2)")"
|
||||
FILENAME="$(echo "${FILENAME%%.*}" | tr -d -)"
|
||||
|
||||
if [ -n "$FILENAME" ]; then
|
||||
ddgr -w azlyrics.com --ducky "$FILENAME"
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Appends and optionally plays music in MOC
|
||||
#
|
||||
# Notes:
|
||||
# - if selection is available, plays it, else plays the current file or directory
|
||||
# - appends tracks and exits is MOC is running, else clears playlist and adds tracks
|
||||
# - to let mocp shuffle tracks, set SHUFFLE=1
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Authors: Arun Prakash Jana, ath3
|
||||
|
||||
IFS="$(printf '\n\r')"
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
cmd=$(pgrep -x mocp 2>/dev/null)
|
||||
ret=$cmd
|
||||
|
||||
SHUFFLE="${SHUFFLE:-0}"
|
||||
|
||||
mocp_add ()
|
||||
{
|
||||
if [ "$SHUFFLE" = 1 ]; then
|
||||
if [ "$resp" = "y" ]; then
|
||||
arr=$(tr '\0' '\n' < "$selection")
|
||||
elif [ -n "$1" ]; then
|
||||
arr="$1"
|
||||
fi
|
||||
|
||||
for entry in $arr
|
||||
do
|
||||
if [ -d "$entry" ]; then
|
||||
arr2=$arr2$(find "$entry" -type f \( ! -iname "*.m3u" ! -iname "*.pls" \))
|
||||
elif echo "$entry" | grep -qv '\.m3u$\|\.pls$' ; then
|
||||
arr2=$(printf "%s\n%s" "$entry" "$arr2")
|
||||
fi
|
||||
done
|
||||
|
||||
mocp -o shuffle
|
||||
echo "$arr2" | xargs -d "\n" mocp -a
|
||||
else
|
||||
if [ "$resp" = "y" ]; then
|
||||
xargs < "$selection" -0 mocp -a
|
||||
else
|
||||
mocp -a "$1"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if [ ! -s "$selection" ] && [ -z "$1" ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ "$2" = "opener" ]; then
|
||||
:
|
||||
elif [ -s "$selection" ]; then
|
||||
printf "Work with selection? Enter 'y' to confirm: "
|
||||
read -r resp
|
||||
fi
|
||||
|
||||
if [ -z "$ret" ]; then
|
||||
# mocp not running
|
||||
mocp -S
|
||||
else
|
||||
# mocp running, check if it's playing
|
||||
state=$(mocp -i | grep "State:" | cut -d' ' -f2)
|
||||
|
||||
if [ "$state" = 'PLAY' ]; then
|
||||
# add to playlist and exit
|
||||
mocp_add "$1"
|
||||
|
||||
# uncomment the line below to show mocp interface after appending
|
||||
# mocp
|
||||
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
# clear selection and play
|
||||
mocp -c
|
||||
mocp_add "$1" "$resp"
|
||||
mocp -p
|
||||
|
||||
# uncomment the line below to show mocp interface after appending
|
||||
# mocp
|
||||
|
||||
# Clear selection
|
||||
if [ "$resp" = "y" ] && [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Extract audio from multimedia files and convert to mp3
|
||||
#
|
||||
# Dependencies: ffmpeg compiled with libmp3lame audio codec support
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
outdir=_mp3files
|
||||
|
||||
handle_multimedia() {
|
||||
mime="${1}"
|
||||
file="${2}"
|
||||
|
||||
case "${mime}" in
|
||||
audio/* | video/*)
|
||||
ffmpeg -i "${file}" -vn -codec:a libmp3lame -q:a 2 "${outdir}/${file%.*}.mp3"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
printf "Process 'a'll in directory or 'c'urrent? "
|
||||
read -r resp
|
||||
|
||||
if [ "$resp" = "a" ]; then
|
||||
if ! [ -e "${outdir}" ]; then
|
||||
mkdir "${outdir}"
|
||||
fi
|
||||
|
||||
for f in *; do
|
||||
if [ -f "${f}" ]; then
|
||||
mimestr="$( file --dereference --brief --mime-type -- "${f}" )"
|
||||
handle_multimedia "${mimestr}" "${f}"
|
||||
fi
|
||||
done
|
||||
elif [ "$resp" = "c" ] && [ -f "$1" ]; then
|
||||
ffmpeg -i "${1}" -vn -codec:a libmp3lame -q:a 2 "${1%.*}.mp3"
|
||||
fi
|
|
@ -0,0 +1,76 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Toggle mount of MTP device (eg. Android device)
|
||||
# 'l' to list mountable devices
|
||||
# 'n' integer associated to device to mount
|
||||
# 'q'/'Return' exit
|
||||
#
|
||||
# Dependencies: gvfs-mtp
|
||||
#
|
||||
# Notes: The MTP device should be mounted at /run/user/$UID/gvfs.
|
||||
# Put /run/user/$UID/gvfs to bookmark entries (NNN_BMS) for faster access.
|
||||
# Make sure the device is unlocked when mounting.
|
||||
#
|
||||
# When doing copy-paste into MTP device, you will get an error like this:
|
||||
# cp: preserving times for './gambar1.png': Operation not supported
|
||||
# That just means the file is copied but timestamp won't be preserved.
|
||||
# It's like doing `cp -p localfile.txt file-to-SMB.txt`.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Benawi Adha
|
||||
|
||||
prompt="Device number ('l' to list): "
|
||||
|
||||
IFS='
|
||||
'
|
||||
|
||||
lsmtp () {
|
||||
devs=$(gio mount -li | grep -e 'activation_root' | sed 's/\s*activation_root=//g')
|
||||
c=1
|
||||
printf "Devices list:\n"
|
||||
for i in $devs; do
|
||||
printf "%s %s\\n" "$c" "$i"
|
||||
c=$(( c + 1 ))
|
||||
done
|
||||
echo
|
||||
}
|
||||
|
||||
lsmtp
|
||||
printf "%s" "$prompt"
|
||||
read -r input
|
||||
|
||||
while [ -n "$input" ]
|
||||
do
|
||||
if [ "$input" = "l" ]; then
|
||||
lsmtp
|
||||
elif [ "$input" = "q" ] || [ "$input" -eq 0 ]; then
|
||||
exit
|
||||
elif [ "$input" -le "$(printf '%s\n' "${devs}" | grep -c '^')" ]; then
|
||||
# dev=$(printf "%s\n" "$devs" | cut -d$'\n' -f${input})
|
||||
c=1
|
||||
for i in $devs; do
|
||||
dev=$i
|
||||
if [ "$input" -eq $c ]; then
|
||||
break
|
||||
fi
|
||||
c=$(( c + 1 ))
|
||||
done
|
||||
|
||||
if (gio mount -l | grep '^Mount([1-9]).*'"$dev" ) 1>/dev/null; then
|
||||
if gio mount -u "${dev}"; then
|
||||
printf "%s unmounted\n" "$dev"
|
||||
fi
|
||||
else
|
||||
if gio mount "${dev}"; then
|
||||
printf "%s mounted to /run/user/\$UID/gvfs\n" "$dev"
|
||||
fi
|
||||
fi
|
||||
echo
|
||||
else
|
||||
printf "Invalid input\n"
|
||||
fi
|
||||
|
||||
printf "%s" "$prompt"
|
||||
read -r input
|
||||
done
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Backup nnn configuration
|
||||
# - config dir content
|
||||
# - environment config
|
||||
# - shell functions and aliases
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Léo Villeveygoux
|
||||
|
||||
nnn_aliases="n nnn"
|
||||
|
||||
outdir="nnn-$(whoami)@$(hostname)"
|
||||
|
||||
outfile="${outdir}.tar.bz2"
|
||||
|
||||
shellname="$(basename "$SHELL")"
|
||||
|
||||
conffile="config.txt"
|
||||
|
||||
configdir="${XDG_CONFIG_HOME:-$HOME/.config}/nnn"
|
||||
|
||||
workdir="$PWD"
|
||||
|
||||
tempdir="$(mktemp -d)"
|
||||
|
||||
mkdir "$tempdir/$outdir"
|
||||
|
||||
if [ ! -d "$tempdir" ]; then
|
||||
echo "Can't create work directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$tempdir/$outdir" || exit 1
|
||||
|
||||
# Backing up config dir content
|
||||
cp -r "$configdir" . || exit 1
|
||||
|
||||
# Environment config
|
||||
env | sed "s/'/'\\\\''/" |\
|
||||
awk '/^NNN_/{print "export '\''"$0"'\''"}' > "$conffile"
|
||||
|
||||
# Shell functions/aliases
|
||||
case "$shellname" in
|
||||
bash)
|
||||
for name in $nnn_aliases ; do
|
||||
if [ "$(bash -ic "type -t $name")" = "function" ] ; then
|
||||
bash -ic "type $name" | tail -n+2 >> "$conffile"
|
||||
elif bash -ic "alias $name" >/dev/null 2>&1 ; then
|
||||
bash -ic "alias $name" >> "$conffile"
|
||||
fi
|
||||
done
|
||||
;;
|
||||
zsh)
|
||||
for name in $nnn_aliases ; do
|
||||
if zsh -ic "functions $name" ; then
|
||||
zsh -ic "functions $name" >> "$conffile"
|
||||
elif zsh -ic "alias $name" ; then
|
||||
echo alias "$(zsh -ic "alias $name")" >> "$conffile"
|
||||
fi
|
||||
done
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown shell, skipping alias/function checking." >&2
|
||||
;;
|
||||
esac
|
||||
|
||||
cd .. || exit 1
|
||||
|
||||
printf "Saving as '%s' ... " "$workdir/$outfile"
|
||||
|
||||
tar caf "$workdir/$outfile" "$outdir" && echo "Done" || echo "Failed"
|
||||
|
||||
cd "$workdir" && rm -rf "$tempdir"
|
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Toggle mount status of a device using pmount
|
||||
# If the device is not mounted, it will be mounted.
|
||||
# If the device is mounted, it will be unmounted and powered down.
|
||||
#
|
||||
# Dependencies: lsblk, pmount
|
||||
#
|
||||
# Usage: Runs `lsblk` on 'l', exits on 'Return`.
|
||||
#
|
||||
# Notes:
|
||||
# - The script uses Linux-specific lsblk to list block devices. Alternatives:
|
||||
# macOS: "diskutil list"
|
||||
# BSD: "geom disk list"
|
||||
# - The script uses udisksctl (from udisks2) to power down devices. This is also Linux-specific.
|
||||
# Users on non-Linux platforms can comment it and use an alterntive to power-down disks.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
prompt="device name [e.g. sdXn] ('l'ist, 'q'uit): "
|
||||
|
||||
lsblk
|
||||
|
||||
printf "\nEnsure you aren't still in the mounted device.\n"
|
||||
printf "%s" "$prompt"
|
||||
read -r dev
|
||||
|
||||
while [ -n "$dev" ]
|
||||
do
|
||||
if [ "$dev" = "l" ]; then
|
||||
lsblk
|
||||
elif [ "$dev" = "q" ]; then
|
||||
exit
|
||||
else
|
||||
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
|
|
@ -0,0 +1,555 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Sample script to play files in apps by file type or mime
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Usage: nuke filepath
|
||||
#
|
||||
# Integration with nnn:
|
||||
# 1. Export the required config:
|
||||
# export NNN_OPENER=/absolute/path/to/nuke
|
||||
# # Otherwise, if nuke is in $PATH
|
||||
# # export NNN_OPENER=nuke
|
||||
# 2. Run nnn with the program option to indicate a CLI opener
|
||||
# nnn -c
|
||||
# # The -c program option overrides option -e
|
||||
# 3. nuke can use nnn plugins (e.g. mocq is used for audio), $PATH is updated.
|
||||
#
|
||||
# Details:
|
||||
# Inspired by ranger's scope.sh, modified for usage with nnn.
|
||||
#
|
||||
# Guards against accidentally opening mime types like executables, shared libs etc.
|
||||
#
|
||||
# Tries to play 'file' (1st argument) in the following order:
|
||||
# 1. by extension
|
||||
# 2. by mime (image, video, audio, pdf)
|
||||
# 3. by mime (other file types)
|
||||
# 4. by mime (prompt and run executables)
|
||||
#
|
||||
# Modification tips:
|
||||
# 1. Invokes CLI utilities by default. Set GUI to 1 to enable GUI apps.
|
||||
# 2. PAGER is "less -R".
|
||||
# 3. Start GUI apps in bg to unblock. Redirect stdout and strerr if required.
|
||||
# 4. Some CLI utilities are piped to the $PAGER, to wait and quit uniformly.
|
||||
# 5. If the output cannot be paged use "read -r _" to wait for user input.
|
||||
# 6. On a DE, try 'xdg-open' or 'open' in handle_fallback() as last resort.
|
||||
#
|
||||
# Feel free to change the utilities to your favourites and add more mimes.
|
||||
#
|
||||
# Defaults:
|
||||
# By extension (only the enabled ones):
|
||||
# most archives: list with atool, bsdtar
|
||||
# rar: list with unrar
|
||||
# 7-zip: list with 7z
|
||||
# pdf: zathura (GUI), pdftotext, mutool, exiftool
|
||||
# audio: mocq (nnn plugin using MOC), mpv, media_client (Haiku), mediainfo, exiftool
|
||||
# avi|mkv|mp4: smplayer, mpv (GUI), ffmpegthumbnailer, mediainfo, exiftool
|
||||
# log: vi
|
||||
# torrent: rtorrent, transmission-show
|
||||
# odt|ods|odp|sxw: odt2txt
|
||||
# md: glow (https://github.com/charmbracelet/glow), lowdown (https://kristaps.bsd.lv/lowdown)
|
||||
# htm|html|xhtml: w3m, lynx, elinks
|
||||
# json: jq, python (json.tool module)
|
||||
# Multimedia by mime:
|
||||
# image/*: imv/sxiv/nsxiv (GUI), viu (https://github.com/atanunq/viu), img2txt, exiftool
|
||||
# video/*: smplayer, mpv (GUI), ffmpegthumbnailer, mediainfo, exiftool
|
||||
# audio/*: mocq (nnn plugin using MOC), mpv, media_client (Haiku), mediainfo, exiftool
|
||||
# application/pdf: zathura (GUI), pdftotext, mutool, exiftool
|
||||
# Other mimes:
|
||||
# text/troff: man -l
|
||||
# text/* | */xml: vi
|
||||
# image/vnd.djvu): djvutxt, exiftool
|
||||
#
|
||||
# TODO:
|
||||
# 1. Adapt, test and enable all mimes
|
||||
# 2. Clean-up the unnecessary exit codes
|
||||
|
||||
# set to 1 to enable GUI apps and/or BIN execution
|
||||
GUI="${GUI:-0}"
|
||||
BIN="${BIN:-0}"
|
||||
|
||||
set -euf -o noclobber -o noglob -o nounset
|
||||
IFS="$(printf '%b_' '\n')"; IFS="${IFS%_}" # protect trailing \n
|
||||
|
||||
PATH=$PATH:"${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins"
|
||||
IMAGE_CACHE_PATH="$(dirname "$1")"/.thumbs
|
||||
|
||||
FPATH="$1"
|
||||
FNAME=$(basename "$1")
|
||||
EDITOR="${VISUAL:-${EDITOR:-vi}}"
|
||||
PAGER="${PAGER:-less -R}"
|
||||
ext="${FNAME##*.}"
|
||||
if [ -n "$ext" ]; then
|
||||
ext="$(printf "%s" "${ext}" | tr '[:upper:]' '[:lower:]')"
|
||||
fi
|
||||
|
||||
is_mac() {
|
||||
uname | grep -q "Darwin"
|
||||
}
|
||||
|
||||
handle_pdf() {
|
||||
if [ "$GUI" -ne 0 ]; then
|
||||
if is_mac; then
|
||||
nohup open "${FPATH}" >/dev/null 2>&1 &
|
||||
elif type zathura >/dev/null 2>&1; then
|
||||
nohup zathura "${FPATH}" >/dev/null 2>&1 &
|
||||
else
|
||||
return
|
||||
fi
|
||||
elif type pdftotext >/dev/null 2>&1; then
|
||||
## Preview as text conversion
|
||||
pdftotext -l 10 -nopgbrk -q -- "${FPATH}" - | eval "$PAGER"
|
||||
elif type mutool >/dev/null 2>&1; then
|
||||
mutool draw -F txt -i -- "${FPATH}" 1-10 | eval "$PAGER"
|
||||
elif type exiftool >/dev/null 2>&1; then
|
||||
exiftool "${FPATH}" | eval "$PAGER"
|
||||
else
|
||||
return
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
handle_audio() {
|
||||
if type mocp >/dev/null 2>&1 && type mocq >/dev/null 2>&1; then
|
||||
mocq "${FPATH}" "opener" >/dev/null 2>&1
|
||||
elif type mpv >/dev/null 2>&1; then
|
||||
mpv "${FPATH}" >/dev/null 2>&1 &
|
||||
elif type media_client >/dev/null 2>&1; then
|
||||
media_client play "${FPATH}" >/dev/null 2>&1 &
|
||||
elif type mediainfo >/dev/null 2>&1; then
|
||||
mediainfo "${FPATH}" | eval "$PAGER"
|
||||
elif type exiftool >/dev/null 2>&1; then
|
||||
exiftool "${FPATH}"| eval "$PAGER"
|
||||
else
|
||||
return
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
handle_video() {
|
||||
if [ "$GUI" -ne 0 ]; then
|
||||
if is_mac; then
|
||||
nohup open "${FPATH}" >/dev/null 2>&1 &
|
||||
elif type smplayer >/dev/null 2>&1; then
|
||||
nohup smplayer "${FPATH}" >/dev/null 2>&1 &
|
||||
elif type mpv >/dev/null 2>&1; then
|
||||
nohup mpv "${FPATH}" >/dev/null 2>&1 &
|
||||
else
|
||||
return
|
||||
fi
|
||||
elif type ffmpegthumbnailer >/dev/null 2>&1; then
|
||||
# Thumbnail
|
||||
[ -d "${IMAGE_CACHE_PATH}" ] || mkdir "${IMAGE_CACHE_PATH}"
|
||||
ffmpegthumbnailer -i "${FPATH}" -o "${IMAGE_CACHE_PATH}/${FNAME}.jpg" -s 0
|
||||
viu -n "${IMAGE_CACHE_PATH}/${FNAME}.jpg" | eval "$PAGER"
|
||||
elif type mediainfo >/dev/null 2>&1; then
|
||||
mediainfo "${FPATH}" | eval "$PAGER"
|
||||
elif type exiftool >/dev/null 2>&1; then
|
||||
exiftool "${FPATH}"| eval "$PAGER"
|
||||
else
|
||||
return
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
# handle this extension and exit
|
||||
handle_extension() {
|
||||
case "${ext}" in
|
||||
## Archive
|
||||
a|ace|alz|arc|arj|bz|bz2|cab|cpio|deb|gz|jar|lha|lz|lzh|lzma|lzo|\
|
||||
rpm|rz|t7z|tar|tbz|tbz2|tgz|tlz|txz|tZ|tzo|war|xpi|xz|Z|zip)
|
||||
if type atool >/dev/null 2>&1; then
|
||||
atool --list -- "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
elif type bsdtar >/dev/null 2>&1; then
|
||||
bsdtar --list --file "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
fi
|
||||
exit 1;;
|
||||
rar)
|
||||
if type unrar >/dev/null 2>&1; then
|
||||
## Avoid password prompt by providing empty password
|
||||
unrar lt -p- -- "${FPATH}" | eval "$PAGER"
|
||||
fi
|
||||
exit 1;;
|
||||
7z)
|
||||
if type 7z >/dev/null 2>&1; then
|
||||
## Avoid password prompt by providing empty password
|
||||
7z l -p -- "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
fi
|
||||
exit 1;;
|
||||
|
||||
## PDF
|
||||
pdf)
|
||||
handle_pdf
|
||||
exit 1;;
|
||||
|
||||
## Audio
|
||||
aac|flac|m4a|mid|midi|mpa|mp2|mp3|ogg|wav|wma)
|
||||
handle_audio
|
||||
exit 1;;
|
||||
|
||||
## Video
|
||||
avi|mkv|mp4)
|
||||
handle_video
|
||||
exit 1;;
|
||||
|
||||
## Log files
|
||||
log)
|
||||
"$EDITOR" "${FPATH}"
|
||||
exit 0;;
|
||||
|
||||
## BitTorrent
|
||||
torrent)
|
||||
if type rtorrent >/dev/null 2>&1; then
|
||||
rtorrent "${FPATH}"
|
||||
exit 0
|
||||
elif type transmission-show >/dev/null 2>&1; then
|
||||
transmission-show -- "${FPATH}"
|
||||
exit 0
|
||||
fi
|
||||
exit 1;;
|
||||
|
||||
## OpenDocument
|
||||
odt|ods|odp|sxw)
|
||||
if type odt2txt >/dev/null 2>&1; then
|
||||
## Preview as text conversion
|
||||
odt2txt "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
fi
|
||||
exit 1;;
|
||||
|
||||
## Markdown
|
||||
md)
|
||||
if type glow >/dev/null 2>&1; then
|
||||
glow -sdark "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
elif type lowdown >/dev/null 2>&1; then
|
||||
lowdown -Tterm "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
|
||||
## HTML
|
||||
htm|html|xhtml)
|
||||
## Preview as text conversion
|
||||
if type w3m >/dev/null 2>&1; then
|
||||
w3m -dump "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
elif type lynx >/dev/null 2>&1; then
|
||||
lynx -dump -- "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
elif type elinks >/dev/null 2>&1; then
|
||||
elinks -dump "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
|
||||
## JSON
|
||||
json)
|
||||
if type jq >/dev/null 2>&1; then
|
||||
jq --color-output . "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
elif type python >/dev/null 2>&1; then
|
||||
python -m json.tool -- "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# sets the variable abs_target, this should be faster than calling printf
|
||||
abspath() {
|
||||
case "$1" in
|
||||
/*) abs_target="$1";;
|
||||
*) abs_target="$PWD/$1";;
|
||||
esac
|
||||
}
|
||||
|
||||
# storing the result to a tmp file is faster than calling listimages twice
|
||||
listimages() {
|
||||
find -L "///${1%/*}" -maxdepth 1 -type f -print0 |
|
||||
grep -izZE '\.(jpe?g|png|gif|webp|tiff|bmp|ico|svg)$' |
|
||||
sort -z | tee "$tmp"
|
||||
}
|
||||
|
||||
load_dir() {
|
||||
abspath "$2"
|
||||
tmp="${TMPDIR:-/tmp}/nuke_$$"
|
||||
trap 'rm -f $tmp' EXIT
|
||||
count="$(listimages "$abs_target" | grep -a -m 1 -ZznF "$abs_target" | cut -d: -f1)"
|
||||
|
||||
if [ -n "$count" ]; then
|
||||
if [ "$GUI" -ne 0 ]; then
|
||||
xargs -0 nohup "$1" -n "$count" -- < "$tmp"
|
||||
else
|
||||
xargs -0 "$1" -n "$count" -- < "$tmp"
|
||||
fi
|
||||
else
|
||||
shift
|
||||
"$1" -- "$@" # fallback
|
||||
fi
|
||||
}
|
||||
|
||||
handle_multimedia() {
|
||||
## Size of the preview if there are multiple options or it has to be
|
||||
## rendered from vector graphics. If the conversion program allows
|
||||
## specifying only one dimension while keeping the aspect ratio, the width
|
||||
## will be used.
|
||||
# local DEFAULT_SIZE="1920x1080"
|
||||
|
||||
mimetype="${1}"
|
||||
case "${mimetype}" in
|
||||
## SVG
|
||||
# image/svg+xml|image/svg)
|
||||
# convert -- "${FPATH}" "${IMAGE_CACHE_PATH}" && exit 6
|
||||
# exit 1;;
|
||||
|
||||
## DjVu
|
||||
# image/vnd.djvu)
|
||||
# ddjvu -format=tiff -quality=90 -page=1 -size="${DEFAULT_SIZE}" \
|
||||
# - "${IMAGE_CACHE_PATH}" < "${FPATH}" \
|
||||
# && exit 6 || exit 1;;
|
||||
|
||||
## Image
|
||||
image/*)
|
||||
if [ "$GUI" -ne 0 ]; then
|
||||
if is_mac; then
|
||||
nohup open "${FPATH}" >/dev/null 2>&1 &
|
||||
exit 0
|
||||
elif type imv >/dev/null 2>&1; then
|
||||
load_dir imv "${FPATH}" >/dev/null 2>&1 &
|
||||
exit 0
|
||||
elif type imvr >/dev/null 2>&1; then
|
||||
load_dir imvr "${FPATH}" >/dev/null 2>&1 &
|
||||
exit 0
|
||||
elif type sxiv >/dev/null 2>&1; then
|
||||
load_dir sxiv "${FPATH}" >/dev/null 2>&1 &
|
||||
exit 0
|
||||
elif type nsxiv >/dev/null 2>&1; then
|
||||
load_dir nsxiv "${FPATH}" >/dev/null 2>&1 &
|
||||
exit 0
|
||||
fi
|
||||
elif type viu >/dev/null 2>&1; then
|
||||
viu -n "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
elif type img2txt >/dev/null 2>&1; then
|
||||
img2txt --gamma=0.6 -- "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
elif type exiftool >/dev/null 2>&1; then
|
||||
exiftool "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
fi
|
||||
# local orientation
|
||||
# orientation="$( identify -format '%[EXIF:Orientation]\n' -- "${FPATH}" )"
|
||||
## If orientation data is present and the image actually
|
||||
## needs rotating ("1" means no rotation)...
|
||||
# if [[ -n "$orientation" && "$orientation" != 1 ]]; then
|
||||
## ...auto-rotate the image according to the EXIF data.
|
||||
# convert -- "${FPATH}" -auto-orient "${IMAGE_CACHE_PATH}" && exit 6
|
||||
# fi
|
||||
|
||||
## `w3mimgdisplay` will be called for all images (unless overridden
|
||||
## as above), but might fail for unsupported types.
|
||||
exit 7;;
|
||||
|
||||
## PDF
|
||||
application/pdf)
|
||||
handle_pdf
|
||||
exit 1;;
|
||||
|
||||
## Audio
|
||||
audio/*)
|
||||
handle_audio
|
||||
exit 1;;
|
||||
|
||||
## Video
|
||||
video/*)
|
||||
handle_video
|
||||
exit 1;;
|
||||
|
||||
# pdftoppm -f 1 -l 1 \
|
||||
# -scale-to-x "${DEFAULT_SIZE%x*}" \
|
||||
# -scale-to-y -1 \
|
||||
# -singlefile \
|
||||
# -jpeg -tiffcompression jpeg \
|
||||
# -- "${FPATH}" "${IMAGE_CACHE_PATH%.*}" \
|
||||
# && exit 6 || exit 1;;
|
||||
|
||||
|
||||
## ePub, MOBI, FB2 (using Calibre)
|
||||
# application/epub+zip|application/x-mobipocket-ebook|\
|
||||
# application/x-fictionbook+xml)
|
||||
# # ePub (using https://github.com/marianosimone/epub-thumbnailer)
|
||||
# epub-thumbnailer "${FPATH}" "${IMAGE_CACHE_PATH}" \
|
||||
# "${DEFAULT_SIZE%x*}" && exit 6
|
||||
# ebook-meta --get-cover="${IMAGE_CACHE_PATH}" -- "${FPATH}" \
|
||||
# >/dev/null && exit 6
|
||||
# exit 1;;
|
||||
|
||||
## Font
|
||||
# application/font*|application/*opentype)
|
||||
# preview_png="/tmp/$(basename "${IMAGE_CACHE_PATH%.*}").png"
|
||||
# if fontimage -o "${preview_png}" \
|
||||
# --pixelsize "120" \
|
||||
# --fontname \
|
||||
# --pixelsize "80" \
|
||||
# --text " ABCDEFGHIJKLMNOPQRSTUVWXYZ " \
|
||||
# --text " abcdefghijklmnopqrstuvwxyz " \
|
||||
# --text " 0123456789.:,;(*!?') ff fl fi ffi ffl " \
|
||||
# --text " The quick brown fox jumps over the lazy dog. " \
|
||||
# "${FPATH}";
|
||||
# then
|
||||
# convert -- "${preview_png}" "${IMAGE_CACHE_PATH}" \
|
||||
# && rm "${preview_png}" \
|
||||
# && exit 6
|
||||
# else
|
||||
# exit 1
|
||||
# fi
|
||||
# ;;
|
||||
|
||||
## Preview archives using the first image inside.
|
||||
## (Very useful for comic book collections for example.)
|
||||
# application/zip|application/x-rar|application/x-7z-compressed|\
|
||||
# application/x-xz|application/x-bzip2|application/x-gzip|application/x-tar)
|
||||
# local fn=""; local fe=""
|
||||
# local zip=""; local rar=""; local tar=""; local bsd=""
|
||||
# case "${mimetype}" in
|
||||
# application/zip) zip=1 ;;
|
||||
# application/x-rar) rar=1 ;;
|
||||
# application/x-7z-compressed) ;;
|
||||
# *) tar=1 ;;
|
||||
# esac
|
||||
# { [ "$tar" ] && fn=$(tar --list --file "${FPATH}"); } || \
|
||||
# { fn=$(bsdtar --list --file "${FPATH}") && bsd=1 && tar=""; } || \
|
||||
# { [ "$rar" ] && fn=$(unrar lb -p- -- "${FPATH}"); } || \
|
||||
# { [ "$zip" ] && fn=$(zipinfo -1 -- "${FPATH}"); } || return
|
||||
#
|
||||
# fn=$(echo "$fn" | python -c "import sys; import mimetypes as m; \
|
||||
# [ print(l, end='') for l in sys.stdin if \
|
||||
# (m.guess_type(l[:-1])[0] or '').startswith('image/') ]" |\
|
||||
# sort -V | head -n 1)
|
||||
# [ "$fn" = "" ] && return
|
||||
# [ "$bsd" ] && fn=$(printf '%b' "$fn")
|
||||
#
|
||||
# [ "$tar" ] && tar --extract --to-stdout \
|
||||
# --file "${FPATH}" -- "$fn" > "${IMAGE_CACHE_PATH}" && exit 6
|
||||
# fe=$(echo -n "$fn" | sed 's/[][*?\]/\\\0/g')
|
||||
# [ "$bsd" ] && bsdtar --extract --to-stdout \
|
||||
# --file "${FPATH}" -- "$fe" > "${IMAGE_CACHE_PATH}" && exit 6
|
||||
# [ "$bsd" ] || [ "$tar" ] && rm -- "${IMAGE_CACHE_PATH}"
|
||||
# [ "$rar" ] && unrar p -p- -inul -- "${FPATH}" "$fn" > \
|
||||
# "${IMAGE_CACHE_PATH}" && exit 6
|
||||
# [ "$zip" ] && unzip -pP "" -- "${FPATH}" "$fe" > \
|
||||
# "${IMAGE_CACHE_PATH}" && exit 6
|
||||
# [ "$rar" ] || [ "$zip" ] && rm -- "${IMAGE_CACHE_PATH}"
|
||||
# ;;
|
||||
esac
|
||||
}
|
||||
|
||||
handle_mime() {
|
||||
mimetype="${1}"
|
||||
case "${mimetype}" in
|
||||
## Manpages
|
||||
text/troff)
|
||||
man -l "${FPATH}"
|
||||
exit 0;;
|
||||
|
||||
## Text
|
||||
text/* | */xml)
|
||||
"$EDITOR" "${FPATH}"
|
||||
exit 0;;
|
||||
## Syntax highlight
|
||||
# if [[ "$( stat --printf='%s' -- "${FPATH}" )" -gt "${HIGHLIGHT_SIZE_MAX}" ]]; then
|
||||
# exit 2
|
||||
# fi
|
||||
# if [[ "$( tput colors )" -ge 256 ]]; then
|
||||
# local pygmentize_format='terminal256'
|
||||
# local highlight_format='xterm256'
|
||||
# else
|
||||
# local pygmentize_format='terminal'
|
||||
# local highlight_format='ansi'
|
||||
# fi
|
||||
# env HIGHLIGHT_OPTIONS="${HIGHLIGHT_OPTIONS}" highlight \
|
||||
# --out-format="${highlight_format}" \
|
||||
# --force -- "${FPATH}" && exit 5
|
||||
# pygmentize -f "${pygmentize_format}" -O "style=${PYGMENTIZE_STYLE}"\
|
||||
# -- "${FPATH}" && exit 5
|
||||
# exit 2;;
|
||||
|
||||
## DjVu
|
||||
image/vnd.djvu)
|
||||
if type djvutxt >/dev/null 2>&1; then
|
||||
## Preview as text conversion (requires djvulibre)
|
||||
djvutxt "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
elif type exiftool >/dev/null 2>&1; then
|
||||
exiftool "${FPATH}" | eval "$PAGER"
|
||||
exit 0
|
||||
fi
|
||||
exit 1;;
|
||||
esac
|
||||
}
|
||||
|
||||
handle_fallback() {
|
||||
if [ "$GUI" -ne 0 ]; then
|
||||
if type xdg-open >/dev/null 2>&1; then
|
||||
nohup xdg-open "${FPATH}" >/dev/null 2>&1 &
|
||||
exit 0
|
||||
elif type open >/dev/null 2>&1; then
|
||||
nohup open "${FPATH}" >/dev/null 2>&1 &
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
echo '----- File details -----' && file --dereference --brief -- "${FPATH}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
handle_blocked() {
|
||||
case "${MIMETYPE}" in
|
||||
application/x-sharedlib)
|
||||
exit 0;;
|
||||
|
||||
application/x-shared-library-la)
|
||||
exit 0;;
|
||||
|
||||
application/x-executable)
|
||||
exit 0;;
|
||||
|
||||
application/x-shellscript)
|
||||
exit 0;;
|
||||
|
||||
application/octet-stream)
|
||||
exit 0;;
|
||||
esac
|
||||
}
|
||||
|
||||
handle_bin() {
|
||||
case "${MIMETYPE}" in
|
||||
application/x-executable|application/x-shellscript)
|
||||
clear
|
||||
echo '-------- Executable File --------' && file --dereference --brief -- "${FPATH}"
|
||||
printf "Run executable (y/N/'a'rgs)? "
|
||||
read -r answer
|
||||
case "$answer" in
|
||||
[Yy]* ) exec "${FPATH}";;
|
||||
[Aa]* )
|
||||
printf "args: "
|
||||
read -r args
|
||||
exec "${FPATH}" "$args";;
|
||||
[Nn]* ) exit;;
|
||||
esac
|
||||
esac
|
||||
}
|
||||
|
||||
MIMETYPE="$( file -bL --mime-type -- "${FPATH}" )"
|
||||
handle_extension
|
||||
handle_multimedia "${MIMETYPE}"
|
||||
handle_mime "${MIMETYPE}"
|
||||
[ "$BIN" -ne 0 ] && [ -x "${FPATH}" ] && handle_bin
|
||||
handle_blocked "${MIMETYPE}"
|
||||
handle_fallback
|
||||
|
||||
exit 1
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: List files bigger than input size by ascending access date.
|
||||
#
|
||||
# Dependencies: find sort
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
printf "Min file size (MB): "
|
||||
read -r size
|
||||
|
||||
find . -size +"$size"M -type f -printf '%A+ %s %p\n' | sort
|
||||
|
||||
echo "Press any key to exit"
|
||||
read -r _
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Description: Open selected files in nuke one by one or in oneshot
|
||||
#
|
||||
# Notes: 1. Opens the hovered file if the selection is empty
|
||||
# 2. nuke is the default, set OPENER below for custom
|
||||
# 3. Opener is invoked once for each file in a loop
|
||||
# 4. Keep pressing "Enter" to open files one by one
|
||||
#
|
||||
# Shell: bash
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
sel=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
OPENER="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins/nuke"
|
||||
|
||||
if [ -s "$sel" ]; then
|
||||
targets=()
|
||||
while IFS= read -r -d '' entry || [ -n "$entry" ]; do
|
||||
targets+=( "$entry" )
|
||||
done < "$sel"
|
||||
|
||||
elements=${#targets[@]}
|
||||
|
||||
if (( elements == 1 )); then
|
||||
# If there's only one file selected, open without prompts
|
||||
"$OPENER" "${targets[0]}"
|
||||
else
|
||||
printf "open [A]ll? "
|
||||
read -r all
|
||||
|
||||
for ((index=0; index <= ${#targets[@]}; index++)); do
|
||||
"$OPENER" "${targets[index]}"
|
||||
if [ "$all" != "A" ] && (( index+1 < elements )); then
|
||||
printf "press Enter to open '%s'\n" "${targets[index+1]}"
|
||||
read -r -s -n 1 key
|
||||
if [[ $key != "" ]]; then
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Clear selection
|
||||
if [ -s "$sel" ] && [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
||||
elif [ -n "$1" ]; then
|
||||
"$OPENER" "$1"
|
||||
fi
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Organize files in directories by category
|
||||
#
|
||||
# Note: This plugin clears the selection as it changes the contents of the current dir
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: th3lusive
|
||||
|
||||
sel=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
|
||||
organize() {
|
||||
case "$(file -biL "$1")" in
|
||||
*video*)
|
||||
[ ! -d "Videos" ] && mkdir "Videos"
|
||||
mv "$1" "Videos/$1"
|
||||
printf "Moved %s to Videos\n" "$1" ;;
|
||||
|
||||
*audio*) [ ! -d "Audio" ] && mkdir "Audio"
|
||||
mv "$1" "Audio/$1"
|
||||
printf "Moved %s to Audio\n" "$1" ;;
|
||||
|
||||
*image*)
|
||||
[ ! -d "Images" ] && mkdir "Images"
|
||||
mv "$1" "Images/$1"
|
||||
printf "Moved %s to Images\n" "$1" ;;
|
||||
|
||||
*pdf*|*document*|*epub*|*djvu*|*cb*)
|
||||
[ ! -d "Documents" ] && mkdir "Documents"
|
||||
mv "$1" "Documents/$1"
|
||||
printf "Moved %s to Documents\n" "$1" ;;
|
||||
|
||||
*text*)
|
||||
[ ! -d "Plaintext" ] && mkdir "Plaintext"
|
||||
mv "$1" "Plaintext/$1"
|
||||
printf "Moved %s to Plaintext\n" "$1" ;;
|
||||
|
||||
*tar*|*xz*|*compress*|*7z*|*rar*|*zip*)
|
||||
[ ! -d "Archives" ] && mkdir "Archives"
|
||||
mv "$1" "Archives/$1"
|
||||
printf "Moved %s to Archives\n" "$1" ;;
|
||||
|
||||
*binary*)
|
||||
[ ! -d "Binaries" ] && mkdir "Binaries"
|
||||
mv "$1" "Binaries/$1"
|
||||
printf "Moved %s to Binaries\n" "$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main() {
|
||||
for file in *
|
||||
do
|
||||
[ -f "$file" ] && organize "$file"
|
||||
done
|
||||
|
||||
# Clear selection
|
||||
if [ -s "$sel" ] && [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Read a text or PDF file in British English
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
tmpf="$(basename "$1")"
|
||||
tmpf="${TMPDIR:-/tmp}"/"${tmpf%.*}"
|
||||
|
||||
if [ "$(head -c 4 "$1")" = "%PDF" ]; then
|
||||
# Convert using pdftotext
|
||||
pdftotext -nopgbrk -layout "$1" - | sed 's/\xe2\x80\x8b//g' > "$tmpf".txt
|
||||
|
||||
pico2wave -w "$tmpf".wav -l en-GB "$(tr '\n' ' ' < "$tmpf".txt)"
|
||||
|
||||
rm "$tmpf".txt
|
||||
else
|
||||
pico2wave -w "$tmpf".wav -l en-GB "$(tr '\n' ' ' < "$1")"
|
||||
fi
|
||||
|
||||
# to jump around and note the time
|
||||
mpv "$tmpf".wav
|
||||
|
||||
# flat read but better quality
|
||||
# play -qV0 "$tmpf".wav treble 2 gain -l 2
|
||||
|
||||
rm "$tmpf".wav
|
||||
fi
|
|
@ -0,0 +1,211 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Description: tabbed/xembed based file previewer
|
||||
#
|
||||
# Dependencies:
|
||||
# - tabbed (https://tools.suckless.org/tabbed): xembed host
|
||||
# - xterm (or urxvt or st) : xembed client for text-based preview
|
||||
# - mpv (https://mpv.io): xembed client for video/audio
|
||||
# - sxiv (https://github.com/muennich/sxiv) or,
|
||||
# - nsxiv (https://codeberg.org/nsxiv/nsxiv) : xembed client for images
|
||||
# - zathura (https://pwmt.org/projects/zathura): xembed client for PDF
|
||||
# - nnn's nuke plugin for text preview and fallback
|
||||
# nuke is a fallback for 'mpv', 'sxiv'/'nsxiv', and 'zathura', but has its
|
||||
# own dependencies, see the script for more information
|
||||
# - vim (or any editor/pager really)
|
||||
# - file
|
||||
# - mktemp
|
||||
# - xdotool (optional, to keep main window focused)
|
||||
#
|
||||
# Usage:
|
||||
# - Install the dependencies. Then set a NNN_FIFO
|
||||
# and set a key for the plugin, then start `nnn`:
|
||||
# $ NNN_FIFO=/tmp/nnn.fifo nnn
|
||||
# - Launch the plugin with the designated key from nnn
|
||||
#
|
||||
# Notes:
|
||||
# 1. This plugin needs a "NNN_FIFO" to work. See man.
|
||||
# 2. If the same NNN_FIFO is used in multiple nnn instances, there will be one
|
||||
# common preview window. With different FIFO paths, they will be independent.
|
||||
#
|
||||
# How it works:
|
||||
# We use `tabbed` [1] as a xembed [2] host, to have a single window
|
||||
# owning each previewer window. So each previewer must be a xembed client.
|
||||
# For text previewers, this is not an issue, as there are a lot of
|
||||
# xembed-able terminal emulator (we default to `xterm`, but examples are
|
||||
# provided for `urxvt` and `st`). For graphic preview this can be trickier,
|
||||
# but a few popular viewers are xembed-able, we use:
|
||||
# - `mpv`: multimedia player, for video/audio preview
|
||||
# - `sxiv`/`nsxiv`: image viewer
|
||||
# - `zathura`: PDF viewer
|
||||
# - but we always fallback to `nuke` plugin
|
||||
#
|
||||
# [1]: https://tools.suckless.org/tabbed/
|
||||
# [2]: https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html
|
||||
#
|
||||
# Shell: Bash (job control is weakly specified in POSIX)
|
||||
# Author: Léo Villeveygoux
|
||||
|
||||
|
||||
XDOTOOL_TIMEOUT=2
|
||||
PAGER=${PAGER:-"vim -R"}
|
||||
NUKE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins/nuke"
|
||||
|
||||
|
||||
if type xterm >/dev/null 2>&1 ; then
|
||||
TERMINAL="xterm -into"
|
||||
elif type urxvt >/dev/null 2>&1 ; then
|
||||
TERMINAL="urxvt -embed"
|
||||
elif type st >/dev/null 2>&1 ; then
|
||||
TERMINAL="st -w"
|
||||
else
|
||||
echo "No xembed term found" >&2
|
||||
fi
|
||||
|
||||
|
||||
term_nuke () {
|
||||
# $1 -> $XID, $2 -> $FILE
|
||||
$TERMINAL "$1" -e "$NUKE" "$2" &
|
||||
}
|
||||
|
||||
start_tabbed () {
|
||||
FIFO="$(mktemp -u)"
|
||||
mkfifo "$FIFO"
|
||||
|
||||
tabbed > "$FIFO" &
|
||||
|
||||
jobs # Get rid of the "Completed" entries
|
||||
|
||||
TABBEDPID="$(jobs -p %%)"
|
||||
|
||||
if [ -z "$TABBEDPID" ] ; then
|
||||
echo "Can't start tabbed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
read -r XID < "$FIFO"
|
||||
|
||||
rm "$FIFO"
|
||||
}
|
||||
|
||||
get_viewer_pid () {
|
||||
VIEWERPID="$(jobs -p %%)"
|
||||
}
|
||||
|
||||
kill_viewer () {
|
||||
if [ -n "$VIEWERPID" ] && jobs -p | grep "$VIEWERPID" ; then
|
||||
kill "$VIEWERPID"
|
||||
fi
|
||||
}
|
||||
|
||||
sigint_kill () {
|
||||
kill_viewer
|
||||
kill "$TABBEDPID"
|
||||
exit 0
|
||||
}
|
||||
|
||||
previewer_loop () {
|
||||
unset -v NNN_FIFO
|
||||
# mute from now
|
||||
exec >/dev/null 2>&1
|
||||
|
||||
MAINWINDOW="$(xdotool getactivewindow)"
|
||||
|
||||
start_tabbed
|
||||
trap sigint_kill SIGINT
|
||||
|
||||
xdotool windowactivate "$MAINWINDOW"
|
||||
|
||||
# Bruteforce focus stealing prevention method,
|
||||
# works well in floating window managers like XFCE
|
||||
# but make interaction with the preview window harder
|
||||
# (uncomment to use):
|
||||
#xdotool behave "$XID" focus windowactivate "$MAINWINDOW" &
|
||||
|
||||
while read -r FILE ; do
|
||||
|
||||
jobs # Get rid of the "Completed" entries
|
||||
|
||||
if ! jobs | grep tabbed ; then
|
||||
break
|
||||
fi
|
||||
|
||||
if [ ! -e "$FILE" ] ; then
|
||||
continue
|
||||
fi
|
||||
|
||||
kill_viewer
|
||||
|
||||
MIME="$(file -bL --mime-type "$FILE")"
|
||||
|
||||
case "$MIME" in
|
||||
video/*)
|
||||
if type mpv >/dev/null 2>&1 ; then
|
||||
mpv --force-window=immediate --loop-file --wid="$XID" "$FILE" &
|
||||
else
|
||||
term_nuke "$XID" "$FILE"
|
||||
fi
|
||||
;;
|
||||
audio/*)
|
||||
if type mpv >/dev/null 2>&1 ; then
|
||||
mpv --force-window=immediate --loop-file --wid="$XID" "$FILE" &
|
||||
else
|
||||
term_nuke "$XID" "$FILE"
|
||||
fi
|
||||
;;
|
||||
image/*)
|
||||
if type sxiv >/dev/null 2>&1 ; then
|
||||
sxiv -ae "$XID" "$FILE" &
|
||||
elif type nsxiv >/dev/null 2>&1 ; then
|
||||
nsxiv -ae "$XID" "$FILE" &
|
||||
else
|
||||
term_nuke "$XID" "$FILE"
|
||||
fi
|
||||
;;
|
||||
application/pdf)
|
||||
if type zathura >/dev/null 2>&1 ; then
|
||||
zathura -e "$XID" "$FILE" &
|
||||
else
|
||||
term_nuke "$XID" "$FILE"
|
||||
fi
|
||||
;;
|
||||
inode/directory)
|
||||
$TERMINAL "$XID" -e nnn "$FILE" &
|
||||
;;
|
||||
text/*)
|
||||
if [ -x "$NUKE" ] ; then
|
||||
term_nuke "$XID" "$FILE"
|
||||
else
|
||||
# shellcheck disable=SC2086
|
||||
$TERMINAL "$XID" -e $PAGER "$FILE" &
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if [ -x "$NUKE" ] ; then
|
||||
term_nuke "$XID" "$FILE"
|
||||
else
|
||||
$TERMINAL "$XID" -e sh -c "file '$FILE' | $PAGER -" &
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
get_viewer_pid
|
||||
|
||||
# following lines are not needed with the bruteforce xdotool method
|
||||
ACTIVE_XID="$(xdotool getactivewindow)"
|
||||
if [ $((ACTIVE_XID == XID)) -ne 0 ] ; then
|
||||
xdotool windowactivate "$MAINWINDOW"
|
||||
else
|
||||
timeout "$XDOTOOL_TIMEOUT" xdotool behave "$XID" focus windowactivate "$MAINWINDOW" &
|
||||
fi
|
||||
done
|
||||
kill "$TABBEDPID"
|
||||
kill_viewer
|
||||
}
|
||||
|
||||
if [ ! -r "$NNN_FIFO" ] ; then
|
||||
echo "Can't read \$NNN_FIFO ('$NNN_FIFO')"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
previewer_loop < "$NNN_FIFO" &
|
||||
disown
|
|
@ -0,0 +1,481 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Terminal based file previewer
|
||||
#
|
||||
# Note: This plugin needs a "NNN_FIFO" to work. See man.
|
||||
#
|
||||
# Dependencies:
|
||||
# - Supports 5 independent methods to preview with:
|
||||
# - tmux (>=3.0), or
|
||||
# - kitty with allow_remote_control and listen_on set in kitty.conf, or
|
||||
# - QuickLook on WSL (https://github.com/QL-Win/QuickLook), or
|
||||
# - Windows Terminal (https://github.com/Microsoft/Terminal | https://aka.ms/terminal) with WSL, or
|
||||
# - $TERMINAL set to a terminal (it's xterm by default).
|
||||
# - less or $PAGER
|
||||
# - tree or exa or ls
|
||||
# - mediainfo or file
|
||||
# - mktemp
|
||||
# - unzip
|
||||
# - tar
|
||||
# - man
|
||||
# - optional: bsdtar or atool for additional archive preview
|
||||
# - optional: bat for code syntax highlighting
|
||||
# - optional: ueberzug, kitty terminal, viu or catimg for images
|
||||
# - optional: convert(ImageMagick) for playing gif preview (required for kitty image previews)
|
||||
# - optional: ffmpegthumbnailer for video thumbnails (https://github.com/dirkvdb/ffmpegthumbnailer)
|
||||
# - optional: ffmpeg for audio thumbnails
|
||||
# - optional: libreoffce for opendocument/officedocument preview
|
||||
# - optional: pdftoppm(poppler) for pdf thumbnails
|
||||
# - optional: gnome-epub-thumbnailer for epub thumbnails (https://gitlab.gnome.org/GNOME/gnome-epub-thumbnailer)
|
||||
# - optional: fontpreview for font preview (https://github.com/sdushantha/fontpreview)
|
||||
# - optional: djvulibre for djvu
|
||||
# - optional: glow or lowdown for markdown
|
||||
# - optional: w3m or lynx or elinks for html
|
||||
# - optional: set/export ICONLOOKUP as 1 to enable file icons in front of directory previews with .iconlookup
|
||||
# Icons and colors are configureable in .iconlookup
|
||||
# - optional: scope.sh file viewer from ranger.
|
||||
# 1. drop scope.sh executable in $PATH
|
||||
# 2. set/export $USE_SCOPE as 1
|
||||
# - optional: pistol file viewer (https://github.com/doronbehar/pistol).
|
||||
# 1. install pistol
|
||||
# 2. set/export $USE_PISTOL as 1
|
||||
#
|
||||
# Usage:
|
||||
# You need to set a NNN_FIFO path and a key for the plugin with NNN_PLUG,
|
||||
# then start `nnn`:
|
||||
#
|
||||
# $ nnn -a
|
||||
#
|
||||
# or
|
||||
#
|
||||
# $ NNN_FIFO=/tmp/nnn.fifo nnn
|
||||
#
|
||||
# Then launch the `preview-tui` plugin in `nnn`.
|
||||
#
|
||||
# If you provide the same NNN_FIFO to all nnn instances, there will be a
|
||||
# single common preview window. If you provide different FIFO path (e.g.
|
||||
# with -a), they will be independent.
|
||||
#
|
||||
# The previews will be shown in a tmux split. If that isn't possible, it
|
||||
# will try to use a kitty terminal split. And as a final fallback, a
|
||||
# different terminal window will be used ($TERMINAL).
|
||||
#
|
||||
# Tmux and kitty users can configure $SPLIT to either "h" or "v" to set a
|
||||
# 'h'orizontal split or a 'v'ertical split (as in, the line that splits the
|
||||
# windows will be horizontal or vertical).
|
||||
#
|
||||
# Kitty users need something similar to the following in their kitty.conf:
|
||||
# - `allow_remote_control yes`
|
||||
# - `listen_on unix:$TMPDIR/kitty`
|
||||
# - `enabled_layouts splits` (optional)
|
||||
# With ImageMagick installed, this terminal can use the icat kitten to display images.
|
||||
# Refer to kitty documentation for further details.
|
||||
#
|
||||
# Iterm2 users are recommended to use viu to view images without getting pixelated.
|
||||
#
|
||||
# Windows Terminal users can set "Profile termination behavior" under "Profile > Advanced" settings
|
||||
# to automaticaly close pane on quit when exit code is 0.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Authors: Todd Yamakawa, Léo Villeveygoux, @Recidiviste, Mario Ortiz Manero, Luuk van Baal, @WanderLanz
|
||||
|
||||
#SPLIT="$SPLIT" # you can set a permanent split here
|
||||
#TERMINAL="$TERMINAL" # same goes for the terminal
|
||||
SPLIT_SIZE="${SPLIT_SIZE:-50}" # split size in percentage for supported previewers
|
||||
USE_SCOPE="${USE_SCOPE:-0}"
|
||||
USE_PISTOL="${USE_PISTOL:-0}"
|
||||
ICONLOOKUP="${ICONLOOKUP:-0}"
|
||||
PAGER="${PAGER:-less -P?n -R}"
|
||||
TMPDIR="${TMPDIR:-/tmp}"
|
||||
BAT_STYLE="${BAT_STYLE:-numbers}"
|
||||
BAT_THEME="${BAT_THEME:-ansi}"
|
||||
# Consider setting NNN_PREVIEWDIR to $XDG_CACHE_HOME/nnn/previews if you want to keep previews on disk between reboots
|
||||
NNN_PREVIEWDIR="${NNN_PREVIEWDIR:-$TMPDIR/nnn/previews}"
|
||||
NNN_PREVIEWWIDTH="${NNN_PREVIEWWIDTH:-1920}"
|
||||
NNN_PREVIEWHEIGHT="${NNN_PREVIEWHEIGHT:-1080}"
|
||||
NNN_PARENT="${NNN_FIFO#*.}"
|
||||
[ "$NNN_PARENT" -eq "$NNN_PARENT" ] 2>/dev/null || NNN_PARENT=""
|
||||
FIFOPID="$TMPDIR/nnn-preview-tui-fifopid.$NNN_PARENT"
|
||||
PREVIEWPID="$TMPDIR/nnn-preview-tui-pagerpid.$NNN_PARENT"
|
||||
CURSEL="$TMPDIR/nnn-preview-tui-selection.$NNN_PARENT"
|
||||
FIFO_UEBERZUG="$TMPDIR/nnn-preview-tui-ueberzug-fifo.$NNN_PARENT"
|
||||
POSOFFSET="$TMPDIR/nnn-preview-tui-posoffset"
|
||||
|
||||
exists() { type "$1" >/dev/null 2>&1 ;}
|
||||
pkill() { command pkill "$@" >/dev/null 2>&1 ;}
|
||||
pidkill() { [ -f "$1" ] && kill "$(cat "$1")" >/dev/null 2>&1 ;}
|
||||
prompt() { printf "%b" "$@"; cfg=$(stty -g); stty raw -echo; head -c 1; stty "$cfg" ;}
|
||||
|
||||
start_preview() {
|
||||
[ "$PAGER" = "most" ] && PAGER="less -R"
|
||||
|
||||
if [ -e "${TMUX%%,*}" ] && tmux -V | grep -q '[ -][3456789]\.'; then
|
||||
TERMINAL=tmux
|
||||
elif [ -n "$KITTY_LISTEN_ON" ]; then
|
||||
TERMINAL=kitty
|
||||
elif [ -z "$TERMINAL" ] && [ "$TERM_PROGRAM" = "iTerm.app" ]; then
|
||||
TERMINAL=iterm
|
||||
elif [ -n "$WT_SESSION" ]; then
|
||||
TERMINAL=winterm
|
||||
else
|
||||
TERMINAL="${TERMINAL:-xterm}"
|
||||
fi
|
||||
|
||||
if [ -z "$SPLIT" ] && [ $(($(tput lines) * 2)) -gt "$(tput cols)" ]; then
|
||||
SPLIT='h'
|
||||
elif [ "$SPLIT" != 'h' ]; then
|
||||
SPLIT='v'
|
||||
fi
|
||||
|
||||
case "$TERMINAL" in
|
||||
tmux) # tmux splits are inverted
|
||||
if [ "$SPLIT" = "v" ]; then DSPLIT="h"; else DSPLIT="v"; fi
|
||||
tmux split-window -e "NNN_FIFO=$NNN_FIFO" -e "PREVIEW_MODE=1" -e "CURSEL=$CURSEL" \
|
||||
-e "TMPDIR=$TMPDIR" -e "FIFOPID=$FIFOPID" -e "POSOFFSET=$POSOFFSET" \
|
||||
-e "BAT_STYLE=$BAT_STYLE" -e "BAT_THEME=$BAT_THEME" -e "PREVIEWPID=$PREVIEWPID" \
|
||||
-e "PAGER=$PAGER" -e "ICONLOOKUP=$ICONLOOKUP" -e "NNN_PREVIEWWIDTH=$NNN_PREVIEWWIDTH" \
|
||||
-e "USE_SCOPE=$USE_SCOPE" -e "SPLIT=$SPLIT" -e "USE_PISTOL=$USE_PISTOL" \
|
||||
-e "NNN_PREVIEWDIR=$NNN_PREVIEWDIR" -e "NNN_PREVIEWHEIGHT=$NNN_PREVIEWHEIGHT" \
|
||||
-e "FIFO_UEBERZUG=$FIFO_UEBERZUG" -e "QLPATH=$2" -d"$DSPLIT" -p"$SPLIT_SIZE" "$0" "$1" ;;
|
||||
kitty) # Setting the layout for the new window. It will be restored after the script ends.
|
||||
kitty @ goto-layout splits
|
||||
# Trying to use kitty's integrated window management as the split window. All
|
||||
# environmental variables that will be used in the new window must be explicitly passed.
|
||||
kitty @ launch --no-response --title "nnn preview" --keep-focus \
|
||||
--cwd "$PWD" --env "PATH=$PATH" --env "NNN_FIFO=$NNN_FIFO" \
|
||||
--env "PREVIEW_MODE=1" --env "PAGER=$PAGER" --env "TMPDIR=$TMPDIR" \
|
||||
--env "USE_SCOPE=$USE_SCOPE" --env "SPLIT=$SPLIT" --env "TERMINAL=$TERMINAL"\
|
||||
--env "PREVIEWPID=$PREVIEWPID" --env "FIFO_UEBERZUG=$FIFO_UEBERZUG" \
|
||||
--env "ICONLOOKUP=$ICONLOOKUP" --env "NNN_PREVIEWHEIGHT=$NNN_PREVIEWHEIGHT" \
|
||||
--env "NNN_PREVIEWWIDTH=$NNN_PREVIEWWIDTH" --env "NNN_PREVIEWDIR=$NNN_PREVIEWDIR" \
|
||||
--env "USE_PISTOL=$USE_PISTOL" --env "BAT_STYLE=$BAT_STYLE" \
|
||||
--env "BAT_THEME=$BAT_THEME" --env "FIFOPID=$FIFOPID" \
|
||||
--env "CURSEL=$CURSEL" --location "${SPLIT}split" "$0" "$1" ;;
|
||||
iterm)
|
||||
command="$SHELL -c 'cd $PWD; \
|
||||
PATH=\\\"$PATH\\\" NNN_FIFO=\\\"$NNN_FIFO\\\" PREVIEW_MODE=1 PAGER=\\\"$PAGER\\\" \
|
||||
USE_SCOPE=\\\"$USE_SCOPE\\\" SPLIT=\\\"$SPLIT\\\" TERMINAL=\\\"$TERMINAL\\\" \
|
||||
PREVIEWPID=\\\"$PREVIEWPID\\\" CURSEL=\\\"$CURSEL\\\" TMPDIR=\\\"$TMPDIR\\\" \
|
||||
ICONLOOKUP=\\\"$ICONLOOKUP\\\" NNN_PREVIEWHEIGHT=\\\"$NNN_PREVIEWHEIGHT\\\" \
|
||||
NNN_PREVIEWWIDTH=\\\"$NNN_PREVIEWWIDTH\\\" NNN_PREVIEWDIR=\\\"$NNN_PREVIEWDIR\\\" \
|
||||
USE_PISTOL=\\\"$USE_PISTOL\\\" BAT_STYLE=\\\"$BAT_STYLE\\\" \
|
||||
BAT_THEME=\\\"$BAT_THEME\\\" FIFOPID=\\\"$FIFOPID\\\" \\\"$0\\\" \\\"$1\\\"'"
|
||||
if [ "$SPLIT" = "h" ]; then split="horizontally"; else split="vertically"; fi
|
||||
osascript <<-EOF
|
||||
tell application "iTerm"
|
||||
tell current session of current window
|
||||
split $split with default profile command "$command"
|
||||
end tell
|
||||
end tell
|
||||
EOF
|
||||
;;
|
||||
winterm)
|
||||
if [ "$SPLIT" = "h" ]; then split="H"; else split="V"; fi
|
||||
cmd.exe /c wt -w 0 sp -$split -s$((SPLIT_SIZE / 100)) bash -c "cd $PWD \; \
|
||||
PATH='$PATH' NNN_FIFO=$NNN_FIFO PREVIEW_MODE=1 CURSEL=$CURSEL TMPDIR=$TMPDIR \
|
||||
FIFOPID=$FIFOPID BAT_STYLE=$BAT_STYLE BAT_THEME=$BAT_THEME PREVIEWPID=$PREVIEWPID \
|
||||
PAGER='$PAGER' ICONLOOKUP=$ICONLOOKUP NNN_PREVIEWWIDTH=$NNN_PREVIEWWIDTH \
|
||||
USE_SCOPE=$USE_SCOPE SPLIT=$SPLIT USE_PISTOL=$USE_PISTOL \
|
||||
NNN_PREVIEWDIR=$NNN_PREVIEWDIR NNN_PREVIEWHEIGHT=$NNN_PREVIEWHEIGHT \
|
||||
FIFO_UEBERZUG=$FIFO_UEBERZUG QLPATH=$2 $0 $1" \; -w 0 mf previous
|
||||
;;
|
||||
*) if [ -n "$2" ]; then
|
||||
QUICKLOOK=1 QLPATH="$2" PREVIEW_MODE=1 "$0" "$1" &
|
||||
else
|
||||
PREVIEWPID="$PREVIEWPID" CURSEL="$CURSEL" PREVIEW_MODE=1 \
|
||||
FIFOPID="$FIFOPID" FIFO_UEBERZUG="$FIFO_UEBERZUG" $TERMINAL -e "$0" "$1" &
|
||||
fi ;;
|
||||
esac
|
||||
}
|
||||
|
||||
toggle_preview() {
|
||||
if exists QuickLook.exe; then
|
||||
QLPATH="QuickLook.exe"
|
||||
elif exists Bridge.exe; then
|
||||
QLPATH="Bridge.exe"
|
||||
fi
|
||||
if pidkill "$FIFOPID"; then
|
||||
[ -p "$NNN_PPIPE" ] && printf "0" > "$NNN_PPIPE"
|
||||
pidkill "$PREVIEWPID"
|
||||
pkill -f "tail --follow $FIFO_UEBERZUG"
|
||||
if [ -n "$QLPATH" ] && stat "$1"; then
|
||||
f="$(wslpath -w "$1")" && "$QLPATH" "$f" &
|
||||
fi
|
||||
else
|
||||
[ -p "$NNN_PPIPE" ] && printf "1" > "$NNN_PPIPE"
|
||||
start_preview "$1" "$QLPATH"
|
||||
fi
|
||||
}
|
||||
|
||||
fifo_pager() {
|
||||
cmd="$1"
|
||||
shift
|
||||
|
||||
# We use a FIFO to access $PAGER PID in jobs control
|
||||
tmpfifopath="$TMPDIR/nnn-preview-tui-fifo.$$"
|
||||
mkfifo "$tmpfifopath" || return
|
||||
|
||||
$PAGER < "$tmpfifopath" &
|
||||
printf "%s" "$!" > "$PREVIEWPID"
|
||||
|
||||
(
|
||||
exec > "$tmpfifopath"
|
||||
if [ "$cmd" = "pager" ]; then
|
||||
if exists bat; then
|
||||
bat --terminal-width="$cols" --decorations=always --color=always \
|
||||
--paging=never --style="$BAT_STYLE" --theme="$BAT_THEME" "$@" &
|
||||
else
|
||||
$PAGER "$@" &
|
||||
fi
|
||||
else
|
||||
"$cmd" "$@" &
|
||||
fi
|
||||
)
|
||||
|
||||
rm "$tmpfifopath"
|
||||
}
|
||||
|
||||
# Binary file: show file info inside the pager
|
||||
print_bin_info() {
|
||||
printf -- "-------- \033[1;31mBinary file\033[0m --------\n"
|
||||
if exists mediainfo; then
|
||||
mediainfo "$1"
|
||||
else
|
||||
file -b "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
handle_mime() {
|
||||
case "$2" in
|
||||
image/jpeg) image_preview "$cols" "$lines" "$1" ;;
|
||||
image/gif) generate_preview "$cols" "$lines" "$1" "gif" ;;
|
||||
image/vnd.djvu) generate_preview "$cols" "$lines" "$1" "djvu" ;;
|
||||
image/*) generate_preview "$cols" "$lines" "$1" "image" ;;
|
||||
video/*) generate_preview "$cols" "$lines" "$1" "video" ;;
|
||||
audio/*) generate_preview "$cols" "$lines" "$1" "audio" ;;
|
||||
application/font*|application/*opentype|font/*) generate_preview "$cols" "$lines" "$1" "font" ;;
|
||||
*/*office*|*/*document*) generate_preview "$cols" "$lines" "$1" "office" ;;
|
||||
application/zip) fifo_pager unzip -l "$1" ;;
|
||||
text/troff)
|
||||
if exists man; then
|
||||
fifo_pager man -Pcat -l "$1"
|
||||
else
|
||||
fifo_pager pager "$1"
|
||||
fi ;;
|
||||
*) handle_ext "$1" "$3" "$4" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
handle_ext() {
|
||||
case "$2" in
|
||||
epub) generate_preview "$cols" "$lines" "$1" "epub" ;;
|
||||
pdf) generate_preview "$cols" "$lines" "$1" "pdf" ;;
|
||||
gz|bz2) fifo_pager tar -tvf "$1" ;;
|
||||
md) if exists glow; then
|
||||
fifo_pager glow -s dark "$1"
|
||||
elif exists lowdown; then
|
||||
fifo_pager lowdown -Tterm "$1"
|
||||
else
|
||||
fifo_pager pager "$1"
|
||||
fi ;;
|
||||
htm|html|xhtml)
|
||||
if exists w3m; then
|
||||
fifo_pager w3m "$1"
|
||||
elif exists lynx; then
|
||||
fifo_pager lynx "$1"
|
||||
elif exists elinks; then
|
||||
fifo_pager elinks "$1"
|
||||
else
|
||||
fifo_pager pager "$1"
|
||||
fi ;;
|
||||
7z|a|ace|alz|arc|arj|bz|cab|cpio|deb|jar|lha|lz|lzh|lzma|lzo\
|
||||
|rar|rpm|rz|t7z|tar|tbz|tbz2|tgz|tlz|txz|tZ|tzo|war|xpi|xz|Z)
|
||||
if exists atool; then
|
||||
fifo_pager atool -l "$1"
|
||||
elif exists bsdtar; then
|
||||
fifo_pager bsdtar -tvf "$1"
|
||||
fi ;;
|
||||
*) if [ "$3" = "bin" ]; then
|
||||
fifo_pager print_bin_info "$1"
|
||||
else
|
||||
fifo_pager pager "$1"
|
||||
fi ;;
|
||||
esac
|
||||
}
|
||||
|
||||
preview_file() {
|
||||
clear
|
||||
# Trying to use pistol if it's available.
|
||||
if [ "$USE_PISTOL" -ne 0 ] && exists pistol; then
|
||||
fifo_pager pistol "$1"
|
||||
return
|
||||
fi
|
||||
|
||||
# Trying to use scope.sh if it's available.
|
||||
if [ "$USE_SCOPE" -ne 0 ] && exists scope.sh; then
|
||||
fifo_pager scope.sh "$1" "$cols" "$lines" "$(mktemp -d)" "True"
|
||||
return
|
||||
fi
|
||||
|
||||
# Use QuickLook if it's available.
|
||||
if [ -n "$QUICKLOOK" ]; then
|
||||
stat "$1" && f="$(wslpath -w "$1")" && "$QLPATH" "$f" &
|
||||
return
|
||||
fi
|
||||
|
||||
# Detecting the exact type of the file: the encoding, mime type, and extension in lowercase.
|
||||
encoding="$(file -bL --mime-encoding -- "$1")"
|
||||
mimetype="$(file -bL --mime-type -- "$1")"
|
||||
ext="${1##*.}"
|
||||
[ -n "$ext" ] && ext="$(printf "%s" "${ext}" | tr '[:upper:]' '[:lower:]')"
|
||||
lines=$(tput lines)
|
||||
cols=$(tput cols)
|
||||
|
||||
# Otherwise, falling back to the defaults.
|
||||
if [ -d "$1" ]; then
|
||||
cd "$1" || return
|
||||
if [ "$ICONLOOKUP" -ne 0 ] && [ -f "$(dirname "$0")"/.iconlookup ]; then
|
||||
[ "$SPLIT" = v ] && BSTR="\n"
|
||||
# shellcheck disable=SC2012
|
||||
ls -F --group-directories-first | head -n "$((lines - 3))" | "$(dirname "$0")"/.iconlookup -l "$cols" -B "$BSTR" -b " "
|
||||
elif exists tree; then
|
||||
fifo_pager tree --filelimit "$(find . -maxdepth 1 | wc -l)" -L 3 -C -F --dirsfirst --noreport
|
||||
elif exists exa; then
|
||||
exa -G --group-directories-first --colour=always
|
||||
else
|
||||
fifo_pager ls -F --group-directories-first --color=always
|
||||
fi
|
||||
elif [ "${encoding#*)}" = "binary" ]; then
|
||||
handle_mime "$1" "$mimetype" "$ext" "bin"
|
||||
else
|
||||
handle_mime "$1" "$mimetype" "$ext"
|
||||
fi
|
||||
}
|
||||
|
||||
generate_preview() {
|
||||
if [ -n "$QLPATH" ] && stat "$3"; then
|
||||
f="$(wslpath -w "$3")" && "$QLPATH" "$f" &
|
||||
elif [ ! -f "$NNN_PREVIEWDIR/$3.jpg" ] || [ -n "$(find -L "$3" -newer "$NNN_PREVIEWDIR/$3.jpg")" ]; then
|
||||
mkdir -p "$NNN_PREVIEWDIR/${3%/*}"
|
||||
case $4 in
|
||||
audio) ffmpeg -i "$3" -filter_complex "scale=iw*min(1\,min($NNN_PREVIEWWIDTH/iw\,ih)):-1" "$NNN_PREVIEWDIR/$3.jpg" -y ;;
|
||||
epub) gnome-epub-thumbnailer "$3" "$NNN_PREVIEWDIR/$3.jpg" ;;
|
||||
font) fontpreview -i "$3" -o "$NNN_PREVIEWDIR/$3.jpg" ;;
|
||||
gif) if [ -p "$FIFO_UEBERZUG" ] && exists convert; then
|
||||
frameprefix="$NNN_PREVIEWDIR/$3/${3##*/}"
|
||||
if [ ! -d "$NNN_PREVIEWDIR/$3" ]; then
|
||||
mkdir -p "$NNN_PREVIEWDIR/$3"
|
||||
convert -coalesce -resize "$NNN_PREVIEWWIDTH"x"$NNN_PREVIEWHEIGHT"\> "$3" "$frameprefix.jpg" ||
|
||||
MAGICK_TMPDIR="/tmp" convert -coalesce -resize "$NNN_PREVIEWWIDTH"x"$NNN_PREVIEWHEIGHT"\> "$3" "$frameprefix.jpg"
|
||||
fi
|
||||
frames=$(($(find "$NNN_PREVIEWDIR/$3" | wc -l) - 2))
|
||||
[ $frames -lt 0 ] && return
|
||||
while true; do
|
||||
for i in $(seq 0 $frames); do
|
||||
image_preview "$1" "$2" "$frameprefix-$i.jpg"
|
||||
sleep 0.1
|
||||
done
|
||||
done &
|
||||
printf "%s" "$!" > "$PREVIEWPID"
|
||||
return
|
||||
else
|
||||
image_preview "$1" "$2" "$3"
|
||||
return
|
||||
fi ;;
|
||||
image) if exists convert; then
|
||||
convert "$3" -flatten -resize "$NNN_PREVIEWWIDTH"x"$NNN_PREVIEWHEIGHT"\> "$NNN_PREVIEWDIR/$3.jpg"
|
||||
else
|
||||
image_preview "$1" "$2" "$3" && return
|
||||
fi ;;
|
||||
office) libreoffice --convert-to jpg "$3" --outdir "$NNN_PREVIEWDIR/${3%/*}"
|
||||
filename="$(printf "%s" "${3##*/}" | cut -d. -f1)"
|
||||
mv "$NNN_PREVIEWDIR/${3%/*}/$filename.jpg" "$NNN_PREVIEWDIR/$3.jpg" ;;
|
||||
pdf) pdftoppm -jpeg -f 1 -singlefile "$3" "$NNN_PREVIEWDIR/$3" ;;
|
||||
djvu) ddjvu -format=ppm -page=1 "$3" "$NNN_PREVIEWDIR/$3.jpg" ;;
|
||||
video) ffmpegthumbnailer -m -s0 -i "$3" -o "$NNN_PREVIEWDIR/$3.jpg" || rm "$NNN_PREVIEWDIR/$3.jpg" ;;
|
||||
esac
|
||||
fi
|
||||
if [ -f "$NNN_PREVIEWDIR/$3.jpg" ]; then
|
||||
image_preview "$1" "$2" "$NNN_PREVIEWDIR/$3.jpg"
|
||||
else
|
||||
fifo_pager print_bin_info "$3"
|
||||
fi
|
||||
} >/dev/null 2>&1
|
||||
|
||||
image_preview() {
|
||||
clear
|
||||
exec >/dev/tty
|
||||
if [ "$TERMINAL" = "kitty" ]; then
|
||||
# Kitty terminal users can use the native image preview method
|
||||
kitty +kitten icat --silent --scale-up --place "$1"x"$2"@0x0 --transfer-mode=stream --stdin=no "$3" &
|
||||
elif exists ueberzug; then
|
||||
ueberzug_layer "$1" "$2" "$3" && return
|
||||
elif exists catimg; then
|
||||
catimg "$3" &
|
||||
elif exists viu; then
|
||||
viu -t "$3" &
|
||||
else
|
||||
fifo_pager print_bin_info "$3" && return
|
||||
fi
|
||||
printf "%s" "$!" > "$PREVIEWPID"
|
||||
}
|
||||
|
||||
ueberzug_layer() {
|
||||
[ -f "$POSOFFSET" ] && read -r x y < "$POSOFFSET"
|
||||
printf '{"action": "add", "identifier": "nnn_ueberzug", "x": %d, "y": %d, "width": "%d", "height": "%d", "scaler": "fit_contain", "path": "%s"}\n'\
|
||||
"${x:-0}" "${y:-0}" "$1" "$2" "$3" > "$FIFO_UEBERZUG"
|
||||
}
|
||||
|
||||
ueberzug_remove() {
|
||||
printf '{"action": "remove", "identifier": "nnn_ueberzug"}\n' > "$FIFO_UEBERZUG"
|
||||
}
|
||||
|
||||
winch_handler() {
|
||||
clear
|
||||
pidkill "$PREVIEWPID"
|
||||
if [ -p "$FIFO_UEBERZUG" ]; then
|
||||
pkill -f "tail --follow $FIFO_UEBERZUG"
|
||||
tail --follow "$FIFO_UEBERZUG" | ueberzug layer --silent --parser json &
|
||||
fi
|
||||
preview_file "$(cat "$CURSEL")"
|
||||
}
|
||||
|
||||
preview_fifo() {
|
||||
while read -r selection; do
|
||||
if [ -n "$selection" ]; then
|
||||
pidkill "$PREVIEWPID"
|
||||
[ -p "$FIFO_UEBERZUG" ] && ueberzug_remove
|
||||
[ "$selection" = "close" ] && break
|
||||
preview_file "$selection"
|
||||
printf "%s" "$selection" > "$CURSEL"
|
||||
fi
|
||||
done < "$NNN_FIFO"
|
||||
sleep 0.1 # make sure potential preview by winch_handler is killed
|
||||
pkill -P "$$"
|
||||
}
|
||||
|
||||
if [ "$PREVIEW_MODE" ]; then
|
||||
if [ "$TERMINAL" != "kitty" ] && exists ueberzug; then
|
||||
mkfifo "$FIFO_UEBERZUG"
|
||||
tail --follow "$FIFO_UEBERZUG" | ueberzug layer --silent --parser json &
|
||||
fi
|
||||
|
||||
preview_file "$PWD/$1"
|
||||
preview_fifo &
|
||||
printf "%s" "$!" > "$FIFOPID"
|
||||
printf "%s" "$PWD/$1" > "$CURSEL"
|
||||
trap 'winch_handler; wait' WINCH
|
||||
trap 'rm "$PREVIEWPID" "$CURSEL" "$FIFO_UEBERZUG" "$FIFOPID" "$POSOFFSET" 2>/dev/null' INT HUP EXIT
|
||||
wait "$!" 2>/dev/null
|
||||
exit 0
|
||||
else
|
||||
if [ ! -r "$NNN_FIFO" ]; then
|
||||
clear
|
||||
prompt "No FIFO available! (\$NNN_FIFO='$NNN_FIFO')\nPlease read Usage in preview-tui."
|
||||
elif [ "$KITTY_WINDOW_ID" ] && [ -z "$TMUX" ] && [ -z "$KITTY_LISTEN_ON" ]; then
|
||||
clear
|
||||
prompt "\$KITTY_LISTEN_ON not set!\nPlease read Usage in preview-tui."
|
||||
else
|
||||
toggle_preview "$1" &
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Fuzzy list and kill a (zombie) process by name
|
||||
#
|
||||
# Dependencies: fzf, ps
|
||||
#
|
||||
# Note: To kill a zombie process enter "zombie"
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
printf "Enter process name ['defunct' for zombies]: "
|
||||
read -r psname
|
||||
|
||||
# shellcheck disable=SC2009
|
||||
if [ -n "$psname" ]; then
|
||||
if type sudo >/dev/null 2>&1; then
|
||||
sucmd=sudo
|
||||
elif type doas >/dev/null 2>&1; then
|
||||
sucmd=doas
|
||||
else
|
||||
sucmd=: # noop
|
||||
fi
|
||||
|
||||
if type fzf >/dev/null 2>&1; then
|
||||
fuzzy=fzf
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cmd="$(ps -ax | grep -iw "$psname" | "$fuzzy" | sed -e 's/^[ \t]*//' | cut -d' ' -f1)"
|
||||
if [ -n "$cmd" ]; then
|
||||
$sucmd kill -9 "$cmd"
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Batch rename selection or current directory with qmv or vidir
|
||||
#
|
||||
# Notes:
|
||||
# - Try to mimic current batch rename functionality but with correct
|
||||
# handling of edge cases by qmv or vidir.
|
||||
# - Qmv opens with hidden files if no selection is used. Selected
|
||||
# directories are shown.
|
||||
# - Vidir don't show directories nor hidden files.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: José Neder
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
|
||||
if type qmv >/dev/null 2>&1; then
|
||||
batchrenamesel="qmv -fdo -da"
|
||||
batchrename="qmv -fdo -a"
|
||||
elif type vidir >/dev/null 2>&1; then
|
||||
batchrenamesel="vidir"
|
||||
batchrename="vidir"
|
||||
else
|
||||
printf "there is not batchrename program installed."
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -s "$selection" ]; then
|
||||
printf "rename selection? "
|
||||
read -r resp
|
||||
fi
|
||||
|
||||
if [ "$resp" = "y" ]; then
|
||||
# -o flag is necessary for interactive editors
|
||||
xargs -o -0 $batchrenamesel < "$selection"
|
||||
|
||||
# Clear selection
|
||||
if [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
||||
elif [ ! "$(LC_ALL=C ls -a)" = ".
|
||||
.." ]; then
|
||||
# On older systems that don't have ls -A
|
||||
$batchrename
|
||||
fi
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Create an mp3 ringtone out of an audio file in any format
|
||||
# Needs user to provide start and end where to cut the file
|
||||
# Input file audio.ext results in audio_ringtone.mp3
|
||||
#
|
||||
# Tip: To convert a complete media file, set start as 0 and
|
||||
# the runtime of the file as end.
|
||||
#
|
||||
# Dependencies: date, ffmpeg
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
printf "start (hh:mm:ss): "
|
||||
read -r start
|
||||
st=$(date -d "$start" +%s) || exit 1
|
||||
|
||||
printf "end (hh:mm:ss): "
|
||||
read -r end
|
||||
et=$(date -d "$end" +%s) || exit 1
|
||||
|
||||
if [ "$st" -ge "$et" ]; then
|
||||
printf "error: start >= end "
|
||||
read -r _
|
||||
exit 1
|
||||
fi
|
||||
|
||||
interval=$(( et - st ))
|
||||
|
||||
outfile=$(basename "$1")
|
||||
outfile="${outfile%.*}"_ringtone.mp3
|
||||
|
||||
ffmpeg -i "$1" -ss "$start" -t "$interval" -vn -sn -acodec libmp3lame -q:a 2 "$outfile"
|
||||
fi
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Simple script to give copy-paste a progress percentage
|
||||
# by utilizing rsync.
|
||||
#
|
||||
# LIMITATION: this won't work when pasting to MTP device.
|
||||
#
|
||||
# Dependencies: rsync
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Benawi Adha
|
||||
|
||||
sel=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
|
||||
# Choose one of these two schemes by commenting
|
||||
|
||||
# more verbose
|
||||
xargs -0 -I % rsync -ah --progress % "$PWD" < "$sel"
|
||||
|
||||
# less verbose
|
||||
# xargs -0 -I % rsync -ah --info=progress2 % "$PWD" < "$sel"
|
||||
|
||||
# Clear selection
|
||||
if [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Splits the file passed as argument or joins selection
|
||||
#
|
||||
# Note: Adds numeric suffix to split files
|
||||
# Adds '.out suffix to the first file to be joined and saves as output file for join
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Authors: Arun Prakash Jana, ath3
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
resp=s
|
||||
|
||||
if [ -s "$selection" ]; then
|
||||
printf "press 's' (split current file) or 'j' (join selection): "
|
||||
read -r resp
|
||||
fi
|
||||
|
||||
if [ "$resp" = "j" ]; then
|
||||
if [ -s "$selection" ]; then
|
||||
arr=$(tr '\0' '\n' < "$selection")
|
||||
if [ "$(echo "$arr" | wc -l)" -lt 2 ]; then
|
||||
echo "joining needs at least 2 files"
|
||||
exit
|
||||
fi
|
||||
for entry in $arr
|
||||
do
|
||||
if [ -d "$entry" ]; then
|
||||
echo "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"
|
||||
|
||||
# Clear selection
|
||||
if [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
||||
fi
|
||||
elif [ "$resp" = "s" ]; then
|
||||
if [ -n "$1" ] && [ -f "$1" ]; then
|
||||
# a single file is passed
|
||||
printf "split size in MB: "
|
||||
read -r size
|
||||
|
||||
if [ -n "$size" ]; then
|
||||
split -d -b "$size"M "$1" "$1"
|
||||
fi
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Edit file as superuser
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Anna Arad
|
||||
|
||||
EDITOR="${EDITOR:-vim}"
|
||||
|
||||
if type sudo >/dev/null 2>&1; then
|
||||
sudo -E "$EDITOR" "$1"
|
||||
elif type sudoedit >/dev/null 2>&1; then
|
||||
sudoedit -E "$1"
|
||||
elif type doas >/dev/null 2>&1; then
|
||||
doas "$EDITOR" "$1"
|
||||
fi
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Toggles executable mode for selection
|
||||
#
|
||||
# Dependencies: chmod
|
||||
#
|
||||
# Note: Works _only_ with selection (nnn can toggle the mode for the hovered file)
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
|
||||
if [ -s "$selection" ]; then
|
||||
xargs -0 -I {} sh -c 'if [ -x "{}" ] ; then chmod -x "{}" ; else chmod +x "{}" ; fi' < "$selection"
|
||||
|
||||
# Clear selection
|
||||
if [ -p "$NNN_PIPE" ]; then
|
||||
printf "-" > "$NNN_PIPE"
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Autodetects a nnn remote mountpoint (mounted with `c`)
|
||||
# from any of its subfolders and allows unmounting it
|
||||
# from the subdir without navigating to the mountppoint
|
||||
# or entering the remote name. Also works when hovering
|
||||
# the mountpoint directly like vanilla `u`.
|
||||
#
|
||||
# Dependencies: fusermount
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Authors: Kabouik & 0xACE
|
||||
#
|
||||
# TODO:
|
||||
# - Avoid lazy unmount by forcing nnn context to leave the subfolder before fusermount.
|
||||
# Tried `printf "%s" "0c$m" > "$NNN_PIPE"` but it breaks the nnn interface, see #854.
|
||||
|
||||
err=0
|
||||
m=$HOME/.config/nnn/mounts
|
||||
if [ "$PWD" = "$m" ]; then
|
||||
# Allow running the script on hovered directory if user is in ~/.config/nnn/mounts
|
||||
d="$1"
|
||||
else
|
||||
d=$(dirname "$(readlink -f "$1")" | grep -oP "^$m\K.*" | cut -d"/" -f2)
|
||||
fi
|
||||
|
||||
# Test if user is within $m or a subdir, abort if not
|
||||
if [ "$d" = "" ]; then
|
||||
clear && printf "You are not in a remote folder mounted with nnn. Press return to continue. " && read -r _
|
||||
else
|
||||
# Test if $m/$d is a mountpoint and try unmounting if it is
|
||||
mountpoint -q -- "$m/$d"
|
||||
if [ "$?" -eq "1" ]; then
|
||||
clear && printf "Parent '%s' is not a mountpoint. Press return to continue. " "$d" && read -r _
|
||||
else
|
||||
cd "$m" && fusermount -uq "$m/$d" || err=1
|
||||
if [ "$err" -eq "0" ]; then
|
||||
rmdir "$m/$d" && clear && printf "Parent '%s' unmounted." "$d"
|
||||
else
|
||||
clear && printf "Failed to unmount. Try lazy unmount? [Yy/Nn] " && read -r
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# If unmount fails, offer lazy unmount
|
||||
if [ "$REPLY" = "y" ] || [ "$REPLY" = "Y" ]; then
|
||||
err=0
|
||||
cd "$m" && fusermount -uqz "$m/$d" || err=1
|
||||
if [ "$err" -eq "0" ]; then
|
||||
rmdir "$m/$d" && clear && printf "Parent '%s' unmounted with lazy unmount. " "$d"
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Selections are uploaded using Firefox Send
|
||||
# For single files:
|
||||
# Upload to Firefox Send if ffsend is found, else
|
||||
# Paste contents of a text a file http://ix.io
|
||||
# Upload a binary file to file.io
|
||||
#
|
||||
# Dependencies: ffsend (https://github.com/timvisee/ffsend), curl, jq, tr
|
||||
#
|
||||
# Note: Binary file set to expire after a week
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Arun Prakash Jana
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
if [ -s "$selection" ]; then
|
||||
if type ffsend >/dev/null 2>&1; then
|
||||
# File name will be randomized foo.tar
|
||||
xargs -0 < "$selection" ffsend u
|
||||
else
|
||||
printf "ffsend is required to upload selection."
|
||||
fi
|
||||
|
||||
# Clear selection
|
||||
printf "-" > "$NNN_PIPE"
|
||||
else
|
||||
if [ -n "$1" ] && [ -s "$1" ]; then
|
||||
if type ffsend >/dev/null 2>&1; then
|
||||
ffsend -fiq u "$1"
|
||||
elif [ "$(mimetype --output-format %m "$1" | awk -F '/' '{print $1}')" = "text" ]; then
|
||||
curl -F "f:1=@$1" ix.io
|
||||
else
|
||||
# Upload the file, show the download link and wait till user presses any key
|
||||
curl -s -F "file=@$1" https://file.io/?expires=1w | jq '.link' | tr -d '"'
|
||||
|
||||
# To write download link to "$1".loc and exit
|
||||
# curl -s -F "file=@$1" https://file.io/?expires=1w -o `basename "$1"`.loc
|
||||
fi
|
||||
else
|
||||
printf "empty file!"
|
||||
fi
|
||||
fi
|
||||
|
||||
read -r _
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Set the selected image as wallpaper.
|
||||
# Uses nitrogen or pywal on X11, swww on wayland.
|
||||
#
|
||||
# Usage: Hover on an image and run the script to set it as wallpaper.
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: juacq97
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
if [ "$(file --mime-type "$1" | awk '{print $NF}' | awk -F '/' '{print $1}')" = "image" ]; then
|
||||
if [ "$XDG_SESSION_TYPE" = "x11" ]; then
|
||||
if type nitrogen >/dev/null 2>&1; then
|
||||
nitrogen --set-zoom-fill --save "$1"
|
||||
elif type wal >/dev/null 2>&1; then
|
||||
wal -i "$1"
|
||||
else
|
||||
printf "nitrogen or pywal missing"
|
||||
read -r _
|
||||
fi
|
||||
else
|
||||
if type swww >/dev/null 2>&1; then
|
||||
swww img "$1"
|
||||
else
|
||||
printf "swww missing"
|
||||
read -r _
|
||||
fi
|
||||
fi
|
||||
|
||||
# If you want a system notification, uncomment the next 3 lines.
|
||||
# notify-send -a "nnn" "Wallpaper changed!"
|
||||
# else
|
||||
# notify-send -a "nnn" "No image selected"
|
||||
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Copy system clipboard newline-separated file list to selection
|
||||
#
|
||||
# Dependencies:
|
||||
# - tr
|
||||
# - xclip/xsel (Linux)
|
||||
# - pbpaste (macOS)
|
||||
# - termux-clipboard-get (Termux)
|
||||
# - powershell (WSL)
|
||||
# - cygwim's /dev/clipboard (Cygwin)
|
||||
# - wl-paste (Wayland)
|
||||
# - clipboard (Haiku)
|
||||
#
|
||||
# Note:
|
||||
# - Limitation: breaks if a filename has newline in it
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: Léo Villeveygoux, after Arun Prakash Jana's .cbcp
|
||||
|
||||
IFS="$(printf '%b_' '\n')"; IFS="${IFS%_}" # protect trailing \n
|
||||
|
||||
selection=${NNN_SEL:-${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection}
|
||||
|
||||
getclip () {
|
||||
if type xsel >/dev/null 2>&1; then
|
||||
# Linux
|
||||
xsel -bo
|
||||
elif type xclip >/dev/null 2>&1; then
|
||||
# Linux
|
||||
xclip -sel clip -o
|
||||
elif type pbpaste >/dev/null 2>&1; then
|
||||
# macOS
|
||||
pbpaste
|
||||
elif type termux-clipboard-get >/dev/null 2>&1; then
|
||||
# Termux
|
||||
termux-clipboard-get
|
||||
elif type powershell.exe >/dev/null 2>&1; then
|
||||
# WSL
|
||||
powershell.exe Get-Clipboard
|
||||
elif [ -r /dev/clipboard ] ; then
|
||||
# Cygwin
|
||||
cat /dev/clipboard
|
||||
elif type wl-paste >/dev/null 2>&1; then
|
||||
# Wayland
|
||||
wl-paste
|
||||
elif type clipboard >/dev/null 2>&1; then
|
||||
# Haiku
|
||||
clipboard --print
|
||||
fi
|
||||
}
|
||||
|
||||
CLIPBOARD=$(getclip)
|
||||
|
||||
# Check if clipboard actually contains a file list
|
||||
for file in $CLIPBOARD ; do
|
||||
if [ ! -e "$file" ] ; then
|
||||
exit 1;
|
||||
fi
|
||||
done
|
||||
|
||||
printf "%s" "$CLIPBOARD" | tr '\n' '\0' > "$selection"
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Description: Sets the xdg-open's default application for the current entry's file
|
||||
# type. ${XDG_DATA_DIRS} and ${XDG_DATA_HOME} are set to the recommended
|
||||
# defaults if unset, as specified in XDG Base Directory Specification
|
||||
# - http://specifications.freedesktop.org/basedir-spec/.
|
||||
#
|
||||
# Dependencies: xdg-utils, fzf or dmenu (GUI)
|
||||
#
|
||||
# Shell: POSIX compliant
|
||||
# Author: lwnctd
|
||||
|
||||
# set to 1 to enable GUI apps
|
||||
GUI="${GUI:-0}"
|
||||
|
||||
if [ "$GUI" -ne 0 ] && command -v dmenu > /dev/null 2>& 1; then
|
||||
menu="dmenu -i -l 7"
|
||||
elif command -v fzf > /dev/null 2>& 1; then
|
||||
menu="fzf -e --tiebreak=begin"
|
||||
fi
|
||||
|
||||
if [ -z "$1" ] || [ -z "$menu" ] > /dev/null 2>& 1; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ftype=$(xdg-mime query filetype "$2/$1")
|
||||
|
||||
if [ -z "$ftype" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dirs=${XDG_DATA_DIRS:-/usr/local/share:/usr/share}
|
||||
dirs=${dirs}:${XDG_DATA_HOME:-$HOME/.local/share}:
|
||||
|
||||
while [ -n "$dirs" ]; do
|
||||
d=${dirs%%:*}
|
||||
if [ -n "$d" ] && [ -d "$d"/applications ]; then
|
||||
set -- "$@" "$d"/applications
|
||||
fi
|
||||
dirs=${dirs#*:}
|
||||
done
|
||||
|
||||
app=$(find "$@" -iname '*.desktop' -exec grep '^Name=' {} + \
|
||||
| sort -u -t ':' -k 1,1 \
|
||||
| sed -e 's;..*/\(..*desktop\):Name=\(..*\);\2:\1;' \
|
||||
| sort -t ':' -k 1,1 \
|
||||
| column -t -s ':' -o "$(printf '\t')" \
|
||||
| $menu \
|
||||
| cut -f 2)
|
||||
|
||||
if [ -n "$app" ]; then
|
||||
xdg-mime default "${app%%[[:blank:]]*}" "$ftype"
|
||||
fi
|
|
@ -0,0 +1,30 @@
|
|||
n ()
|
||||
{
|
||||
# Block nesting of nnn in subshells
|
||||
if [[ "${NNNLVL:-0}" -ge 1 ]]; then
|
||||
echo "nnn is already running"
|
||||
return
|
||||
fi
|
||||
|
||||
# The behaviour is set to cd on quit (nnn checks if NNN_TMPFILE is set)
|
||||
# If NNN_TMPFILE is set to a custom path, it must be exported for nnn to
|
||||
# see. To cd on quit only on ^G, remove the "export" and make sure not to
|
||||
# use a custom path, i.e. set NNN_TMPFILE *exactly* as follows:
|
||||
# NNN_TMPFILE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.lastd"
|
||||
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
|
||||
|
||||
# The backslash allows one to alias n to nnn if desired without making an
|
||||
# infinitely recursive alias
|
||||
\nnn "$@"
|
||||
|
||||
if [ -f "$NNN_TMPFILE" ]; then
|
||||
. "$NNN_TMPFILE"
|
||||
rm -f "$NNN_TMPFILE" > /dev/null
|
||||
fi
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
# NOTE: set NNN_TMPFILE correctly if you use 'XDG_CONFIG_HOME'
|
||||
|
||||
# The behaviour is set to cd on quit (nnn checks if NNN_TMPFILE is set)
|
||||
# If NNN_TMPFILE is set to a custom path, it must be exported for nnn to see.
|
||||
# To cd on quit only on ^G, set NNN_TMPFILE after the nnn invocation, and make
|
||||
# sure not to use a custom path.
|
||||
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
|
||||
|
||||
# The backslash allows one to alias n to nnn if desired without making an
|
||||
# infinitely recursive alias
|
||||
alias n '\nnn; source "$NNN_TMPFILE"; rm -f "$NNN_TMPFILE"'
|
|
@ -0,0 +1,41 @@
|
|||
# Append this file to ~/.elvish/rc.elv (Elvish > 0.17.0)
|
||||
|
||||
use path
|
||||
|
||||
fn n {|@a|
|
||||
# Block nesting of nnn in subshells
|
||||
if (has-env NNNLVL) {
|
||||
try {
|
||||
if (>= $E:NNNLVL 1) {
|
||||
echo "nnn is already running"
|
||||
return
|
||||
}
|
||||
} catch e {
|
||||
nop
|
||||
}
|
||||
}
|
||||
|
||||
# The behaviour is set to cd on quit (nnn checks if NNN_TMPFILE is set)
|
||||
# If NNN_TMPFILE is set to a custom path, it must be exported for nnn to
|
||||
# see.
|
||||
if (has-env XDG_CONFIG_HOME) {
|
||||
set-env NNN_TMPFILE $E:XDG_CONFIG_HOME/nnn/.lastd
|
||||
} else {
|
||||
set-env NNN_TMPFILE $E: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
|
||||
|
||||
# The e: prefix allows one to alias n to nnn if desired without making an
|
||||
# infinitely recursive alias
|
||||
e:nnn $@a
|
||||
|
||||
if (path:is-regular $E:NNN_TMPFILE) {
|
||||
eval (slurp < $E:NNN_TMPFILE)
|
||||
rm $E:NNN_TMPFILE
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
# 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 --wraps nnn --description 'support nnn quit and change directory'
|
||||
# Block nesting of nnn in subshells
|
||||
if test -n "$NNNLVL" -a "$NNNLVL" -ge 1
|
||||
echo "nnn is already running"
|
||||
return
|
||||
end
|
||||
|
||||
# The behaviour is set to cd on quit (nnn checks if NNN_TMPFILE is set)
|
||||
# If NNN_TMPFILE is set to a custom path, it must be exported for nnn to
|
||||
# see. To cd on quit only on ^G, remove the "-x" from both lines below,
|
||||
# without changing the paths.
|
||||
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
|
||||
|
||||
# The command function allows one to alias this function to `nnn` without
|
||||
# making an infinitely recursive alias
|
||||
command nnn $argv
|
||||
|
||||
if test -e $NNN_TMPFILE
|
||||
source $NNN_TMPFILE
|
||||
rm $NNN_TMPFILE
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue