Amusement: ASCII Art generator

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

a few days ago, I posted an ASCII representation of a commit graph. This 
was really tedious, so I wrote a simple script to generate it (and also to 
prove that I am not making everything a builtin). It takes revision range 
arguments, so if you call it with '-25 229ed74' on the git repository, you 
will get this:

A---C-----F---------------------Q---------------Y
   /     /                     /               /
  B   D-E   G-------K-------O-P---R---T-U-V-W-X
                           /         ,-----'
              H-I-J---L-M-N---------S

Now, without further ado, the script.

-- snipsnap --
#!/usr/bin/perl

if ($#ARGV < 1) {
	print STDERR "Usage: $ARGV0 <revision range>\n";
	exit(1);
}

open INPUT, 'git rev-list --parents ' . join(' ', @ARGV) . '|';

%commits=();
@list=();

sub add_parents ($$) {
	my $parents = $_[0];
	my $y = $_[1];
	foreach my $parent (split / /,$parents) {
		if ($commits->{$parent} == undef) {
			$commits->{$parent} = {
				'y' => $y++,
				'sha1' => $parent
			};
		} else {
			if ($commits->{$parent}->{y} < $y) {
				$commits->{$parent}->{y} = $y++;
			} else {
				$y = $commits->{$parent}->{y} + 1;
			}
		}
	}
}

# expects output of `rev-list --parents --topo-order`
$i = 0;
while (<INPUT>) {
	if (/^([0-9a-f]{40}) ?(.*)$/) {
		$sha1 = $1;
		$parents = $2;
		if ($commits->{$sha1} == undef) {
			$commits->{$sha1} = {
				'y' => 0,
				'sha1' => $sha1,
			};
		} else {
			$commits->{$sha1}->{index} = $#list;
		}
		$commits->{$sha1}->{parents} = $parents;
		$list[$i] = $commits->{$sha1};
		$commits->{$sha1}->{index} = $i++;
		add_parents($parents, $commits->{$sha1}->{y});
	}
}
close INPUT;

if ($#list >= 26) {
	print STDERR "Cannot draw more than 26 revs.";
	exit(1);
}

# make labels
$height = 0;
for ($i = 0; $i <= $#list; $i++) {
	$list[$i]->{x} = $#list - $i;
	$list[$i]->{label} = chr(0x41 + $list[$i]->{x});
	if ($height < $list[$i]->{y}) {
		$height = $list[$i]->{y};
	}
}

# make a canvas
$width = $#list * 2 + 1;
$height = $height * 2 + 1;
@canvas = ();
for ($i = 0; $i < $height; $i++) {
	$canvas[$i] = ' ' x $width . "\n";
}

sub set_cell ($$$) {
	my $x = $_[0];
	my $y = $_[1];
	my $c = $_[2];
	$canvas[$y] = substr($canvas[$y], 0, $x) . $c .
		substr($canvas[$y], $x + 1);
}

sub get_cell ($$) {
	my $x = $_[0];
	my $y = $_[1];
	return substr($canvas[$y], $x, 1);
}

sub msg($) {
	my $info = $_[0];
	return $info->{label} . ": " . $info->{x} . ", " . $info->{y};
}

sub draw_line ($$) {
	my $commit1 = $_[0];
	my $commit2 = $_[1];
	my $x1 = $commit1->{x};
	my $y1 = $commit1->{y};
	my $x2 = $commit2->{x};
	my $y2 = $commit2->{y};
	if ($y1 == $y2) {
		for (my $i = $x1 * 2 - 1; $i > $x2 * 2; $i--) {
			set_cell($i, $y1 * 2, "-");
		}
	} else {
		my $is_straight = 0;
		my $factor = ($y2 - $y1) / ($x1 - $x2);
		my $i;
		if ($x1 - $x2 == $y2 - $y1) {
			$is_straight = 1;
			for ($i = $x1 * 2 - 1; $i > $x2 * 2; $i -= 2) {
				my $y = $y1 * 2 + ($x1 * 2 - $i) * $factor;
				my $c = get_cell($i, int($y));
				if ($c ne ' ' && $c ne '-') {
					$is_straight = 0;
				}
			}
		}
		if ($is_straight) {
			for ($i = $x1 * 2 - 1; $i > $x2 * 2; $i--) {
				my $y = $y1 * 2 + ($x1 * 2 - $i) * $factor;
				my $c = (get_cell($i, int($y)) ne ' ') ?
					'+' : '/';
				set_cell($i, int($y), $c);
			}
		} else {
			set_cell($x1 * 2 - 1, $y1 * 2 + 1, '\'');
			for ($i = $x1 * 2 - 2; $i > $x2 * 2 + 1; $i--) {
				set_cell($i, $y1 * 2 + 1, '-');
			}
			set_cell($x2 * 2 + 1, $y1 * 2 + 1, ',');
			for ($i = $y1 * 2 + 2; $i < $y2 * 2; $i++) {
				my $c = (get_cell($x2 * 2, $i) ne ' ') ?
					'+' : '|';
				set_cell($x2 * 2, $i, $c);
			}
		}
	}
}

# draw it
for ($i = 0; $i <= $#list; $i++) {
	$info = $list[$i];
	$x = $info->{x} * 2;
	$y = $info->{y} * 2;
	set_cell ($x, $y, $info->{label});
	foreach my $parent (split / /,$info->{parents}) {
		if ($commits->{$parent}->{index} != undef) {
			draw_line($info, $commits->{$parent});
		}
	}
}

print @canvas;

-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]