fuzzy option to replace typos
[git-grep-footer.git] / git-grep-footer
index ff279a606bc2ad4cc8545b1e2e14f039b23550ce..0c26549197cfddfa4eeb8e511edd4aab1134dcde 100755 (executable)
@@ -9,8 +9,10 @@ use Getopt::Long qw(:config bundling);
 
 GetOptions(\my %opt,
        'debug!',
+       'count|c!',
        'simplify|s:s',
        'ignore-case|i!',
+       'fuzzy!',
        'min|min-count|unique|u:i',
        'max|max-count|show|n:i',
        'version|V'  => sub { Getopt::Long::VersionMessage() },
@@ -23,6 +25,8 @@ local $/ = "\0";
 
 my $HEADERMATCH = qr/ [a-z]+ (?: (?:-\w+)+ | \ by ) /ix;
 
+my (%headercount, @headercache);
+
 while (readline) {
        s/(.+)\n//m;
        my $hash = $1;
@@ -59,6 +63,18 @@ while (readline) {
 
                        push @header, $_ if defined $opt{max};
 
+                       if ($opt{fuzzy}) {
+                               for ($header[0]) {
+                                       tr/ _/-/;
+
+                                       state $BY = qr{ (?: -? b[yu] )? \Z }ix;
+                                       s{^ si (?:ge?n|n?g) (?:e?[dt])? -? (?:of+)? $BY}{Signed-off-by}ix;
+                                       s{^ ack (?:ed|de)?  $BY}{Acked-by}ix;
+                                       s{^ review (?:e?d)? $BY}{Reviewed-by}ix;
+                                       s{^ teste[dt]       $BY}{Tested-by}ix;
+                               }
+                       }
+
                        given ($opt{simplify} // 'none') {
                                when (['email', 'authors']) {
                                        $header[1] =~ s{
@@ -76,7 +92,8 @@ while (readline) {
                                                s{\b (https?)://\S+ }{[$1]}gmsx;  # url
                                                s{(?: < | \A ) [^@>\s]+ @ [^>]+ (?: > | \Z )}{<...>}igmsx;  # address
                                                s{\b [0-9]+ \b}{[num]}gmsx;  # number
-                                               s{\b I? [0-9a-f]{40} \b}{[sha1]}gmsx;  # hash
+                                               s{\b [Ig]? [0-9a-f]{  40} \b}{[sha1]}gmsx;  # hash
+                                               s{\b [Ig]? [0-9a-f]{6,40} \b}{[hash]}gmsx;  # abbrev
                                        }
                                }
                                when (['all', 'contents']) {
@@ -105,19 +122,28 @@ while (readline) {
                }
 
                for (@headers) {
+                       my $line = $_->[2] // join(': ', @$_);
                        if (defined $opt{min} or $opt{max}) {
-                               state $seen;
-                               my $count = $seen->{ $_->[0] }->{ $_->[1] // '' }++;
-                               next if $count >= ($opt{min} // 0) + ($opt{max} || 1);
-                               next if $count < ($opt{min} // 0);
+                               my $counter = \$headercount{ $_->[0] }->{ $_->[1] // '' };
+                               my $excess = $$counter++ - ($opt{min} // 0);
+                               next if $excess >= ($opt{max} || 1);
+                               next if $excess <  0;
+                               if ($opt{count}) {
+                                       push @headercache, [ $line, $excess ? \undef : $counter ];
+                                       next;
+                               }
                        }
-                       say $_->[2] // join(': ', @$_);
+                       say $line;
                }
 
                last BLOCK;
        }
 }
 
+for (@headercache) {
+       say ${$_->[1]} // '', "\t", $_->[0];
+}
+
 __END__
 
 =head1 NAME