123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- #!/usr/bin/env bash
-
- usage() {
- LESS=-FEXR less <<'HELP'
- fv [OPTIONS] [SEARCH]
- fuzzy file filtering and command executing
-
- a) allfiles=1 ;;
- c) cmd="$OPTARG" ;;
- d) dtach=1 ;;
- o) loop=1 ;;
- s) small=1 ;;
-
- -a search all dirs and hidden files (possibly quirky)
- -c command to execute [defaults to vim]
- -d run in background (for ie non-terminal programs)
- -h show this help
- -l additional arguments to pass to filtering program
- -o run continuously
- -s run in a smaller window
- HELP
- }
-
- declare cmd=''
- declare cmdopts=()
- declare search_str=''
- declare search_cmd=''
- declare search_opts=()
- declare allfiles=''
- declare loop
- declare small
- declare -A colors
- colors[red]=$(tput setaf 1)
- colors[green]=$(tput setaf 2)
- colors[blue]=$(tput setaf 4)
- colors[reset]=$(tput sgr0)
-
- color() {
- local c
- c="$1"
- shift
- printf '%s' "${colors[$c]}"
- printf '%s\n' "$@"
- printf '%s' "${colors[reset]}"
- }
-
- err() {
- color red "$@" >&2
- }
-
- die() {
- [[ -n "$1" ]] && err "$1"
- exit 1
- }
-
- has() {
- local o c verbose
- verbose=0
- while getopts 'v' o; do
- case "$o" in
- v) v=1 ;;
- esac
- done
- shift "$((OPTIND-1))"
- for c; do c="${c%% *}"
- if ! command -v "$c" &> /dev/null; then
- (( verbose > 0 )) && err "$c not found"
- return 1
- fi
- done
- }
-
- select_from() {
- local o c cmd OPTARG OPTIND
- cmd='command -v'
- while getopts 'c:' o; do
- case "$o" in
- c) cmd="$OPTARG" ;;
- esac
- done
- shift "$((OPTIND-1))"
- for c; do
- if $cmd "${c%% *}" &> /dev/null; then
- echo "$c"
- return 0
- fi
- done
- return 1
- }
-
- while getopts 'ac:dhlos' opt; do
- case "$opt" in
- a) allfiles=1 ;;
- c) cmd="$OPTARG" ;;
- d) dtach=1 ;;
- h) usage; exit 0 ;;
- l) search_opts+=( '-l' ) ;;
- o) loop=1 ;;
- s) small=1 ;;
- esac
- done
- shift "$((OPTIND-1))"
-
- has -v 'fzf' || die
-
- if [[ -v FV_CMD ]]; then
- cmd="$FV_CMD"
- elif [[ -z "$cmd" ]]; then
- cmd=$(select_from 'v' 'vim')
- fi
-
-
- if [[ -v FV_SEARCH ]]; then
- search_cmd="$FV_SEARCH"
- else
- search_cmd=$(select_from 'ag' 'ack' 'grep')
- fi
-
- if [[ "$search_cmd" == 'grep' ]]; then
- err 'grep is slow, you should strongly consider installing ag or ack'
- sleep .75
- fi
-
- if [[ -n "$1" ]]; then
- if [[ -e "$1" ]]; then
- search_opts+=( "$1" )
- else
- search_str="$1"
- fi
- shift
- fi
-
- case "$search_cmd" in
- 'ag')
- search_opts+=( '--color' )
- if [[ -n "$allfiles" ]]; then
- search_opts+=( '-u' '--hidden' )
- fi
- if [[ "$search_str" == '' ]]; then
- search_opts+=( '-l' )
- fi ;;
- 'ack')
- if [[ "$search_str" == '' ]]; then
- if [[ -z "$allfiles" ]]; then
- search_opts+=( '-f' )
- else
- search_opts+=( '-g' '^[^\.]' )
- fi
- else
- search_opts+=( '-l' )
- # search_opts+=( '--match' )
- fi ;;
- 'grep')
- search_opts+=( '-r' '-I' )
- if [[ -z "$allfiles" ]]; then
- if [[ -r ~/.ignore ]]; then
- while read -r line; do
- search_opts+=( "--exclude-dir=$line" )
- done < ~/.ignore
- else
- search_opts+=( '--exclude-dir=bower_components' )
- search_opts+=( '--exclude-dir=node_modules' )
- search_opts+=( '--exclude-dir=jspm_packages' )
- search_opts+=( '--exclude-dir=.cvs' )
- search_opts+=( '--exclude-dir=.git' )
- search_opts+=( '--exclude-dir=.hg' )
- search_opts+=( '--exclude-dir=.svn' )
- fi
- fi
- if [[ -z "$search_str" ]]; then
- search_opts+=( -F '' )
- else
- search_opts+=( -P )
- fi ;;
- esac
-
- if [[ "$search_str" != '' ]]; then
- search_opts+=( "$search_str" )
- fi
-
- main() {
- choices=$($search_cmd "${search_opts[@]}" 2> /dev/null |
- fzf --ansi --multi --preview='[[ $(file -b {}) = *text* ]] && highlight -q --force -O ansi {}') || exit 1
-
- if [[ "$search_str" != '' ]]; then
- if [[ $search_cmd == 'ag' ]]; then
- choices=$(cut -d: -f1 <<< "$choices")
- fi
- fi
-
- mapfile -t choices <<< "$choices"
-
- if [[ $dtach ]]; then
- ($cmd "${cmdopts[@]}" "${choices[@]}" &> /dev/null &)
- else
- $cmd "${cmdopts[@]}" "${choices[@]}"
- fi
- }
-
- if [[ -n "$loop" ]]; then
- while main; do
- true
- done
- else
- main
- fi
|