Last active
June 13, 2022 18:25
-
-
Save nkh/6144e0dfcaf5848c43fa962ad47be865 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env bash | |
bff() # Inspired by fff. Run: bbf 3> some_file, to get exit-time selection | |
{ | |
shopt -s checkwinsize ; trap 'rdir' SIGWINCH ; | |
declare -A dir_file filters marks tags ; show_dirs=1 ;kolumn=1 | |
local BFF=(/ /home/nadim /home/nadim/nadim /home/nadim/nadim/downloads) | |
pushd "$1" &>/dev/null ; tabs+=("$PWD") ; tab=0 ; rdir | |
while true; do [[ -n $key ]] && { REPLY=$key ; key= ; } || read -rsn 1 ; case "${REPLY: -1}" in | |
q|Q) ((${#tabs[@]} - 1 == 0)) \ | |
&& { true >&3 && [[ $REPLY == 'q' ]] && selection '\n' >&3 || :>&3 ; quit ; } \ | |
|| { unset -v 'tabs[tab]' ; tabs=("${tabs[@]}") ; ((tab -= 1)) ; key=$'\t'; } ;; | |
g|G) dir_file["$PWD"]=0 ; [[ "$REPLY" == 'G' ]] && ((dir_file["$PWD"] = nfiles - 1)) ; list ;; | |
B|j) ((file < nfiles - 1)) && { ((dir_file["$PWD"] = file + 1)) ; list; } ;; | |
A|k) ((file > 0)) && { ((dir_file["$PWD"] = file - 1)) ; list; } ;; | |
5) ((file -= $LINES, file = file < 0 ? 0 : file)) ; list $file ;; | |
6) ((file += $LINES, file = file > nfiles ? nfiles : file)) ; list $file ;; | |
D|h) [[ "$PWD" != / ]] && { nd="${PWD%/*}" ; opwd=$PWD ; cdir "${nd:-/}" "$opwd"; } ;; | |
C|l|"") [[ -f "${files[file]}" ]] && { "${EDITOR}" "${files[file]}"; echo -e '\e[?25l' ; } \ | |
|| { (($nfiles)) ; cdir "${files[file]}" ; } ;; | |
.) [[ $show_hidden ]] && show_hidden= || show_hidden=1 ; rdir ;; | |
_) ((show_dirs ^= 1)) ; rdir ;; | |
S) ((show_stat ^= 1)) ; list ;; | |
f) prompt "~ " -ei "${filters[$tab]}" ; filters[$tab]="$REPLY" ; filter_mark="~" ; rdir ;; | |
F) filters[$tab]= ; filter_mark= ; rdir ;; | |
K) prompt 'sort -k ' -sn 1 && [[ -n $REPLY ]] && kolumn=$REPLY ; rdir ;; | |
#) sorting by ... | |
[0-9]) cdir "${BFF[REPLY]}" ;; | |
b|n|N) how="$REPLY" ; [[ $how == 'b' ]] && prompt "find: " ; ffind "$REPLY" $how ;; | |
/) g="$(cd "$PWD" ; fd . --color=always | fzf --ansi --info=inline --layout=reverse)" ; \ | |
[[ "$g" ]] && nd="$PWD/"$(dirname "$g") && cdir "$nd" "$PWD/$g" ;; | |
-) cdir "${PPWD}" ;; | |
c) prompt 'cd: ' -e && [[ -n $REPLY ]] && cdir "$REPLY" ;; | |
m) prompt 'M' -n 1 && [[ -n $REPLY ]] && marks[$REPLY]=$(dirname "${files[file]}") ; refresh ; list ;; | |
\') prompt "'" -n 1 ; refresh ; list ; [[ -n ${marks[$REPLY]} ]] && cdir ${marks[$REPLY]} ;; | |
y) n=${files[file]} ; [[ ${tags[$n]} == '▪' ]] && unset -v 'tags[$n]' || tags[$n]='▪' ; list ; key=j ;; | |
Y) n=${files[file]} ; [[ ${tags[$n]} == '▪' ]] && unset -v 'tags[$n]' || tags[$n]='▪' ; list ; key=k ;; | |
u) for p in "${files[@]}" ; do tags["$p"]='▪' ; done ; list ;; | |
U) tags=() ; refrsh ; list ;; | |
r) prompt "rename ${files[file]##*/} to: " && mv "${files[file]}" "$PWD/$REPLY" ; rdir ;; | |
M) prompt 'mkdir: ' && [[ "$REPLY" ]] && mkdir -p "$PWD/$REPLY" ; rdir ;; | |
p) ((${#tags[@]})) && { cp "${!tags[@]}" "$PWD" ; rdir ; } ;; | |
P) ((${#tags[@]})) && { mv "${!tags[@]}" "$PWD" ; rdir ; } ;; | |
x) chmod a+x $(selection ' ') ; rdir ;; | |
X) chmod a-x $(selection ' ') ; rdir ;; | |
d) ((${#tags[@]})) && sel=", tags: ${#tags[@]}" || sel= ; \ | |
prompt "delete$sel ? [y/N]: " -n1 && [[ $REPLY == y ]] && { rm -rf $(selection ' ') ; tags=() ; } ; \ | |
rdir ;; | |
t) tabs+=("$PWD") ; ((tab = ${#tabs[@]} - 1)) ; list ;; | |
$'\t') ((tab += 1, tab >= ${#tabs[@]})) && tab=0 ; cdir ${tabs[tab]} ;; | |
\!) tmux split-pane -v -c "$PWD" -p20 ;; | |
#:) shell command with %p %f %e %tags ... set | |
esac ; done | |
} | |
cdir() | |
{ | |
[[ -d "$1" ]] || return | |
[[ "$PPWD" != "$PWD" ]] && PPWD="$PWD" ; PWD="${1}" ; tabs[tab]="$PWD" ; cd $PWD | |
LINES=$(tput lines) ; COLS=$(tput cols) ; files=() ; files_color=() ; search=$2 ; select= ; nfiles=0 ; get_dir | |
while true | |
do | |
read -s -u 4 -t 0.01 p ; [ $? -gt 128 ] && break ; read -s -u 5 pc ; | |
files[$nfiles]="$PWD/$p" ; files_color[$nfiles]="$pc" | |
[[ "$PWD/$p" == "$search" ]] && select=$nfiles ; ((nfiles++)) | |
done | |
((lines = nfiles > LINES - 1 ? LINES - 1 : nfiles, center = lines / 2)) | |
refresh ; list $select | |
} | |
header() | |
{ | |
a=$* ; l=$(( ${#PWD} - ($COLS - (${#a} + 11) ) )) | |
echo -e "\e[H\e[K\e[94m${PWD:l<0?0:l}\e[94m\e[95m$filter_mark $@ $((tab+1))/${#tabs[@]} ${#tags[@]}\e[m" | |
} | |
list() | |
{ | |
(($nfiles == 0)) && header "${#tags[@]}\e[33m<Empty>" && return | |
[[ $1 ]] && dir_file[$PWD]=$1 ; file=${dir_file[$PWD]:-0} | |
((file >= nfiles)) && ((file=nfiles-1)) | |
((top = nfiles < lines || file <= center ? 0 : file >= nfiles - center ? nfiles - lines : file - center)) | |
((show_stat)) && stat="$(stat -c ' %A %U' ${files[file]}) $(stat -c %s ${files[file]} | numfmt --to=iec)" || stat= | |
header "$((file+1))/${nfiles}$stat" | |
for((i=$top ; i <= ((bottom = top + lines - 1, bottom < 0 ? 0 : bottom)) ; i++)) | |
do | |
tag=${tags[${files[$i]}]:- } | |
[[ $i != $file ]] && cursor=$tag || cursor="\e[7;34m$tag\e[m" | |
[[ $i == $bottom ]] && nl= || nl='\n' | |
echo -ne "\e[K$cursor${files_color[i]}$nl" | |
done | |
} | |
get_dir() { mkapipe 4 ; mkapipe 5 ; ((show_dirs)) && _get_dir d "%f" ; _get_dir f "%f" ; } | |
_get_dir() | |
{ | |
find "$PWD/" -mindepth 1 -maxdepth 1 ${show_hidden:+\( ! -iname ".*" \)} -type $1 -printf "$2\t%i\t%f\t%A@\n" | \ | |
rg "${filters[$tab]}" | \ | |
sort -k $kolumn | \ | |
tee >( cut -f 3 >&4) | \ | |
cut -f 1 | lscolors | awk '{print substr($0, 0, '$COLS'-1)}' >&5 | |
} | |
ffind() | |
{ | |
[[ $2 == 'b' ]] && to_search="$1" | |
[[ $2 == 'N' ]] && { ((from = $file > 0 ? $file - 1 : 0)) ; to=0 ; inc='--' ; } \ | |
|| { ((from = $file >= $nfiles ? $file : (($file + 1)))) ; to=$nfiles ; inc='++' ; } | |
for((i=$from ; i != $to ; i$inc)) ; do [[ "${files[i]##*/}" =~ "$to_search" ]] & rrefesh && list $i && break ; done | |
} | |
refresh() { echo -ne "\e[?25l\e[2J\e[H\e[m${1}" ; } | |
prompt() { echo -ne '\e[999B\e[0;H\e[K\e[33m\e[?25h' ; read -rp "$@" ; echo $REPLY ; } | |
rdir() { cdir "$PWD" ; } | |
quit() { refresh "\e[?25h" ; exit 0 ; } | |
mkapipe() { PIPE=$(mktemp -u) && mkfifo $PIPE && pc="exec $1<>$PIPE" && eval "$pc" && rm $PIPE ; } | |
selection() { ((${#tags[@]})) && printf "%s$1" "${!tags[@]}" || printf "%s$1" "${files[file]}" ; } | |
bff $@ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment