Better date handling and terminal size adaptation
[u/fanf2/git-graph.git] / git-graph
CommitLineData
cce87900
TF
1#!/usr/bin/perl
2
3use warnings;
4use strict;
5
6use Getopt::Long qw{:config gnu_getopt posix_default};
37fadc81 7use POSIX;
cce87900
TF
8use Term::ReadKey;
9
10$0 =~ s{^.*/([^/]+)$}{$1};
11
12sub stop { exit 1; } # because 'die' uses a weird exit status
13sub wail { warn "$0: @_\n"; }
14sub fail { wail @_; stop; }
15sub fale { fail "@_: $!"; }
16
17my %opt;
18GetOptions(\%opt, qw{
37fadc81
TF
19 cancel|c
20 overlay|o
21 stack|s
cce87900
TF
22}) or stop;
23
24$opt{stack} = 1 unless $opt{cancel} or $opt{overlay};
25
37fadc81
TF
26my @terminal = GetTerminalSize;
27my $width = $terminal[0] - 10;
28my $height = $terminal[1];
29
30my @log = qx{git log --pretty=format:%ct --no-merges --shortstat --since='$height days ago'};
cce87900
TF
31
32my %add;
33my %del;
34
35my $addmax = 0;
36my $delmax = 0;
37my $canmax = 0;
38
39while (@log) {
40 my $date = shift @log;
41 my $stat = shift @log;
42 my $blank = shift @log;
43 fail "bad blank line $blank"
44 unless not defined $blank or $blank eq "\n";
45 fail "truncated git log output"
46 unless defined $date and defined $stat;
47 chomp ($date, $stat);
37fadc81
TF
48 $date =~ m{^[0-9]{10}$} or fail "bad timestamp $date";
49 $date = int ($date / 86400);
cce87900
TF
50 $stat =~ m{^\ \d+\ files?\ changed
51 (?:,\ (\d+)\ insertion[s()+]+)?
52 (?:,\ (\d+)\ deletion[s()-]+)?$}x
53 or fail "bad stats $stat";
54 my ($add,$del) = ($1 || 0, $2 || 0);
55 $add{$date} += $add;
56 $del{$date} += $del;
57 $addmax = $add{$date} if $addmax < $add{$date};
58 $delmax = $del{$date} if $delmax < $del{$date};
59 my $can = $add{$date} > $del{$date} ?
60 $add{$date} - $del{$date} :
61 $del{$date} - $add{$date};
62 $canmax = $can if $canmax < $can;
63}
64
65my $max = $opt{cancel} ? $canmax :
66 $opt{stack} ? $addmax + $delmax :
67 $addmax > $delmax ? $addmax : $delmax;
cce87900
TF
68my $scale = $width / $max;
69
37fadc81
TF
70my $today = int (time / 86400);
71
72for my $date ($today - $height .. $today) {
cce87900
TF
73 my $add;
74 my $del;
75 my $mod;
37fadc81
TF
76 $add{$date} //= 0;
77 $del{$date} //= 0;
cce87900
TF
78 if ($opt{cancel}) {
79 if ($add{$date} > $del{$date}) {
80 $add = $add{$date} - $del{$date};
81 $del = $mod = 0;
82 } else {
83 $del = $del{$date} - $add{$date};
84 $add = $mod = 0;
85 }
86 }
87 if ($opt{overlay}) {
88 if ($add{$date} > $del{$date}) {
89 $add = $add{$date} - $del{$date};
90 $del = 0;
91 $mod = $del{$date};
92 } else {
93 $del = $del{$date} - $add{$date};
94 $add = 0;
95 $mod = $add{$date};
96 }
97 }
98 if ($opt{stack}) {
99 $add = $add{$date};
100 $del = $del{$date};
101 $mod = 0;
102 }
37fadc81
TF
103 my $greg = strftime "%b %d %w", localtime $date * 86400;
104 $greg =~ s{(\d)$}{substr "sMTWTFs", $1, 1}e;
105 printf "$greg \e[33m%s\e[32m%s\e[31m%s\e[0m\n",
106 "#" x ($mod && 1 + $mod * $scale),
107 "+" x ($add && 1 + $add * $scale),
108 "-" x ($del && 1 + $del * $scale);
cce87900 109}