From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

#!/usr/bin/env perl
# Copyright (c) 2015 Christian Jaeger, copying@christianjaeger.ch
# This is free software. See the file COPYING.md that came bundled
# with this file.
use strict;
use warnings FATAL => 'uninitialized';
# find modules from functional-perl working directory (not installed)
use Cwd 'abs_path';
our ($mydir, $myname);
BEGIN {
my $location = (-l $0) ? abs_path($0) : $0;
$location =~ /(.*?)([^\/]+?)_?\z/s or die "?";
($mydir, $myname) = ($1, $2);
}
use lib "$mydir/../lib";
sub usage {
print "usage: $myname < file.diff > file-diff.html
Turn a textual diff as output by `git diff` into HTML format with
some coloring.
Uses streaming and hence works with arbitrarily long inputs.
";
exit(@_ ? 1 : 0);
}
our $verbose = 0;
GetOptions("verbose" => \$verbose, "help" => sub {usage},) or exit 1;
usage if @ARGV;
use FP::Stream ":all";
use FP::IOStream ":all";
use PXML::Serialize qw(puthtmlfile);
use PXML::XHTML ":all";
use FP::Ops ":all";
use Chj::xopen "glob_to_fh";
our $lines = fh_to_stream(
glob_to_fh(*STDIN, "utf-8"),
the_method("xreadline_chomp"),
the_method("xclose")
);
our $html = HTML(
HEAD(
TITLE($myname),
META(
{
'http-equiv' => "Content-Type",
content => "text/html;charset=utf-8"
}
),
STYLE(
{ type => "text/css" }, '
.diff {
color: #008;
border-top: 1px solid;
margin-top: 20px;
padding-top: 10px;
}
.meta {
color: #008;
}
.position {
color: blue;
}
.add {
color: green;
}
.del {
color: red;
}
.context {
color: black;
}
.other {
color: orange;
}
'
),
BODY(
PRE(
stream_map func($line)
{
DIV(
{
class => (
$line =~ /^diff / ? "diff"
: $line =~ /^(index|new|\+\+\+|---) / ? "meta"
: do {
my $c = substr $line, 0, 1;
( $c eq '@' ? "position"
: $c eq '+' ? "add"
: $c eq '-' ? "del"
: $c eq ' ' ? "context"
: "other")
}
)
},
$line
)
},
$lines
)
)
)
);
puthtmlfile("-", $html);
# TODO: why have `puthtmlfile` to write to magic "-" file as
# filehandle, but do glob_to_fh etc. manipulation?