Erich Smith | 3e76d67 | 2012-05-07 09:56:36 -0400 | [diff] [blame] | 1 | #!/usr/bin/env sh |
| 2 | |
| 3 | # Fasd (this file) can be sourced or executed by any POSIX compatible shell. |
| 4 | |
| 5 | # Fasd is originally written based on code from z (https://github.com/rupa/z) |
| 6 | # by rupa deadwyler under the WTFPL license. Most if not all of the code has |
| 7 | # been rewritten. |
| 8 | |
| 9 | # Copyright (C) 2011, 2012 by Wei Dai. All rights reserved. |
| 10 | # |
| 11 | # Permission is hereby granted, free of charge, to any person obtaining |
| 12 | # a copy of this software and associated documentation files (the |
| 13 | # "Software"), to deal in the Software without restriction, including |
| 14 | # without limitation the rights to use, copy, modify, merge, publish, |
| 15 | # distribute, sublicense, and/or sell copies of the Software, and to |
| 16 | # permit persons to whom the Software is furnished to do so, subject to |
| 17 | # the following conditions: |
| 18 | # |
| 19 | # The above copyright notice and this permission notice shall be included |
| 20 | # in all copies or substantial portions of the Software. |
| 21 | # |
| 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 23 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 24 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| 25 | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| 26 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| 27 | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| 28 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 29 | |
| 30 | fasd() { |
| 31 | |
| 32 | case "$1" in |
| 33 | --init) |
| 34 | shift |
| 35 | while [ "$1" ]; do |
| 36 | case $1 in |
| 37 | env) |
| 38 | { # source rc files if present |
| 39 | [ -s "/etc/fasdrc" ] && . "/etc/fasdrc" |
| 40 | [ -s "$HOME/.fasdrc" ] && . "$HOME/.fasdrc" |
| 41 | |
| 42 | # set default options |
| 43 | [ -z "$_FASD_DATA" ] && _FASD_DATA="$HOME/.fasd" |
| 44 | [ -z "$_FASD_BLACKLIST" ] && _FASD_BLACKLIST="--help" |
| 45 | [ -z "$_FASD_SHIFT" ] && _FASD_SHIFT="sudo busybox" |
| 46 | [ -z "$_FASD_IGNORE" ] && _FASD_IGNORE="fasd cd ls echo" |
| 47 | [ -z "$_FASD_SINK" ] && _FASD_SINK=/dev/null |
| 48 | [ -z "$_FASD_TRACK_PWD" ] && _FASD_TRACK_PWD=1 |
| 49 | [ -z "$_FASD_MAX" ] && _FASD_MAX=2000 |
| 50 | [ -z "$_FASD_BACKENDS" ] && _FASD_BACKENDS=native |
| 51 | |
| 52 | if [ -z "$_FASD_AWK" ]; then |
| 53 | # awk preferences |
| 54 | local awk; for awk in mawk gawk original-awk nawk awk; do |
| 55 | $awk "" && _FASD_AWK=$awk && break |
| 56 | done |
| 57 | fi |
| 58 | } >> "${_FASD_SINK:-/dev/null}" 2>&1 |
| 59 | ;; |
| 60 | |
| 61 | auto) cat <<EOS |
| 62 | { if compctl; then # zsh |
| 63 | eval "\$(fasd --init posix-alias zsh-hook zsh-ccomp zsh-ccomp-install \ |
| 64 | zsh-wcomp zsh-wcomp-install)" |
| 65 | elif complete; then # bash |
| 66 | eval "\$(fasd --init posix-alias bash-hook bash-ccomp bash-ccomp-install)" |
| 67 | else # posix shell |
| 68 | eval "\$(fasd --init posix-alias posix-hook)" |
| 69 | fi |
| 70 | } >> "$_FASD_SINK" 2>&1 |
| 71 | |
| 72 | EOS |
| 73 | ;; |
| 74 | |
| 75 | posix-alias) cat <<EOS |
| 76 | alias a='fasd -a' |
| 77 | alias s='fasd -si' |
| 78 | alias sd='fasd -sid' |
| 79 | alias sf='fasd -sif' |
| 80 | alias d='fasd -d' |
| 81 | alias f='fasd -f' |
| 82 | # function to execute built-in cd |
| 83 | fasd_cd() { [ \$# -gt 1 ] && cd "\$(fasd -e echo "\$@")" || fasd "\$@"; } |
| 84 | alias z='fasd_cd -d' |
| 85 | |
| 86 | EOS |
| 87 | ;; |
| 88 | |
| 89 | zsh-hook) cat <<EOS |
| 90 | # add zsh hook |
| 91 | _fasd_preexec() { |
| 92 | { eval "fasd --proc \$(fasd --sanitize \$3)"; } >> "$_FASD_SINK" 2>&1 |
| 93 | } |
| 94 | autoload -U add-zsh-hook |
| 95 | add-zsh-hook preexec _fasd_preexec |
| 96 | |
| 97 | EOS |
| 98 | ;; |
| 99 | |
| 100 | bash-hook) cat <<EOS |
| 101 | # add bash hook |
| 102 | echo \$PROMPT_COMMAND | grep -v -q "fasd --proc" && \ |
| 103 | PROMPT_COMMAND='eval "fasd --proc \$(fasd --sanitize \$(history 1 | \ |
| 104 | sed -e "s/^[ ]*[0-9]*[ ]*//"))" >> "$_FASD_SINK" 2>&1;'"\$PROMPT_COMMAND" |
| 105 | |
| 106 | EOS |
| 107 | ;; |
| 108 | |
| 109 | posix-hook) cat <<EOS |
| 110 | _fasd_ps1_func() { |
| 111 | { eval "fasd --proc \$(fasd --sanitize \ |
| 112 | \$(fc -nl -0 | sed -n '\$s/\s*\(.*\)/\1/p'))"; } >> "$_FASD_SINK" 2>&1 |
| 113 | } |
| 114 | echo "\$PS1" | grep -v -q "_fasd_ps1_func" && \ |
| 115 | export PS1="\\\$(_fasd_ps1_func)\$PS1" |
| 116 | |
| 117 | EOS |
| 118 | ;; |
| 119 | |
| 120 | zsh-ccomp) cat <<EOS |
| 121 | # zsh command mode completion |
| 122 | _fasd_zsh_cmd_complete() { |
| 123 | local compl |
| 124 | read -c compl |
| 125 | compstate[insert]=menu # no expand |
| 126 | reply=(\${(f)"\$(fasd --complete "\$compl")"}) |
| 127 | } |
| 128 | |
| 129 | EOS |
| 130 | ;; |
| 131 | |
| 132 | zsh-wcomp) cat <<EOS |
| 133 | # zsh word mode completion |
| 134 | _fasd_zsh_word_complete() { |
| 135 | [ "\$2" ] && local _fasd_cur="\$2" |
| 136 | [ -z "\$_fasd_cur" ] && local _fasd_cur="\${words[CURRENT]}" |
| 137 | local fnd="\${_fasd_cur//,/ }" |
| 138 | local typ=\${1:-e} |
| 139 | fasd --query \$typ \$fnd | sort -nr | sed 's/^[0-9.]*[ ]*//' | \ |
| 140 | while read line; do |
| 141 | compadd -U -V fasd "\$line" |
| 142 | done |
| 143 | compstate[insert]=menu # no expand |
| 144 | } |
| 145 | _fasd_zsh_word_complete_f() { _fasd_zsh_word_complete f ; } |
| 146 | _fasd_zsh_word_complete_d() { _fasd_zsh_word_complete d ; } |
| 147 | _fasd_zsh_word_complete_trigger() { |
| 148 | local _fasd_cur="\${words[CURRENT]}" |
| 149 | eval \$(fasd --word-complete-trigger _fasd_zsh_word_complete \$_fasd_cur) |
| 150 | } |
| 151 | # define zle widgets |
| 152 | zle -C fasd-complete 'menu-select' _fasd_zsh_word_complete |
| 153 | zle -C fasd-complete-f 'menu-select' _fasd_zsh_word_complete_f |
| 154 | zle -C fasd-complete-d 'menu-select' _fasd_zsh_word_complete_d |
| 155 | |
| 156 | EOS |
| 157 | ;; |
| 158 | |
| 159 | zsh-ccomp-install) cat <<EOS |
| 160 | # enbale command mode completion |
| 161 | compctl -U -K _fasd_zsh_cmd_complete -V fasd -x 'C[-1,-*e],s[-]n[1,e]' -c - \ |
| 162 | 'c[-1,-A][-1,-D]' -f -- fasd fasd_cd |
| 163 | |
| 164 | EOS |
| 165 | ;; |
| 166 | |
| 167 | zsh-wcomp-install) cat <<EOS |
| 168 | # enable word mode completion |
| 169 | zstyle ':completion:*' completer _complete _ignored \ |
| 170 | _fasd_zsh_word_complete_trigger |
| 171 | |
| 172 | EOS |
| 173 | ;; |
| 174 | |
| 175 | bash-ccomp) cat <<EOS |
| 176 | # bash command mode completion |
| 177 | _fasd_bash_cmd_complete() { |
| 178 | # complete command after "-e" |
| 179 | local cur=\${COMP_WORDS[COMP_CWORD]} |
| 180 | [[ \${COMP_WORDS[COMP_CWORD-1]} == -*e ]] && \ |
| 181 | COMPREPLY=( \$(compgen -A command \$cur) ) && return |
| 182 | # complete using default readline complete after "-A" or "-D" |
| 183 | case \${COMP_WORDS[COMP_CWORD-1]} in |
| 184 | -A|-D) COMPREPLY=( \$(compgen -o default \$cur) ) && return |
| 185 | esac |
| 186 | # get completion results using expanded aliases |
| 187 | local RESULT=\$( fasd -q --complete "\$(alias -p \$COMP_WORDS \ |
| 188 | 2>> "$_FASD_SINK" | sed -n "\\\$s/^.*'\(.*\)'/\1/p") \${COMP_LINE#* }" ) |
| 189 | IFS=\$'\n' COMPREPLY=( \$RESULT ) |
| 190 | } |
| 191 | _fasd_bash_hook_cmd_complete() { |
| 192 | for cmd in \$*; do |
| 193 | complete -F _fasd_bash_cmd_complete \$cmd |
| 194 | done |
| 195 | } |
| 196 | |
| 197 | EOS |
| 198 | ;; |
| 199 | |
| 200 | bash-wcomp) cat <<EOS |
| 201 | # bash word mode completion |
| 202 | _fasd_bash_word_complete() { |
| 203 | [ "\$2" ] && local _fasd_cur="\$2" |
| 204 | [ "\$_fasd_cur" ] || local _fasd_cur="\${COMP_WORDS[COMP_CWORD]}" |
| 205 | local typ=\${1:-e} |
| 206 | local fnd="\${_fasd_cur//,/ }" |
| 207 | local RESULT=\$(fasd -q --query \$typ \$fnd | sed 's/^[0-9.]*[ ]*//') |
| 208 | IFS=\$'\n' COMPREPLY=( \$RESULT ) |
| 209 | } >> "$_FASD_SINK" 2>&1 |
| 210 | _fasd_bash_word_complete_trigger() { |
| 211 | [ "\$_fasd_cur" ] || local _fasd_cur="\${COMP_WORDS[COMP_CWORD]}" |
| 212 | eval "\$(fasd --word-complete-trigger _fasd_bash_word_complete \$_fasd_cur)" |
| 213 | } >> "$_FASD_SINK" 2>&1 |
| 214 | _fasd_bash_word_complete_wrap() { |
| 215 | local _fasd_cur="\${COMP_WORDS[COMP_CWORD]}" |
| 216 | _fasd_bash_word_complete_trigger |
| 217 | local z=\${COMP_WORDS[0]} |
| 218 | # try original comp func |
| 219 | [ "\$COMPREPLY" ] || eval "\$( echo "\$_FASD_BASH_COMPLETE_P" | \ |
| 220 | sed -n "/ \$z\$/"'s/.*-F \(.*\) .*/\1/p' )" |
| 221 | # fall back on original complete options |
| 222 | local cmd="\$(echo "\$_FASD_BASH_COMPLETE_P" | \ |
| 223 | sed -n "/ \$z\$/"'s/complete/compgen/') \$_fasd_cur" |
| 224 | [ "\$COMPREPLY" ] || COMPREPLY=( \$(eval \$cmd) ) |
| 225 | } >> "$_FASD_SINK" 2>&1 |
| 226 | |
| 227 | EOS |
| 228 | ;; |
| 229 | |
| 230 | bash-ccomp-install) cat <<EOS |
| 231 | # enable bash command mode completion |
| 232 | _fasd_bash_hook_cmd_complete fasd a s d f sd sf z |
| 233 | |
| 234 | EOS |
| 235 | ;; |
| 236 | |
| 237 | bash-wcomp-install) cat <<EOS |
| 238 | _FASD_BASH_COMPLETE_P="\$(complete -p)" |
| 239 | for cmd in \$(complete -p | awk '{print \$NF}' | tr '\n' ' '); do |
| 240 | complete -o default -o bashdefault -F _fasd_bash_word_complete_wrap \$cmd |
| 241 | done |
| 242 | # enable word mode completion as default completion |
| 243 | complete -o default -o bashdefault -D -F _fasd_bash_word_complete_trigger \ |
| 244 | >> "$_FASD_SINK" 2>&1 |
| 245 | |
| 246 | EOS |
| 247 | ;; |
| 248 | esac; shift |
| 249 | done |
| 250 | ;; |
| 251 | |
| 252 | --init-alias) |
| 253 | fasd --init posix-alias |
| 254 | ;; |
| 255 | |
| 256 | --init-zsh) |
| 257 | fasd --init zsh-hook zsh-ccomp zsh-ccomp-install zsh-wcomp zsh-wcomp-install |
| 258 | ;; |
| 259 | |
| 260 | --init-bash) |
| 261 | fasd --init bash-hook bash-ccomp bash-ccomp-install |
| 262 | ;; |
| 263 | |
| 264 | --init-posix) |
| 265 | fasd --init posix-hook |
| 266 | ;; |
| 267 | |
| 268 | # if "$_fasd_cur" is a query, then eval all the arguments |
| 269 | --word-complete-trigger) |
| 270 | shift; [ "$2" ] && local _fasd_cur="$2" || return |
| 271 | case "$_fasd_cur" in |
| 272 | ,*) echo "$1" e "$_fasd_cur";; |
| 273 | f,*) echo "$1" f "${_fasd_cur#?}";; |
| 274 | d,*) echo "$1" d "${_fasd_cur#?}";; |
| 275 | *,,) echo "$1" e "$_fasd_cur";; |
| 276 | *,,f) echo "$1" f "${_fasd_cur%?}";; |
| 277 | *,,d) echo "$1" d "${_fasd_cur%?}";; |
| 278 | esac |
| 279 | ;; |
| 280 | |
| 281 | --sanitize) |
| 282 | shift; echo "$@" | \ |
| 283 | sed 's/\([^\]\)$([^ ]*\([^)]*\)))*/\1\2/g;s/\([^\]\)[|&;<>$`]\{1,\}/\1 /g' |
| 284 | ;; |
| 285 | |
| 286 | --proc) shift # process commands |
| 287 | # stop if we don't own ~/.fasd (we're another user but our ENV is still set) |
| 288 | [ -f "$_FASD_DATA" -a ! -O "$_FASD_DATA" ] && return |
| 289 | |
| 290 | # make zsh do word splitting for the for loop to work |
| 291 | [ "$ZSH_VERSION" ] && emulate sh && setopt localoptions |
| 292 | |
| 293 | # blacklists |
| 294 | local each; for each in $_FASD_BLACKLIST; do |
| 295 | case " $* " in *\ $each\ *) return;; esac |
| 296 | done |
| 297 | |
| 298 | # shifts |
| 299 | while true; do |
| 300 | case " $_FASD_SHIFT " in |
| 301 | *\ $1\ *) shift;; |
| 302 | *) break |
| 303 | esac |
| 304 | done |
| 305 | |
| 306 | # ignores |
| 307 | case " $_FASD_IGNORE " in |
| 308 | *\ $1\ *) return |
| 309 | esac |
| 310 | |
| 311 | shift; fasd --add "$@" # add all arguments except command |
| 312 | ;; |
| 313 | |
| 314 | --add|-A) shift # add entries |
| 315 | # find all valid path arguments, convert them to simplest absolute form |
| 316 | local paths="$(while [ "$1" ]; do |
| 317 | [ -e "$1" ] && echo "$1"; shift |
| 318 | done | sed '/^[^/]/s@^@'"$PWD"'/@ |
| 319 | s@/\.\.$@/\.\./@;s@/\(\./\)\{1,\}@/@g;: 0;s@[^/][^/]*//*\.\./@/@;t 0 |
| 320 | s@^/*\.\./@/@;s@//*@/@g;s@/\.\{0,1\}$@@;s@^$@/@' | tr '\n' '|')" |
| 321 | |
| 322 | # add current pwd if the option is set |
| 323 | [ "$_FASD_TRACK_PWD" = "1" -a "$PWD" != "$HOME" ] && paths="$paths|$PWD" |
| 324 | |
| 325 | [ -z "${paths##\|}" ] && return # stop if we have nothing to add |
| 326 | |
| 327 | # maintain the file |
| 328 | local tempfile |
| 329 | tempfile="$(mktemp "$_FASD_DATA".XXXXXX)" || return |
| 330 | $_FASD_AWK -v list="$paths" -v now="$(date +%s)" -v max="$_FASD_MAX" -F"|" ' |
| 331 | BEGIN { |
| 332 | split(list, files, "|") |
| 333 | for(i in files) { |
| 334 | path = files[i] |
| 335 | if(path == "") continue |
| 336 | paths[path] = path # array for checking |
| 337 | rank[path] = 1 |
| 338 | time[path] = now |
| 339 | } |
| 340 | } |
| 341 | $2 >= 1 { |
| 342 | if($1 in paths) { |
| 343 | rank[$1] = $2 + 1 |
| 344 | time[$1] = now |
| 345 | } else { |
| 346 | rank[$1] = $2 |
| 347 | time[$1] = $3 |
| 348 | } |
| 349 | count += $2 |
| 350 | } |
| 351 | END { |
| 352 | if(count > max) |
| 353 | for(i in rank) print i "|" 0.9*rank[i] "|" time[i] # aging |
| 354 | else |
| 355 | for(i in rank) print i "|" rank[i] "|" time[i] |
| 356 | }' "$_FASD_DATA" 2>> "$_FASD_SINK" >| "$tempfile" |
| 357 | if [ $? -ne 0 -a -f "$_FASD_DATA" ]; then |
| 358 | env rm -f "$tempfile" |
| 359 | else |
| 360 | env mv -f "$tempfile" "$_FASD_DATA" |
| 361 | fi |
| 362 | ;; |
| 363 | |
| 364 | --delete|-D) shift # delete entries |
| 365 | # turn valid arguments into entry-deleting sed commands |
| 366 | local sed_cmd="$(while [ "$1" ]; do echo "$1"; shift; done | \ |
| 367 | sed '/^[^/]/s@^@'"$PWD"'/@;s@/\.\.$@/\.\./@;s@/\(\./\)\{1,\}@/@g |
| 368 | : 0;s@[^/][^/]*//*\.\./@/@;t 0;s@^/*\.\./@/@;s@//*@/@g;s@/\.\{0,1\}$@@ |
| 369 | s@^$@/@;s@\([.[/*^$]\)@\\\1@g;s@^\(.*\)$@/^\1|/d@')" |
| 370 | |
| 371 | # maintain the file |
| 372 | local tempfile |
| 373 | tempfile="$(mktemp "$_FASD_DATA".XXXXXX)" || return |
| 374 | |
| 375 | sed -e "$sed_cmd" "$_FASD_DATA" 2>> "$_FASD_SINK" >| "$tempfile" |
| 376 | |
| 377 | if [ $? -ne 0 -a -f "$_FASD_DATA" ]; then |
| 378 | env rm -f "$tempfile" |
| 379 | else |
| 380 | env mv -f "$tempfile" "$_FASD_DATA" |
| 381 | fi |
| 382 | ;; |
| 383 | |
| 384 | --query) shift # query the db, --query [$typ ["$fnd" [$mode [$quote]]]] |
| 385 | [ -f "$_FASD_DATA" ] || return # no db yet |
| 386 | [ "$1" ] && local typ="$1" |
| 387 | [ "$2" ] && local fnd="$2" |
| 388 | [ "$3" ] && local mode="$3" |
| 389 | [ "$4" ] && local quote="$4" |
| 390 | [ "$quote" ] && local qts='"\""' || local qts= |
| 391 | |
| 392 | # make zsh do word spliting for the for loop to work |
| 393 | [ "$ZSH_VERSION" ] && emulate sh && setopt localoptions |
| 394 | |
| 395 | # cat all backends |
| 396 | local each _fasd_data; for each in $_FASD_BACKENDS; do |
| 397 | _fasd_data="$_fasd_data |
| 398 | $(fasd --backend $each)" |
| 399 | done |
| 400 | [ "$_fasd_data" ] || _fasd_data="$(cat "$_FASD_DATA")" |
| 401 | |
| 402 | # set mode specific code for calculating the prior |
| 403 | case $mode in |
| 404 | rank) local prior='times[i]';; |
| 405 | recent) local prior='sqrt(100000/(1+t-la[i]))';; |
| 406 | *) local prior='times[i] * frecent(la[i])';; |
| 407 | esac |
| 408 | |
| 409 | # query the database |
| 410 | echo "$_fasd_data" | while read line; do |
| 411 | [ -${typ:-e} "${line%%\|*}" ] && echo "$line" |
| 412 | done | $_FASD_AWK -v t="$(date +%s)" -v q="$fnd" -F"|" ' |
| 413 | function frecent(time) { |
| 414 | dx = t-time |
| 415 | if( dx < 3600 ) return 6 |
| 416 | if( dx < 86400 ) return 4 |
| 417 | if( dx < 604800 ) return 2 |
| 418 | return 1 |
| 419 | } |
| 420 | function likelihood(pattern, path) { |
| 421 | m = gsub("/+", "/", path) |
| 422 | r = 1 |
| 423 | for(i in pattern) { |
| 424 | tmp = path |
| 425 | gsub(".*" pattern[i], "", tmp) |
| 426 | n = gsub("/+", "/", tmp) |
| 427 | if(n == m) |
| 428 | return 0 |
| 429 | else if(n == 0) |
| 430 | r *= 20 # F |
| 431 | else |
| 432 | r *= 1 - (n / m) |
| 433 | } |
| 434 | return r |
| 435 | } |
| 436 | BEGIN { |
| 437 | split(q, pattern, " ") |
| 438 | for(i in pattern) pattern_lower[i] = tolower(pattern[i]) # nocase |
| 439 | } |
| 440 | { |
| 441 | if(!wcase[$1]) { |
| 442 | times[$1] = $2 |
| 443 | la[$1] = $3 |
| 444 | wcase[$1] = likelihood(pattern, $1) |
| 445 | if(!cx) nocase[$1] = likelihood(pattern_lower, tolower($1)) |
| 446 | } else { |
| 447 | times[$1] += $2 |
| 448 | if($3 > la[$1]) la[$1] = $3 |
| 449 | } |
| 450 | cx = cx || wcase[$1] |
| 451 | ncx = ncx || nocase[$1] |
| 452 | } |
| 453 | END { |
| 454 | if(cx) { |
| 455 | for(i in wcase) { |
| 456 | if(wcase[i]) |
| 457 | printf "%-10s %s\n", '"$prior"' * wcase[i], '"$qts"' i '"$qts"' |
| 458 | } |
| 459 | } else if(ncx) { |
| 460 | for(i in nocase) { |
| 461 | if(nocase[i]) |
| 462 | printf "%-10s %s\n", '"$prior"' * nocase[i], '"$qts"' i '"$qts"' |
| 463 | } |
| 464 | } |
| 465 | }' - 2>> "$_FASD_SINK" |
| 466 | ;; |
| 467 | |
| 468 | --backend) |
| 469 | case $2 in |
| 470 | native) cat "$_FASD_DATA";; |
| 471 | viminfo) |
| 472 | local t="$(date +%s)" |
| 473 | < "$HOME/.viminfo" sed -n '/^>/{s@~@'"$HOME"'@;p}' | \ |
| 474 | while IFS=" " read line; do |
| 475 | t=$((t-60)); echo "${line#??}|1|$t" |
| 476 | done |
| 477 | ;; |
| 478 | recently-used) |
| 479 | tr -d '\n' < "$HOME/.local/share/recently-used.xbel" | \ |
| 480 | sed 's@file:/@\n@g;s@count="@\n@g' | sed '1d;s/".*$//' | \ |
| 481 | tr '\n' '|' | sed 's@|/@\n@g' | $_FASD_AWK -F'|' '{ |
| 482 | sum = 0 |
| 483 | for( i=2; i<=NF; i++ ) sum += $i |
| 484 | print $1 "|" sum |
| 485 | }' |
| 486 | ;; |
| 487 | *) eval "$2";; |
| 488 | esac |
| 489 | ;; |
| 490 | |
| 491 | *) # parsing logic and processing |
| 492 | local fnd last _FASD_BACKENDS="$_FASD_BACKENDS" _fasd_data |
| 493 | while [ "$1" ]; do case "$1" in |
| 494 | --complete) [ "$2" = "--" ] && shift; set -- $(echo $2); local lst=1 r=r;; |
| 495 | --query|--add|--delete|-A|-D) fasd "$@"; return $?;; |
| 496 | --version) echo "0.5.4"; return 0;; |
| 497 | --) while [ "$2" ]; do shift; fnd="$fnd$1 "; last="$1"; done;; |
| 498 | -*) local o="${1#-}"; while [ "$o" ]; do case "$o" in |
| 499 | s*) local show=1;; |
| 500 | l*) local lst=1;; |
| 501 | i*) local interactive=1 show=1;; |
| 502 | r*) local mode=rank;; |
| 503 | t*) local mode=recent;; |
| 504 | e*) o="${o#?}"; if [ "$o" ]; then # there are characters after "-e" |
| 505 | local exec="$o" # anything after "-e" |
| 506 | else # use the next argument |
| 507 | local exec="${2:?"-e: Argument needed "}" |
| 508 | shift |
| 509 | fi; break;; |
| 510 | b*) o="${o#?}"; if [ "$o" ]; then |
| 511 | _FASD_BACKENDS="$o" |
| 512 | else |
| 513 | _FASD_BACKENDS="${2:?"-b: Argument needed"}" |
| 514 | shift |
| 515 | fi; break;; |
| 516 | B*) o="${o#?}"; if [ "$o" ]; then |
| 517 | _FASD_BACKENDS="$_FASD_BACKENDS $o" |
| 518 | else |
| 519 | _FASD_BACKENDS="$_FASD_BACKENDS ${2:?"-B: Argument needed"}" |
| 520 | shift |
| 521 | fi; break;; |
| 522 | a*) local typ=e;; |
| 523 | d*) local typ=d;; |
| 524 | f*) local typ=f;; |
| 525 | q*) local quote=1;; |
| 526 | h*) echo "fasd [options] [query ...] |
| 527 | [f|a|s|d|z] [opions] [query ...] |
| 528 | options: |
| 529 | -s show list of files with their ranks |
| 530 | -l list paths only |
| 531 | -i interactive mode |
| 532 | -e <cmd> set command to execute on the result file |
| 533 | -b <name> only use <name> backend |
| 534 | -b <name> add additional backend <name> |
| 535 | -a match files and directories |
| 536 | -d match directories only |
| 537 | -f match files only |
| 538 | -r match by rank only |
| 539 | -t match by recent access only |
| 540 | -h show a brief help message |
| 541 | |
| 542 | fasd [-A|-D] [paths ...] |
| 543 | -A add paths |
| 544 | -D delete paths" >&2; return;; |
| 545 | esac; o="${o#?}"; done;; |
| 546 | *) fnd="$fnd $1"; last="$1";; |
| 547 | esac; shift; done |
| 548 | |
| 549 | # if we hit enter on a completion just execute |
| 550 | case "$last" in |
| 551 | # completions will always start with / |
| 552 | /*) [ -z "$show$lst" -a -${typ:-e} "$last" -a "$exec" ] \ |
| 553 | && eval $exec "\"$last\"" && return;; |
| 554 | esac |
| 555 | |
| 556 | local result |
| 557 | result="$(fasd --query 2>> "$_FASD_SINK")" # query the database |
| 558 | [ $? -gt 0 ] && return |
| 559 | if [ "$interactive" ] || [ "$exec" -a -z "$fnd$lst$show" -a -t 1 ]; then |
| 560 | result="$(echo "$result" | sort -nr)" |
| 561 | echo "$result" | sed = | sed 'N;s/\n/ /' | sort -nr >&2; printf "> " >&2 |
| 562 | local i; read i; [ 0 -lt "${i:-0}" ] 2>> "$_FASD_SINK" || return 1 |
| 563 | result="$(echo "$result" | sed -n "${i:-1}"'s/^[0-9.]*[ ]*//p')" |
| 564 | if [ "$result" ]; then |
| 565 | fasd --add "$result"; eval ${exec:-echo} "\"$result\"" |
| 566 | fi |
| 567 | elif [ "$lst" ]; then |
| 568 | echo "$result" | sort -n${r} | sed 's/^[0-9.]*[ ]*//' |
| 569 | elif [ "$show" ]; then |
| 570 | echo "$result" | sort -n |
| 571 | elif [ "$fnd" -a "$exec" ]; then # exec |
| 572 | result="$(echo "$result" | sort -n | sed -n '$s/^[0-9.]*[ ]*//p')" |
| 573 | fasd --add "$result"; eval $exec "\"$result\"" |
| 574 | elif [ "$fnd" -a ! -t 1 ]; then # echo if output is not terminal |
| 575 | result="$(echo "$result" | sort -n | sed -n '$s/^[0-9.]*[ ]*//p')" |
| 576 | fasd --add "$result"; echo "$result" |
| 577 | else # no args, show |
| 578 | echo "$result" | sort -n |
| 579 | fi |
| 580 | |
| 581 | esac |
| 582 | } |
| 583 | |
| 584 | fasd --init env |
| 585 | |
| 586 | case $- in |
Erich Smith | b9e985b | 2012-05-07 12:57:23 -0400 | [diff] [blame^] | 587 | *i*) alias fasd='~/.bash_it/plugins/enabled/fasd.bash' |
Erich Smith | 3e76d67 | 2012-05-07 09:56:36 -0400 | [diff] [blame] | 588 | eval "$(fasd --init auto)" |
| 589 | ;; |
| 590 | *) # assume being executed as an executable |
| 591 | if [ -x "$_FASD_SHELL" -a -z "$_FASD_SET" ]; then |
| 592 | _FASD_SET=1 exec $_FASD_SHELL "$0" "$@" |
| 593 | else |
| 594 | fasd "$@" |
| 595 | fi |
| 596 | esac |
| 597 | |