278e424b5ec253b99b8cfcfe2c8cc1b683ddb4c7
[u/fanf2/git-graph.git] / git-graph
1 #!/usr/bin/perl
2
3 use warnings;
4 use strict;
5
6 use Getopt::Long qw{:config gnu_getopt posix_default};
7 use POSIX;
8 use Term::ReadKey;
9
10 $0 =~ s{^.*/([^/]+)$}{$1};
11
12 my %opt;
13 GetOptions(\%opt, qw{
14 cancel|c
15 height|h=i
16 overlay|o
17 stack|s
18 width|w=i
19 }) or exit 1;
20
21 $opt{overlay} = 1 unless $opt{cancel} or $opt{stack};
22
23 my @terminal = GetTerminalSize;
24 my $width = $terminal[0] - 11;
25 my $height = $opt{height} // $terminal[1] - 2;
26
27 my %add;
28 my %del;
29
30 my $addmax = 0;
31 my $delmax = 0;
32 my $canmax = 0;
33
34 my $date;
35
36 for (qx{git log --pretty=format:%ct --shortstat --since='$height days ago'}) {
37 next if m{^\s*$};
38 if (m{^(\d{10})\n$}) {
39 $date = int ($1 / 86400);
40 next;
41 }
42 m{^\ \d+\ files?\ changed
43 (?:,\ (\d+)\ insertion[s()+]+)?
44 (?:,\ (\d+)\ deletion[s()-]+)?$}x
45 or die "$0: bad stats $_";
46 my ($add,$del) = ($1 || 0, $2 || 0);
47 $add{$date} += $add;
48 $del{$date} += $del;
49 $addmax = $add{$date} if $addmax < $add{$date};
50 $delmax = $del{$date} if $delmax < $del{$date};
51 my $can = abs $add{$date} - $del{$date};
52 $canmax = $can if $canmax < $can;
53 }
54
55 my $max = $opt{width} ? $opt{width} :
56 $opt{cancel} ? $canmax :
57 $opt{stack} ? $addmax + $delmax :
58 $addmax > $delmax ? $addmax : $delmax;
59 my $scale = $width / $max;
60
61 my $today = int (time / 86400);
62
63 for my $date ($today - $height .. $today) {
64 my $add = 0;
65 my $del = 0;
66 my $mod = 0;
67 $add{$date} //= 0;
68 $del{$date} //= 0;
69 if ($opt{cancel} or $opt{overlay}) {
70 if ($add{$date} > $del{$date}) {
71 $add = $add{$date} - $del{$date};
72 } else {
73 $del = $del{$date} - $add{$date};
74 }
75 }
76 if ($opt{overlay}) {
77 $mod = $add{$date} < $del{$date} ?
78 $add{$date} : $del{$date};
79 }
80 if ($opt{stack}) {
81 $add = $add{$date};
82 $del = $del{$date};
83 }
84 my $greg = strftime "%b %d %w", localtime $date * 86400;
85 $greg =~ s{(\d)$}{substr "sMTWTFs", $1, 1}e;
86 my $line = sprintf "$greg \e[33m%s\e[32m%s\e[31m%s\e[0m\n",
87 "#" x ($mod && 1 + $mod * $scale),
88 "+" x ($add && 1 + $add * $scale),
89 "-" x ($del && 1 + $del * $scale);
90 if (length $line > $width) {
91 $line = sprintf "## %d ##\e[32m++ %d ++\e[31m-- %d --\e[0m\n",
92 $mod, $add, $del;
93 $line = "$greg \e[33m" . "#"x($width + 16 - length $line) . $line;
94 }
95 print $line;
96 }
97 printf " \e[33m#\e[0m <- %-8.1f %s %8d ->\n",
98 1/$scale, " " x ($width - 25), $max;