#!/bin/bash

# Usage: ack-grep [OPTION]... PATTERN [FILES OR DIRECTORIES]
# 
# The following is the list of filetypes supported by ack-grep.  You can
# specify a file type with the --type=TYPE format, or the --TYPE
# format.  For example, both --type=perl and --perl work.
# 
# Note that some extensions may appear in multiple types.  For example,
# .pod files are both Perl and Parrot.
# 
#     --[no]actionscript .as .mxml
#     --[no]ada          .ada .adb .ads
#     --[no]asm          .asm .s
#     --[no]asp          .asp
#     --[no]aspx         .master .ascx .asmx .aspx .svc
#     --[no]batch        .bat .cmd
#     --[no]cc           .c .h .xs
#     --[no]cfmx         .cfc .cfm .cfml
#     --[no]clojure      .clj
#     --[no]cmake        CMakeLists.txt; .cmake
#     --[no]coffeescript .coffee
#     --[no]cpp          .cpp .cc .cxx .m .hpp .hh .h .hxx
#     --[no]csharp       .cs
#     --[no]css          .css
#     --[no]dart         .dart
#     --[no]delphi       .pas .int .dfm .nfm .dof .dpk .dproj .groupproj .bdsgroup .bdsproj
#     --[no]elisp        .el
#     --[no]elixir       .ex .exs
#     --[no]erlang       .erl .hrl
#     --[no]fortran      .f .f77 .f90 .f95 .f03 .for .ftn .fpp
#     --[no]go           .go
#     --[no]groovy       .groovy .gtmpl .gpp .grunit .gradle
#     --[no]haskell      .hs .lhs
#     --[no]hh           .h
#     --[no]html         .htm .html
#     --[no]java         .java .properties
#     --[no]js           .js
#     --[no]json         .json
#     --[no]jsp          .jsp .jspx .jhtm .jhtml
#     --[no]less         .less
#     --[no]lisp         .lisp .lsp
#     --[no]lua          .lua; first line matches /^#!.*\blua(jit)?/
#     --[no]make         .mk; .mak; makefile; Makefile; GNUmakefile
#     --[no]matlab       .m
#     --[no]objc         .m .h
#     --[no]objcpp       .mm .h
#     --[no]ocaml        .ml .mli
#     --[no]parrot       .pir .pasm .pmc .ops .pod .pg .tg
#     --[no]perl         .pl .pm .pod .t .psgi; first line matches /^#!.*\bperl/
#     --[no]perltest     .t
#     --[no]php          .php .phpt .php3 .php4 .php5 .phtml; first line matches /^#!.*\bphp/
#     --[no]plone        .pt .cpt .metadata .cpy .py
#     --[no]python       .py; first line matches /^#!.*\bpython/
#     --[no]rake         Rakefile
#     --[no]rr           .R
#     --[no]ruby         .rb .rhtml .rjs .rxml .erb .rake .spec; Rakefile; first line matches /^#!.*\bruby/
#     --[no]rust         .rs
#     --[no]sass         .sass .scss
#     --[no]scala        .scala
#     --[no]scheme       .scm .ss
#     --[no]shell        .sh .bash .csh .tcsh .ksh .zsh .fish; first line matches /^#!.*\b(?:ba|t?c|k|z|fi)?sh\b/
#     --[no]smalltalk    .st
#     --[no]sql          .sql .ctl
#     --[no]tcl          .tcl .itcl .itk
#     --[no]tex          .tex .cls .sty
#     --[no]tt           .tt .tt2 .ttml
#     --[no]vb           .bas .cls .frm .ctl .vb .resx
#     --[no]verilog      .v .vh .sv
#     --[no]vhdl         .vhd .vhdl
#     --[no]vim          .vim
#     --[no]xml          .xml .dtd .xsl .xslt .ent; first line matches /<[?]xml/
#     --[no]yaml         .yaml .yml

source_files='CMakeLists.txt makefile Makefile GNUmakefile Rakefile'
source_suffixes='
  .as .mxml
  .ada .adb .ads
  .asm .s
  .asp
  .master .ascx .asmx .aspx .svc
  .bat .cmd
  .c .h .xs
  .cfc .cfm .cfml
  .clj
  .cmake
  .coffee
  .cpp .cc .cxx .m .hpp .hh .h .hxx
  .cs
  .css
  .dart
  .pas .int .dfm .nfm .dof .dpk .dproj .groupproj .bdsgroup .bdsproj
  .el
  .ex .exs
  .erl .hrl
  .f .f77 .f90 .f95 .f03 .for .ftn .fpp
  .go
  .groovy .gtmpl .gpp .grunit .gradle
  .hs .lhs
  .h
  .htm .html
  .java .properties
  .js
  .json
  .jsp .jspx .jhtm .jhtml
  .less
  .lisp .lsp
  .lua
  .mk .mak 
  .m
  .m .h
  .mm .h
  .ml .mli
  .pir .pasm .pmc .ops .pod .pg .tg
  .pl .pm .pod .t .psgi
  .t
  .php .phpt .php3 .php4 .php5 .phtml
  .pt .cpt .metadata .cpy .py
  .py
  .R
  .rb .rhtml .rjs .rxml .erb .rake .spec
  .rs
  .sass .scss
  .scala
  .scm .ss
  .sh .bash .csh .tcsh .ksh .zsh .fish
  .st
  .sql .ctl
  .tcl .itcl .itk
  .tex .cls .sty
  .tt .tt2 .ttml
  .bas .cls .frm .ctl .vb .resx
  .v .vh .sv
  .vhd .vhdl
  .vim
  .xml .dtd .xsl .xslt .ent
  .yaml .yml'

source_suffixes=$(printf '%s\n' $source_suffixes | sort | uniq)

bold=$(tput bold)
yellow=$(tput setf 6)
standout=$(tput smso)
norm=$(tput sgr0)

rx_escape ()
{
  local escape_char=${2:-/}
  printf '%s' "${1//$escape_char/\\$escape_char}"
}

rx=$1
shift

egrep 2>/dev/null -Ilre "${rx:?Usage: ${0##*/} EXTENDED_REGEXP [FILE_OR_DIR ...]}" \
    $(printf ' --include=*%s' ${source_suffixes}) \
    $(printf ' --include=%s' ${source_files}) \
    --color "${@:-.}" |
  sed 's,^\./,,' |
  while read -r file
  do
    printf '%s%s%s\n' "$bold" "$file" "$norm"
    egrep 2>/dev/null -ne "$rx" "$file" |
      sed -r '
        # line numbers
        s/^([0-9]+):/'"$yellow"'\1'"$norm"':/

        # matches
        s/('"$(rx_escape "$rx")"')/'"$standout"'\1'"$norm"'/g'
    echo
  done
