You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
208 lines
4.1 KiB
208 lines
4.1 KiB
#!/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
|
|
|