]> ruderich.org/simon Gitweb - config/dotfiles.git/blobdiff - vcs/bin/tig.pl
Move to vcs/ in preparation for merge into new dotfiles repository
[config/dotfiles.git] / vcs / bin / tig.pl
diff --git a/vcs/bin/tig.pl b/vcs/bin/tig.pl
new file mode 100755 (executable)
index 0000000..881583d
--- /dev/null
@@ -0,0 +1,126 @@
+#!/usr/bin/perl
+
+# tig-like git log output. Used when tig is not available or broken.
+
+# Copyright (C) 2013  Simon Ruderich
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+use strict;
+use warnings;
+
+use POSIX ();
+use Term::ANSIColor qw(colored);
+
+
+my $color_graph         = 'yellow';
+my $color_hash          = 'cyan';
+my $color_ref_sep       = 'cyan';
+my $color_ref_head      = 'cyan bold';
+my $color_ref_branch    = 'green bold';
+my $color_ref_reference = 'red bold';
+my $color_author        = 'magenta';
+
+
+# Aliases in Git with "! ..." are always run in the top-level-directory.
+# GIT_PREFIX contains the relative path to the current subdirectory. Thanks to
+# dr_lepper in #git on Freenode (2013-04-03 23:17 CEST) for telling me about
+# GIT_PREFIX.
+if (defined $ENV{GIT_PREFIX} and $ENV{GIT_PREFIX} ne '') {
+    chdir $ENV{GIT_PREFIX} or die $!;
+}
+
+my $format = '%x00'         # separator from --graph
+           . '%h'  . '%x00' # abbreviated commit hash
+           . '%at' . '%x00' # author date
+           . '%an' . '%x00' # author name
+           . '%s'  . '%x00' # subject
+           . '%d';          # ref names
+my @cmd = ('git', 'log', '--graph', "--format=$format",
+           # use either given arguments or --all to list all commits
+           (scalar @ARGV) ? @ARGV : '--all');
+open my $fh, '-|', @cmd or die $!;
+
+my $pager = $ENV{PAGER};
+# Try to find an usable pager without searching $PATH.
+if (not defined $pager) {
+    foreach my $path (qw(/usr/bin/less /bin/less /usr/bin/more /bin/more)) {
+        next if not -x $path;
+
+        $pager = $path;
+        last;
+    }
+}
+# Use a pager if STDOUT is a terminal.
+if (-t STDOUT and defined $pager) {
+    open STDOUT, '|-', $pager or die $!;
+}
+
+while (<$fh>) {
+    # History graph line.
+    if (m{^([|/\\_ ]+)$}) {
+        print colored($_, $color_graph);
+        next;
+    }
+
+    # Commit line.
+    /^([ *|.\\-]+)\x00(.+)\x00(.+)\x00(.+)\x00(.*)\x00(.*)$/ or die $_;
+    my $prefix  = $1;
+    my $hash    = colored($2, $color_hash);
+    my $date    = POSIX::strftime('%Y-%m-%d', localtime($3));
+    my $author  = colored($4, $color_author);
+    my $message = $5;
+    my $refs    = $6;
+
+    # Strip trailing whitespace.
+    $prefix =~ s/\s+$//;
+    # Color "graph".
+    $prefix =~ s/\|/colored($&, $color_graph)/ge;
+
+    # Strip leading whitespace and braces.
+    $refs =~ s/^\s+//;
+    $refs =~ tr/()//d;
+
+    # Color refs.
+    $refs = join colored(', ', $color_ref_sep), map {
+        my $color;
+        if ($_ eq 'HEAD') {
+            $color = $color_ref_head;
+        } elsif (m{/}) {
+            $color = $color_ref_reference;
+        } else {
+            $color = $color_ref_branch;
+        }
+        colored($_, $color);
+    } split /, /, $refs;
+
+    if ($refs ne '') {
+        $refs = ' '
+              . colored('(', $color_ref_sep)
+              . $refs
+              . colored(')', $color_ref_sep);
+    }
+
+    printf "%s %s %s %s%s %s\n",
+           $prefix, $hash, $date, $author, $refs, $message;
+}
+
+close $fh or die $!;
+
+# Necessary for the redirection to a pager or the pager terminates after our
+# script finishes without displaying all data.
+if (defined $pager) {
+    close STDOUT or die $!;
+}