summaryrefslogtreecommitdiffstats
path: root/fff
blob: 4dec64334b4f8cb61e3a08583254e4105b52ab7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env bash
#
# fff - fucking fast file-manager.

refresh() {
    printf '\e[?7l\e[?25l\e[2J\e[H'
    (:;:); ((LINES==0)) && read -r LINES _ < <(stty size)
    ((m=LINES-3,j=l>m/2?l>=c-m/2?c+1:l+m/2+1:m,k=k>=0?j-m>=0?j-m:k:k,l=l>c?k:l))
}

get_dir() {
    d=(); f=()
    for p in "$PWD"/*; do [[ -d $p ]] && d+=("$p") || f+=("$p"); done
    f=("${d[@]}" "${f[@]}"); ((${#f[@]}==0)) && f[0]=$'\e[27mempty'
}

f_print() {
    ((c=${#f[@]},j=j>c?c:j))

    for((i=${k:=0};i<j;i++)); {
        ((c<=0)) && { get_dir; f_print; return; } || path="${f[i]##*/}"
        [[ -d ${f[i]} ]] && { fo+='\e[1m\e[3'"${FFF_COL1:-2}m"; path+=/; }
        [[ ${co[i]} == "${f[i]}" ]] && fo+='\e[7m\e[1m\e[3'"${FFF_COL3:-6}m"
        [[ ${f[i]} == "${f[l]}" ]]  && fo+='\e[7m\e[1m\e[3'"${FFF_COL4:-1}m"
        printf '\e[K%b%s\e[m\n' "$fo" "$path"; fo=
    }
    printf '\e[3%sm\e[%s;H\e[K\n\e[K%s\e[m\e[H' "${FFF_COL2:-7}" "$((LINES-2))" \
           "${PWD/\/\//\/} (${l:-1}/$((c-1))) ${co[*]:+${pr[*]}: ${#co[@]}^ [p]}"
}

hist() {
    l2[((n=n<0?0:++n))]="$l:$k"
}

open() {
    [[ -d $1/ ]] && { l=0; refresh; PWD="${1:-/}"; get_dir; f_print; }
    [[ -f $1  ]] && { shopt -s nocasematch
        case "${1##*.}" in
            3dm|3ds|3g2|3gp|7z|a|aac|adp|ai|aif|aiff|alz|ape|apk|ar|arj|asf|au|\
            avi|bak|baml|bh|bin|bk|bmp|btif|bz2|bzip2|cab|caf|cgm|class|cmx|\
            cpio|cr2|csv|cur|dat|dcm|deb|dex|djvu|dll|dmg|dng|doc|docm|docx|dot|\
            dotm|dra|DS_Store|dsk|dts|dtshd|dvb|dwg|dxf|ecelp4800|ecelp7470|\
            ecelp9600|egg|eol|eot|epub|exe|f4v|fbs|fh|fla|flac|fli|flv|fpx|fst|\
            fvt|g3|gh|gif|graffle|gz|gzip|h261|h263|h264|icns|ico|ief|img|ipa|\
            iso|jar|jpeg|jpg|jpgv|jpm|jxr|key|ktx|lha|lib|lvp|lz|lzh|lzma|lzo|\
            m3u|m4a|m4v|mar|mdi|mht|mid|midi|mj2|mka|mkv|mmr|mng|mobi|mov|movie|\
            mp3|mp4|mp4a|mpeg|mpg|mpga|mxu|nef|npx|numbers|o|oga|ogg|ogv|otf|\
            part|pages|pbm|pcx|pdb|pdf|pea|pgm|pic|png|pnm|pot|potm|potx|ppa|\
            ppam|ppm|pps|ppsm|ppsx|ppt|pptm|pptx|psd|pya|pyc|pyo|pyv|qt|rar|ras|\
            raw|resources|rgb|rip|rlc|rmf|rmvb|rtf|rz|s3m|s7z|scpt|sgi|shar|sil|\
            sketch|slk|smv|so|stl|sub|swf|tar|tbz|tbz2|tga|tgz|thmx|tif|tiff|\
            tlz|ttc|ttf|txz|udf|uvh|uvi|uvm|uvp|uvs|uvu|viv|vob|war|wav|wax|\
            wbmp|wdp|weba|webm|webp|whl|wim|wm|wma|wmv|wmx|woff|woff2|wrm|wvx|\
            xbm|xif|xla|xlam|xls|xlsb|xlsm|xlsx|xlt|xltm|xltx|xm|xmind|xpi|xpm|\
            xwd|xz|z|zip|zipx)
                [[ "$OSTYPE" == darwin* ]] && oc="open"
                nohup "${FFF_OPENER:-${oc:-xdg-open}}" "$1" &>/dev/null & disown
            ;;

            *) "${FFF_EDITOR:-${EDITOR:-vi}}" "$1"; printf '\e[?25l' ;;
        esac
    }; shopt -u nocasematch
}

prompt() {
    printf '\e[999B\e[?25h'
    case "${1: -1}" in
        r) read -rp "rename ${f[l]##*/}: "; [[ $REPLY ]] && \
           mv "${f[l]}" "$PWD/$REPLY" ;;
        d) read -n 1 -rp "trash ${f[l]##*/}? [y/n]: " y; [[ $y == y ]] && {
           mv "${f[l]}" ~/.cache/fff/trash/; ((l>0?l--:l)); } ;;
        n) read -rp "mkdir: ";   [[ $REPLY ]] && mkdir -p "$PWD/$REPLY" ;;
        f) read -rp "mkfile: ";  [[ $REPLY ]] && : > "$PWD/$REPLY" ;;
        /) g="$PWD"; read -rp /; [[ $REPLY ]] && f=("$PWD"/*"$REPLY"*)
           l=0; refresh; f_print; return
    esac
    refresh; get_dir
}

key() {
    case "${1: -1}" in
        C|l|"") [[ -d "${f[l]}" ]] && hist; open "${f[l]}"; g= ;;
        D|h) open "${g:-${PWD%/*}}";
             [[ $g ]] || ((l=${l2[n]/:*},k=${l2[n--]/*:}))
             [[ $PWD == / ]] && l=0; g=; refresh ;;

        g) l=0; refresh ;;
        G) ((l=c-1)); refresh; ((k=k<0?0:k)) ;;
        .) a=(u s); shopt -"${a[((h=h>0?0:++h))]}" dotglob
           l=0; refresh; get_dir ;;

        y) [[ ${co[l]} == *"${f[l]}"* ]] && { unset 'co[l]'; return; }
           co[l]="${f[l]}"; pr=(cp -rt) ;;
        m) [[ ${co[l]} == *"${f[l]}"* ]] && { unset 'co[l]'; return; }
           co[l]="${f[l]}"; pr=(mv -t) ;;
        p) [[ ${co[*]} ]] && "${pr[@]}" "$PWD" "${co[@]}" && {
           refresh; get_dir; co=(); } ;;
        c) co=() ;;

        r|d|n|f|/) prompt "$1" ;;
        \~) g="$PWD"; hist; open ~ ;;
        t)  g="$PWD"; hist; open ~/.cache/fff/trash ;;

        [1-9]) fa="FFF_FAV${1}"; fa="${!fa}"
               [[ $fa ]] && { g="$PWD"; hist; open "${fa%/}"; } ;;

        q) exit ;;

        B|j) ((l=l==c-1?l:++l,j!=c&&l==j-m/2+1))&&((k=k>=j?k:++k,j=j<c?++j:j)) ;;
        A|k) ((l=l<1?l:--l,k>0&&l==k+m/2-2))&&((k=k<=j?k>0?--k:0:j,j=j>0?--j:j))
    esac
}

main() {
    shopt -s nocaseglob nullglob checkwinsize
    mkdir -p ~/.cache/fff/trash/
    pushd "$1" &>/dev/null ||:; refresh; get_dir; f_print

    trap "refresh; printf '\\e[m\\e[?25h\\e[?7h'" EXIT
    trap 'refresh; f_print' SIGWINCH

    for ((;;)); { read -rsn 1; key "$REPLY"; f_print; }
}

main "$@"