#!@l_prefix@/bin/perl
##
##  monotone-colorize -- colorize output of mtn(1)
##  Copyright (c) 2007 Ralf S. Engelschall <rse@engelschall.com> 
##
##  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 2 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, write to the Free Software
##  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
##  USA, or contact Ralf S. Engelschall <rse@engelschall.com>.
##
##  monotone-colorize.pl: filter implementation (language: Perl)
##

require 5.008;
use Term::ANSIColor qw(color);

#   color definitions
my $color = {
    -standout => color("bold"),
    -inverse  => color("bold white on_black"),
    -positive => color("blue"),
    -negative => color("red"),
    -none     => color("reset"),
};

#   if connected to the TTY, colorize and connect to less(1)
my $ontty = 0;
if (-t STDOUT) {
    $ontty = 1;
    open(FP, "|@l_prefix@/bin/less -E -r");
    *STDOUT = *FP;
}

#   determine mtn(1) command
my $cmd = shift(@ARGV);

#   process mtn(1) output
my $in = { -changelog => 0 };
while (<STDIN>) {
    if ($ontty) {
        #   dispatch according to mtn(1) command
        if ($cmd eq "update") {
            #   colorize branch/revision information
            s/(expanded\s+selector\s+')([^']*)('\s+->\s+')([^']*)/$1$color->{-positive}$2$color->{-none}$3$color->{-positive}$4$color->{-none}/o;

            s/((?:updating\s+along\s+branch|expanding\s+selection)\s+')([^']*)(')/$1$color->{-positive}$2$color->{-none}$3/o;
            s/(expanded\s+to\s+')([^']*)(')/$1$color->{-standout}$2$color->{-none}$3/o;
            s/((?:already\s+up\s+to\s+date\s+at|selected\s+update\s+target|updated\s+to\s+base\s+revision)\s+)(\S+)/$1$color->{-standout}$2$color->{-none}/o;
            s/((?:switching\s+to\s+branch|next\s+commit\s+will\s+use\s+branch)\s+)(\S+)/$1$color->{-positive}$2$color->{-none}$3/o;

            #   colorize status list
            s/(\s+dropping\s+)(\S+)/$1$color->{-negative}$2$color->{-none}/o;
            s/(\s+modifying\s+)(\S+)/$1$color->{-positive}$2$color->{-none}/o;
            s/(\s+adding\s+)(\S+)/$1$color->{-standout}$color->{-positive}$2$color->{-none}/o;

            #   colorize errors 
            s/(misuse:)(.+)$/$1$color->{-negative}$2$color->{-none}/o;
        }
        elsif ($cmd eq "status") {
            #   colorize headers
            s/^(Current branch:\s+)(\S+)/$1$color->{-standout}$2$color->{-none}/o;
            s/^(Changes against parent\s+)(\S+)/$1$color->{-standout}$2$color->{-none}/o;

            #   colorize status list
            s/^(\s+patched\s+)(\S+)/$1$color->{-positive}$2$color->{-none}/o;
            s/^(\s+dropped\s+)(\S+)/$1$color->{-negative}$2$color->{-none}/o;
            s/^(\s+added\s+)(\S+)/$1$color->{-standout}$color->{-positive}$2$color->{-none}/o;
        }
        elsif ($cmd eq "log") {
            #   colorize certs
            s/(Revision:\s+)(.+)/$color->{-inverse}$1$2$color->{-none}/o;
            s/((?:Ancestor|Author|Date|Branch|Tag):\s+)(.+)/$1$color->{-standout}$2$color->{-none}/o;

            #   colorize changelog text
            if (m/---------------+/s) {
                $in->{-changelog} = 0;
                s/^([\s|\\\/o]\s*)?(---+)\r?\n$/$1.("_" x 78)."\n"/oes;
            }
            s/^([\s|\\\/o]\s*)(.+)$/$1$color->{-positive}$2$color->{-none}/o if ($in->{-changelog});
            $in->{-changelog} = 1 if (m/ChangeLog:\s*$/s);
        }
        elsif ($cmd eq "diff") {
            #   expand tabs
            1 while (s/\t/" " x (8 - ((length($`)-1) % 8))/e);
         
            #   colorize diff header
            s/^Index:\s+(\S+).*$/("_" x 78)."\n"."$color->{-inverse}    ".$1."    $color->{-none}\n"/oes;
            s/^========+\s*$//os;
         
            #   colorize unified diff
            s/^(@@.*$)/$color->{-standout}$1$color->{-none}/o;
            s/^(\+.*)$/$color->{-positive}$1$color->{-none}/o;
            s/^(---\s+\S+\s+.+)$/$color->{-negative}$1$color->{-none}/o;
            s/^(-([^-].*|))$/$color->{-negative}$1$color->{-none}/o;
         
            #   colorize context diff
            s/^(--- \d+,\d+ ----.*)$/$color->{-standout}$1$color->{-none}/o;
            s/^(\*\*\* \d+,\d+ *\*\*\*.*)$/$color->{-standout}$1$color->{-none}/o;
            s/^(\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*)$/$color->{-standout}$1$color->{-none}/o;
            s/^(!.*)$/$color->{-positive}$1$color->{-none}/o;
        }
        elsif ($cmd eq "list-tags") {
            #   colorize tag names and revisions
            s/^(\S+)(\s+)(\S+)(\s+)(.+)$/$color->{-positive}$1$color->{-none}$2$color->{-standout}$3$color->{-none}$4$5/o;
        }
        elsif ($cmd eq "list-branches") {
            #   colorize branch names
            s/^(\S+)$/$color->{-positive}$1$color->{-none}/o;
        }
    }
    print STDOUT $_;
}

#   close connection to less(1)
if ($ontty) {
    close(FP);
}

