|
|
|
#!/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() {
|
|
|
|
local highlight
|
|
|
|
highlight=$(select_from 'bat --color=always --style=header' 'highlight -q --force -O ansi')
|
|
|
|
choices=$($search_cmd "${search_opts[@]}" 2> /dev/null |
|
|
|
|
fzf --ansi --multi --preview="[[ \$(file -ib {}) = *text* ]] && ${highlight} {}") || 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
|