WIP: asciidoc replacement

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

 



Hi,

I do not want to depend on more than necessary in msysGit, and therefore I 
started to write an asciidoc replacement.

So here it is: a perl script that does a good job on many .txt files in 
Documentation/, although for some it deviates from "make man"'s output, 
and for others it is outright broken.  It is meant to be run in 
Documentation/.

My intention is not to fix the script for all cases, but to make patches 
to Documentation/*.txt themselves, so that they are more consistent (and 
incidentally nicer to the script).

Now, I hear you already moan: "But Dscho, you know you suck at Perl!"

Yeah, I know, but maybe instead of bashing on me (pun intended), you may 
want to enlighten me with tips how to make it nicer to read.  (Yes, there 
are no comments; yes, I will gladly add them where appropriate; yes, html 
is just a stub.)

So here, without further ado, da script:

-- snip --
#!/usr/bin/perl

$conv = new man_page();
$conv->{manual} = 'Git Manual';
$conv->{git_version} = 'Git ' . `cat ../GIT-VERSION-FILE`;
$conv->{git_version} =~ s/GIT_VERSION = //;
$conv->{git_version} =~ s/-/\\-/;
$conv->{git_version} =~ s/\n//;
$conv->{date} = `date +%m/%d/%Y`;
$conv->{date} =~ s/\n//;

$par = '';
handle_file($ARGV[0]);
$conv->finish();

sub handle_text {
	if ($par =~ /^\. /s) {
		my @lines = split(/^\. /m, $par);
		shift @lines;
		$conv->enumeration(\@lines);
	} elsif ($par =~ /^\* /s) {
		my @lines = split(/^\* /m, $par);
		shift @lines;
		$conv->enumeration(\@lines, 'unnumbered');
	} elsif ($par =~ /^\[verse\]/) {
		$par =~ s/\[verse\] *\n?//;
		$conv->verse($par);
	} elsif ($par =~ /^(\t|  +)/s) {
		$par =~ s/^$1//mg;
		$par =~ s/^\+$//mg;
		$conv->indent($par);
	} elsif ($par =~ /^([^\n]*)::\n((\t|  +).*)$/s) {
		my ($first, $rest, $indent) = ($1, $2, $3);
		$rest =~ s/^\+$//mg;
		while ($rest =~ /^(.*?\n\n)--+\n(.*?\n)--+\n\n(.*)$/s) {
			my ($pre, $verb, $post) = ($1, $2, $3);

			$pre =~ s/^(\t|$indent)//mg;
			if ($first ne '') {
				$conv->begin_item($first, $pre);
				$first = '';
			} else {
				$conv->normal($pre);
			}

			$conv->verbatim($verb);
			$rest = $post;
		}
		$rest =~ s/^(\t|$indent)//mg;
		if ($first ne '') {
			$conv->begin_item($first, $rest);
		} else {
			$conv->normal($rest);
		}
		$conv->end_item();
	} elsif ($par =~ /^-+\n(.*\n)-+\n$/s) {
		$conv->verbatim($1);
	} else {
		$conv->normal($par);
	}
	$par = '';
}

sub handle_file {
	my $in;
	open($in, '<' . $_[0]);
	while (<$in>) {
		if (/^=+$/) {
			if ($par ne '' && length($_) >= length($par)) {
				$conv->header($par);
				$par = '';
				next;
			}
		} elsif (/^-+$/) {
			if ($par ne '' && length($_) >= length($par)) {
				$conv->section($par);
				$par = '';
				next;
			}
		} elsif (/^~+$/) {
			if ($par ne '' && length($_) >= length($par)) {
				$conv->subsection($par);
				$par = '';
				next;
			}
		} elsif (/^\[\[(.*)\]\]$/) {
			handle_text();
			$conv->anchor($1);
			next;
		} elsif (/^$/) {
			if ($par =~ /^-+\n.*[^-]\n$/s) {
				# fallthru; is verbatim, but needs more.
			} elsif ($par =~ /::\n$/s) {
				# is item, but needs more.
				next;
			} else {
				handle_text();
				next;
			}
		} elsif (/^include::(.*)\[\]$/) {
			handle_text();
			handle_file($1);
			next;
		}

		# convert "\--" to "--"
		s/\\--/--/g;
		# convert "\*" to "*"
		s/\\\*/*/g;

		# handle gitlink:
		s/gitlink:([^\[ ]*)\[(\d+)\]/sprintf "%s",
			$conv->get_link($1, $2)/ge;
		# handle link:
		s/link:([^\[ ]*)\[(.+)\]/sprintf "%s",
			$conv->get_link($1, $2, 'external')/ge;

		$par .= $_;
	}
	close($in);
	handle_text();
}

package man_page;

sub new {
	my ($class) = @_;
	my $self = {
		sep => '',
		links => [],
#		generator => 'Home grown git txt2man converter'
		generator => 'DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>'
	};
	bless $self, $class;
	return $self;
}

sub header {
	my ($self, $text) = @_;
	$text =~ s/-/\\-/g;

	if ($self->{preamble_shown} == undef) {
		$title = $text;
		$title =~ s/\(\d+\)$//;
		print '.\"     Title: ' . $title
			. '.\"    Author: ' . "\n"
			. '.\" Generator: ' . $self->{generator} . "\n"
			. '.\"      Date: ' . $self->{date} . "\n"
			. '.\"    Manual: ' . $self->{manual} . "\n"
			. '.\"    Source: ' . $self->{git_version} . "\n"
			. '.\"' . "\n";
	}

	$text =~ tr/a-z/A-Z/;
	my $suffix = "\"$self->{date}\" \"$self->{git_version}\""
		. " \"$self->{manual}\"";
	$text =~ s/^(.*)\((\d+)\)$/.TH "\1" "\2" $suffix/;
	print $text;

	if ($self->{preamble_shown} == undef) {
		print '.\" disable hyphenation' . "\n"
			. '.nh' . "\n"
			. '.\" disable justification (adjust text to left'
				. ' margin only)' . "\n"
			. '.ad l' . "\n";
		$self->{preamble_shown} = 1;
	}

	$self->{last_op} = 'header';
}

sub section {
	my ($self, $text) = @_;

	$text =~ tr/a-z/A-Z/;
	$text =~ s/^(.*)$/.SH "\1"/;

	print $text;

	$self->{last_op} = 'section';
}

sub subsection {
	my ($self, $text) = @_;

	$text =~ s/^(.*)$/.SS "\1"/;

	print $text;

	$self->{last_op} = 'subsection';
}

sub get_link {
	my ($self, $command, $section, $option) = @_;

	if ($option eq 'external') {
		my $links = $self->{links};
		push(@$links, $command);
		$command =~ s/\.html$//;
		$command =~ s/-/ /g;
		push(@$links, $command);
		return '\fI' . $command . '\fR\&[1]';
	} else {
		return '\fB' . $command . '\fR(' . $section . ')';
	}
}

sub common {
	my ($self, $text, $option) = @_;

	# escape backslashes, but not in "\n", "\&" or "\fB"
	$text =~ s/\\(?!n|f[A-Z]|&)/\\\\/g;
	# escape "-"
	$text =~ s/-/\\-/g;
	# handle ...
	$text =~ s/(\.\.\.)/\\&\1/g;
	# remove double space after full stop or comma
	$text =~ s/([\.,])  /\1 /g;

	if ($option ne 'no-markup') {
		# make 'italic'
		$text =~ s/'([^'\n]*)'/\\fI\1\\fR/g;
		# ignore `
		$text =~ s/`//g;
		# make *bold*
		$text =~ s/\*([^\*\n]*)\*/\\fB\1\\fR/g;
		# handle <<sections>
		$text =~ s/<<([^>]*)>>/the section called \\(lq\1\\(rq/g;
	}

	return $text;
}

sub normal {
	my ($self, $text) = @_;

	if ($text eq "") {
		return;
	}

	$text = $self->common($text);

	$text =~ s/ *\n(.)/ \1/g;

	if ($self->{last_op} eq 'normal') {
		print "\n";
	}

	print $text;

	$self->{last_op} = 'normal';
}

sub verse {
	my ($self, $text) = @_;

	$text = $self->common($text);
	$text =~ s/^\t/        /mg;

	print ".sp\n.RS 4\n.nf\n" . $text . ".fi\n.RE\n";

	$self->{last_op} = 'verse';
}

sub enumeration {
	my ($self, $text, $option) = @_;

	my $counter = 0;
	foreach $line (@$text) {
		$counter++;
		print ".TP 4\n"
			. ($option eq 'unnumbered' ? '\(bu' : $counter . '.')
			. "\n"
			. $self->common($line);
	}

	$self->{last_op} = 'enumeration';
}

sub begin_item {
	my ($self, $item, $text) = @_;

	$item = $self->common($item);
	$text = $self->common($text);

	$text =~ s/([^\n]) *\n([^\n])/\1 \2/g;

	print ".PP\n" . $item . "\n.RS 4\n" . $text;

	$self->{last_op} = 'item'; 
}

sub end_item {
	my ($self) = @_;

	print ".RE\n";

	$self->{last_op} = 'end_item';
}

sub indent {
	my ($self, $text) = @_;

	$text = $self->common($text, 'no-markup');
	$text =~ s/^\t/        /mg;

	if ($self->{last_op} eq 'normal') {
		print "\n";
	}

	print ".sp\n.RS 4\n.nf\n" . $text . ".fi\n.RE\n";

	$self->{last_op} = 'indent';
}

sub verbatim {
	my ($self, $text) = @_;

	$text = $self->common($text, 'no-markup');

	# convert tabs to spaces
	$text =~ s/^\t/        /mg;
	# remove trailing empty lines
	$text =~ s/\n\n*$/\n/;

	if ($self->{last_op} eq 'normal') {
		print "\n";
	}

	print ".sp\n.RS 4\n.nf\n.ft C\n" . $text . ".ft\n\n.fi\n.RE\n";

	$self->{last_op} = 'verbatim';
}

sub anchor {
	my ($self, $text) = @_;

	$self->{last_op} = 'anchor';
}

sub finish {
	my ($self) = @_;
	my $links = $self->{links};

	if ($#$links >= 0) {
		print '.SH "REFERENCES"' . "\n";
		my $i = 1;
		while ($#$links >= 0) {
			my $ref = shift(@$links);
			$ref =~ s/-/\\-/g;
			my $label = shift(@$links);
			printf (".IP \"% 2d.\" 4\n%s\n.RS 4\n\\%%%s\n.RE\n",
				$i++, $label, $ref);
		}
	} else {
		print "\n";
	}
}

package html_page;

sub new {
	my ($class) = @_;
	my $self = {};
	bless $self, $class;
	return $self;
}

-- snap --

Ciao,
Dscho

P.S.: I need to catch some Zs, and do some real work, so do not be 
surprised if I do not respond within the next 24 hours.
-
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]

  Powered by Linux