No Description
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.

fv 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #!/usr/bin/env bash
  2. usage() {
  3. LESS=-FEXR less <<'HELP'
  4. fv [OPTIONS] [SEARCH]
  5. fuzzy file filtering and command executing
  6. a) allfiles=1 ;;
  7. c) cmd="$OPTARG" ;;
  8. d) dtach=1 ;;
  9. o) loop=1 ;;
  10. s) small=1 ;;
  11. -a search all dirs and hidden files (possibly quirky)
  12. -c command to execute [defaults to vim]
  13. -d run in background (for ie non-terminal programs)
  14. -h show this help
  15. -l additional arguments to pass to filtering program
  16. -o run continuously
  17. -s run in a smaller window
  18. HELP
  19. }
  20. declare cmd=''
  21. declare cmdopts=()
  22. declare search_str=''
  23. declare search_cmd=''
  24. declare search_opts=()
  25. declare allfiles=''
  26. declare loop
  27. declare small
  28. declare -A colors
  29. colors[red]=$(tput setaf 1)
  30. colors[green]=$(tput setaf 2)
  31. colors[blue]=$(tput setaf 4)
  32. colors[reset]=$(tput sgr0)
  33. color() {
  34. local c
  35. c="$1"
  36. shift
  37. printf '%s' "${colors[$c]}"
  38. printf '%s\n' "$@"
  39. printf '%s' "${colors[reset]}"
  40. }
  41. err() {
  42. color red "$@" >&2
  43. }
  44. die() {
  45. [[ -n "$1" ]] && err "$1"
  46. exit 1
  47. }
  48. has() {
  49. local o c verbose
  50. verbose=0
  51. while getopts 'v' o; do
  52. case "$o" in
  53. v) v=1 ;;
  54. esac
  55. done
  56. shift "$((OPTIND-1))"
  57. for c; do c="${c%% *}"
  58. if ! command -v "$c" &> /dev/null; then
  59. (( verbose > 0 )) && err "$c not found"
  60. return 1
  61. fi
  62. done
  63. }
  64. select_from() {
  65. local o c cmd OPTARG OPTIND
  66. cmd='command -v'
  67. while getopts 'c:' o; do
  68. case "$o" in
  69. c) cmd="$OPTARG" ;;
  70. esac
  71. done
  72. shift "$((OPTIND-1))"
  73. for c; do
  74. if $cmd "${c%% *}" &> /dev/null; then
  75. echo "$c"
  76. return 0
  77. fi
  78. done
  79. return 1
  80. }
  81. while getopts 'ac:dhlos' opt; do
  82. case "$opt" in
  83. a) allfiles=1 ;;
  84. c) cmd="$OPTARG" ;;
  85. d) dtach=1 ;;
  86. h) usage; exit 0 ;;
  87. l) search_opts+=( '-l' ) ;;
  88. o) loop=1 ;;
  89. s) small=1 ;;
  90. esac
  91. done
  92. shift "$((OPTIND-1))"
  93. has -v 'fzf' || die
  94. if [[ -v FV_CMD ]]; then
  95. cmd="$FV_CMD"
  96. elif [[ -z "$cmd" ]]; then
  97. cmd=$(select_from 'v' 'vim')
  98. fi
  99. if [[ -v FV_SEARCH ]]; then
  100. search_cmd="$FV_SEARCH"
  101. else
  102. search_cmd=$(select_from 'ag' 'ack' 'grep')
  103. fi
  104. if [[ "$search_cmd" == 'grep' ]]; then
  105. err 'grep is slow, you should strongly consider installing ag or ack'
  106. sleep .75
  107. fi
  108. if [[ -n "$1" ]]; then
  109. if [[ -e "$1" ]]; then
  110. search_opts+=( "$1" )
  111. else
  112. search_str="$1"
  113. fi
  114. shift
  115. fi
  116. case "$search_cmd" in
  117. 'ag')
  118. search_opts+=( '--color' )
  119. if [[ -n "$allfiles" ]]; then
  120. search_opts+=( '-u' '--hidden' )
  121. fi
  122. if [[ "$search_str" == '' ]]; then
  123. search_opts+=( '-l' )
  124. fi ;;
  125. 'ack')
  126. if [[ "$search_str" == '' ]]; then
  127. if [[ -z "$allfiles" ]]; then
  128. search_opts+=( '-f' )
  129. else
  130. search_opts+=( '-g' '^[^\.]' )
  131. fi
  132. else
  133. search_opts+=( '-l' )
  134. # search_opts+=( '--match' )
  135. fi ;;
  136. 'grep')
  137. search_opts+=( '-r' '-I' )
  138. if [[ -z "$allfiles" ]]; then
  139. if [[ -r ~/.ignore ]]; then
  140. while read -r line; do
  141. search_opts+=( "--exclude-dir=$line" )
  142. done < ~/.ignore
  143. else
  144. search_opts+=( '--exclude-dir=bower_components' )
  145. search_opts+=( '--exclude-dir=node_modules' )
  146. search_opts+=( '--exclude-dir=jspm_packages' )
  147. search_opts+=( '--exclude-dir=.cvs' )
  148. search_opts+=( '--exclude-dir=.git' )
  149. search_opts+=( '--exclude-dir=.hg' )
  150. search_opts+=( '--exclude-dir=.svn' )
  151. fi
  152. fi
  153. if [[ -z "$search_str" ]]; then
  154. search_opts+=( -F '' )
  155. else
  156. search_opts+=( -P )
  157. fi ;;
  158. esac
  159. if [[ "$search_str" != '' ]]; then
  160. search_opts+=( "$search_str" )
  161. fi
  162. main() {
  163. choices=$($search_cmd "${search_opts[@]}" 2> /dev/null |
  164. fzf --ansi --multi --preview='[[ $(file -b {}) = *text* ]] && highlight -q --force -O ansi {}') || exit 1
  165. if [[ "$search_str" != '' ]]; then
  166. if [[ $search_cmd == 'ag' ]]; then
  167. choices=$(cut -d: -f1 <<< "$choices")
  168. fi
  169. fi
  170. mapfile -t choices <<< "$choices"
  171. if [[ $dtach ]]; then
  172. ($cmd "${cmdopts[@]}" "${choices[@]}" &> /dev/null &)
  173. else
  174. $cmd "${cmdopts[@]}" "${choices[@]}"
  175. fi
  176. }
  177. if [[ -n "$loop" ]]; then
  178. while main; do
  179. true
  180. done
  181. else
  182. main
  183. fi