]> ruderich.org/simon Gitweb - config/dotfiles.git/blob - vcs/bin/tig.pl
Merge branch 'x11'
[config/dotfiles.git] / vcs / bin / tig.pl
1 #!/usr/bin/perl
2
3 # tig-like git log output. Used when tig is not available or broken.
4
5 # Copyright (C) 2013  Simon Ruderich
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20
21 use strict;
22 use warnings;
23
24 use POSIX ();
25 use Term::ANSIColor qw(colored);
26
27
28 my $color_graph         = 'yellow';
29 my $color_hash          = 'cyan';
30 my $color_ref_sep       = 'cyan';
31 my $color_ref_head      = 'cyan bold';
32 my $color_ref_branch    = 'green bold';
33 my $color_ref_reference = 'red bold';
34 my $color_author        = 'magenta';
35
36
37 # Aliases in Git with "! ..." are always run in the top-level-directory.
38 # GIT_PREFIX contains the relative path to the current subdirectory. Thanks to
39 # dr_lepper in #git on Freenode (2013-04-03 23:17 CEST) for telling me about
40 # GIT_PREFIX.
41 if (defined $ENV{GIT_PREFIX} and $ENV{GIT_PREFIX} ne '') {
42     chdir $ENV{GIT_PREFIX} or die $!;
43 }
44
45 my $format = '%x00'         # separator from --graph
46            . '%h'  . '%x00' # abbreviated commit hash
47            . '%at' . '%x00' # author date
48            . '%an' . '%x00' # author name
49            . '%s'  . '%x00' # subject
50            . '%d';          # ref names
51 my @cmd = ('git', 'log', '--graph', "--format=$format",
52            # use either given arguments or --all to list all commits
53            (scalar @ARGV) ? @ARGV : '--all');
54 open my $fh, '-|', @cmd or die $!;
55
56 my $pager = $ENV{PAGER};
57 # Try to find an usable pager without searching $PATH.
58 if (not defined $pager) {
59     foreach my $path (qw(/usr/bin/less /bin/less /usr/bin/more /bin/more)) {
60         next if not -x $path;
61
62         $pager = $path;
63         last;
64     }
65 }
66 # Use a pager if STDOUT is a terminal.
67 if (-t STDOUT and defined $pager) {
68     open STDOUT, '|-', $pager or die $!;
69 }
70
71 while (<$fh>) {
72     # History graph line.
73     if (m{^([|/\\_ ]+)$}) {
74         print colored($_, $color_graph);
75         next;
76     }
77
78     # Commit line.
79     /^([ *|.\\-]+)\x00(.+)\x00(.+)\x00(.+)\x00(.*)\x00(.*)$/ or die $_;
80     my $prefix  = $1;
81     my $hash    = colored($2, $color_hash);
82     my $date    = POSIX::strftime('%Y-%m-%d', localtime($3));
83     my $author  = colored($4, $color_author);
84     my $message = $5;
85     my $refs    = $6;
86
87     # Strip trailing whitespace.
88     $prefix =~ s/\s+$//;
89     # Color "graph".
90     $prefix =~ s/\|/colored($&, $color_graph)/ge;
91
92     # Strip leading whitespace and braces.
93     $refs =~ s/^\s+//;
94     $refs =~ tr/()//d;
95
96     # Color refs.
97     $refs = join colored(', ', $color_ref_sep), map {
98         my $color;
99         if ($_ eq 'HEAD') {
100             $color = $color_ref_head;
101         } elsif (m{/}) {
102             $color = $color_ref_reference;
103         } else {
104             $color = $color_ref_branch;
105         }
106         colored($_, $color);
107     } split /, /, $refs;
108
109     if ($refs ne '') {
110         $refs = ' '
111               . colored('(', $color_ref_sep)
112               . $refs
113               . colored(')', $color_ref_sep);
114     }
115
116     printf "%s %s %s %s%s %s\n",
117            $prefix, $hash, $date, $author, $refs, $message;
118 }
119
120 close $fh or die $!;
121
122 # Necessary for the redirection to a pager or the pager terminates after our
123 # script finishes without displaying all data.
124 if (defined $pager) {
125     close STDOUT or die $!;
126 }