summaryrefslogtreecommitdiff
path: root/functions/__z.fish
blob: f72ff0ec5c528116b55aa9b06c424a90ac555275 (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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
function __z -d "Jump to a recent directory."
    function __print_help -d "Print z help."
        printf "Usage: $Z_CMD  [-celrth] string1 string2...\n\n"
        printf "         -c --clean    Removes directories that no longer exist from $Z_DATA\n"
        printf "         -d --dir      Opens matching directory using system file manager.\n"
        printf "         -e --echo     Prints best match, no cd\n"
        printf "         -l --list     List matches and scores, no cd\n"
        printf "         -p --purge    Delete all entries from $Z_DATA\n"
        printf "         -r --rank     Search by rank\n"
        printf "         -t --recent   Search by recency\n"
        printf "         -x --delete   Removes the current directory from $Z_DATA\n"
        printf "         -h --help     Print this help\n\n"
    end
    function __z_legacy_escape_regex
        # taken from escape_string_pcre2 in fish
        # used to provide compatibility with fish 2
        for c in (string split '' $argv)
            if contains $c (string split '' '.^$*+()?[{}\\|-]')
                printf \\
            end
            printf '%s' $c
        end
    end

    set -l options h/help c/clean e/echo l/list p/purge r/rank t/recent d/directory x/delete

    argparse $options -- $argv

    if set -q _flag_help
        __print_help
        return 0
    else if set -q _flag_clean
        __z_clean
        printf "%s cleaned!\n" $Z_DATA
        return 0
    else if set -q _flag_purge
        echo >$Z_DATA
        printf "%s purged!\n" $Z_DATA
        return 0
    else if set -q _flag_delete
        sed -i -e "\:^$PWD|.*:d" $Z_DATA
        return 0
    end

    set -l typ

    if set -q _flag_rank
        set typ rank
    else if set -q _flag_recent
        set typ recent
    end

    set -l z_script '
        function frecent(rank, time) {
            dx = t-time
            if( dx < 3600 ) return rank*4
            if( dx < 86400 ) return rank*2
            if( dx < 604800 ) return rank/2
            return rank/4
        }

        function output(matches, best_match, common) {
            # list or return the desired directory
            if( list ) {
                cmd = "sort -nr"
                for( x in matches ) {
                    if( matches[x] ) {
                        printf "%-10s %s\n", matches[x], x | cmd
                    }
                }
            } else {
                if( common ) best_match = common
                print best_match
            }
        }

        function common(matches) {
            # find the common root of a list of matches, if it exists
            for( x in matches ) {
                if( matches[x] && (!short || length(x) < length(short)) ) {
                    short = x
                }
            }
            if( short == "/" ) return
            for( x in matches ) if( matches[x] && index(x, short) != 1 ) {
                    return
                }
            return short
        }

        BEGIN {
            hi_rank = ihi_rank = -9999999999
        }
        {
            if( typ == "rank" ) {
                rank = $2
            } else if( typ == "recent" ) {
                rank = $3 - t
            } else rank = frecent($2, $3)
            if( $1 ~ q ) {
                matches[$1] = rank
            } else if( tolower($1) ~ tolower(q) ) imatches[$1] = rank
            if( matches[$1] && matches[$1] > hi_rank ) {
                best_match = $1
                hi_rank = matches[$1]
            } else if( imatches[$1] && imatches[$1] > ihi_rank ) {
                ibest_match = $1
                ihi_rank = imatches[$1]
            }
        }

        END {
        # prefer case sensitive
            if( best_match ) {
                output(matches, best_match, common(matches))
            } else if( ibest_match ) {
                output(imatches, ibest_match, common(imatches))
            }
        }
    '

    set -l qs
    for arg in $argv
        set -l escaped $arg
        if string escape --style=regex '' >/dev/null 2>&1 # use builtin escape if available
            set escaped (string escape --style=regex $escaped)
        else
            set escaped (__z_legacy_escape_regex $escaped)
        end
        # Need to escape twice, see https://www.math.utah.edu/docs/info/gawk_5.html#SEC32
        set escaped (string replace --all \\ \\\\ $escaped)
        set qs $qs $escaped
    end
    set -l q (string join '.*' $qs)

    if set -q _flag_list
        # Handle list separately as it can print common path information to stderr
        # which cannot be captured from a subcommand.
        command awk -v t=(date +%s) -v list="list" -v typ="$typ" -v q="$q" -F "|" $z_script "$Z_DATA"
        return
    end

    set target (command awk -v t=(date +%s) -v typ="$typ" -v q="$q" -F "|" $z_script "$Z_DATA")

    if test "$status" -gt 0
        return
    end

    if test -z "$target"
        printf "'%s' did not match any results\n" "$argv"
        return 1
    end

    if set -q _flag_echo
        printf "%s\n" "$target"
    else if set -q _flag_directory
        if test -n "$ZO_METHOD"
            type -q "$ZO_METHOD"; and "$ZO_METHOD" "$target"; and return $status
            echo "Cannot open with ZO_METHOD set to $ZO_METHOD"; and return 1
        else if test "$OS" = Windows_NT
            # Be careful, in msys2, explorer always return 1
            type -q explorer; and explorer "$target"
            return 0
            echo "Cannot open file explorer"
            return 1
        else
            type -q xdg-open; and xdg-open "$target"; and return $status
            type -q open; and open "$target"; and return $status
            echo "Not sure how to open file manager"; and return 1
        end
    else
        pushd "$target"
    end
end