#!/usr/bin/perl
# List all functions defined in ./**.{pl,pm}
use vars qw($VERSION);
$VERSION = '0.004';

use strict;
use Term::ExtendedColor qw(fg);
use File::Find::Rule;
use Cwd 'abs_path';


my $dir = abs_path( shift // '.' );

if(-f $dir) {
  output_func($dir);
}
elsif(-d $dir) {
  my $ff = File::Find::Rule->new;
  $ff->file;
  $ff->name('*.pm', '*.pl');
  my @perl = $ff->in( $dir );
  output_func($ff->in($dir));
}
else {
  print STDERR "Neither a file or directory specified.\n";
  exit 1;
}


sub grab_func {
  my @files = @_;

  my %functions;

  for my $file(@files) {
    open(my $fh, '<', $file) or die($!);
    while(<$fh>) {
      if(m;\s*sub\s+(.+)\s*{;) {
        $functions{$1} = $file;
      }
    }
  }
  return \%functions;
}

sub output_func {
  my @files = @_;
  my %func =  %{ grab_func(@files) };

  my $module;
  for my $file(sort { $func{$b} cmp $func{$a} } (keys(%func))) {
    if($func{$file} ne $module) {
      $module = $func{$file};

      my $mod_name;
      if( ($module =~ m;.+lib/(.+)\.pm$;)) {
        $mod_name = $1;
        $mod_name =~ s;/;::;g;
        $mod_name =~ s;\.pm;;;
        print "\n";
        print fg('bold', fg('yellow18', $mod_name)), "\n";
      }
    }
    my ($basename) = $func{$file} =~ m;.+/(.+)$;;
    my ($two_lvl)  = $func{$file} =~ m;.+/(.+/.+)$;;

    my $sep_counter = 0;
    for(split(//, $func{$file})) {
      if($_ eq '/') {
        $sep_counter++;
      }
    }
    if($sep_counter >= 4) {
      $two_lvl =~ s;(.+)/(.+);
        fg('grey10', $1) . fg('grey5', "::") .  fg('grey4', $2)
      ;igex;

      printf("%67.90s -> %s\n",
        $two_lvl, $file);
    }
    else {
      printf("%37.90s -> %s\n",
        fg('gray10', $basename), $file);
    }
  }
  printf("\n%s functions defined in %s\n",
   fg('bold',  scalar(keys(%func))), $dir)
    unless(scalar(keys(%func)) < 1);
}