evolution-docs/res/mdbook-latex

390 lines
8.7 KiB
Plaintext
Raw Permalink Normal View History

#!/usr/bin/perl
use strict;
use warnings;
use Cwd;
use JSON;
my $data;
{
local $/;
undef $/;
$data = <>;
}
my $json = JSON->new->decode($data);
my $sections = $json->{book}->{sections};
my $date = `date '+%d %B %Y'`;
chomp $date;
my $latex;
my %code_inline;
my $code_inline_index = 0;
my %codeblocks;
my $codeblock_index = 0;
# Opening.
$latex .= "\\documentclass[letterpaper]{article}\n";
$latex .= "\\usepackage[margin=4cm]{geometry}\n";
$latex .= "\\usepackage[T1]{fontenc}\n";
$latex .= "\\fontfamily{lmodern}\n";
$latex .= "\\selectfont\n";
$latex .= "\\usepackage{graphicx}\n";
$latex .= "\\usepackage{hyperref}\n";
$latex .= "\\usepackage{listings}\n";
$latex .= "\\lstdefinestyle{void}{\n";
$latex .= " basicstyle=\\ttfamily,\n";
$latex .= " breaklines=true,\n";
$latex .= " showstringspaces=false,\n";
$latex .= " aboveskip=\\bigskipamount,\n";
$latex .= " belowskip=\\bigskipamount,\n";
$latex .= "}\n";
$latex .= "\\def\\code#1{\\texttt{#1}}\n";
$latex .= "\\begin{document}\n";
$latex .= "\\newgeometry{margin=2cm}\n";
$latex .= "\\begin{titlepage}\n";
$latex .= " \\includegraphics[width=160mm,height=230mm]{res/handbook-cover.png}\n";
$latex .= "\\end{titlepage}\n";
$latex .=" \\restoregeometry\n";
$latex .= "\\title{EvolutionOS Handbook}\n";
$latex .= "\\date{$date}\n";
$latex .= "\\maketitle\n";
$latex .= "\\setcounter{tocdepth}{5}\n";
$latex .= "\\tableofcontents\n";
$latex .= "\\begin{sloppypar}\n"; # Ugly; need to find better solution
# Contents.
foreach my $i (@$sections) {
process_json($i);
}
# Postprocessing.
$latex =~ s/config-network-wpa\\_supplicant/config-network-wpa_supplicant/g;
$latex =~ s/config-network-wpa_supplicant-the-wpa\\_supplicant-service/config-network-wpa_supplicant-the-wpa_supplicant-service/g;
$latex =~ s/(handbook-codeblock-\d+)/$codeblocks{$1}/eg;
$latex =~ s/(handbook-codeinline-\d+)/$code_inline{$1}/eg;
# Closing.
$latex .= "\\end{sloppypar}\n";
$latex .= "\\end{document}\n";
open(my $fh, ">", "handbook.tex")
or die "Can't open handbook.tex for writing: $!";
print $fh $latex;
close($fh)
or die "Couldn't close handbook.tex after writing: $!";
exit 0;
sub process_json {
my $i = shift;
my $type = ref($i);
if ($type eq 'HASH') {
if (defined $i->{content}) {
process_content($i->{path},$i->{content});
}
if (defined $i->{Chapter}) {
process_json($i->{Chapter});
}
if (defined $i->{sub_items}) {
foreach my $j ($i->{sub_items}) {
process_json($j);
}
}
}
if ($type eq 'ARRAY') {
foreach my $j (@{$i}) {
process_json($j);
}
}
}
sub process_content {
my $path = shift;
my $content = shift;
my $base = convert_path_to_hypertarget_base($path);
# Create sections.
$content =~ s/^# ([^\n]+)/create_sectioning("section",$1,$base)/eg;
# Create subsections.
$content =~ s/\n## ([^\n]+)/create_sectioning("subsection",$1,$base)/eg;
# Create subsubsections.
$content =~ s/\n### ([^\n]+)/create_sectioning("subsubsection",$1,$base)/eg;
# Create paragraphs.
$content =~ s/\n#### ([^\n]+)/create_sectioning("paragraph",$1,$base)/eg;
# Create subparagraphs.
$content =~ s/\n##### ([^\n]+)/create_sectioning("subparagraph",$1,$base)/eg;
# Create codeblocks.
$content =~ s/```\n(.+?)\n```/create_codeblock($1)/esg;
# Create internal links.
$content =~ s/\[([^]]+?)\]\(((?:\..?.+?)|(?:#.+?))\)/create_internal_link($1,$2,$path)/esg;
# Create external links.
$content =~ s/<(http[^>]+)>/\\href{$1}{$1}/sg; # bare links
$content =~ s/\[([^]]+?)\]\((.+?)\)/\\href{$2}{$1}/sg;
# Create lists.
$content =~ s/\n\n(- .+?)\n(?:\n|\z)/create_list($1)/esg;
# Create numbered lists.
$content =~ s/\n\n(\d+\. .+?)\n(?:\n|\z)/create_numbered_list($1)/esg;
# Create blockquotes.
$content =~ s/((^>(?:\s*\n|[^\n]+))+)/create_blockquote($1)/emsg;
# Bold text.
$content =~ s/\*\*([^*]+)\*\*/{\\bfseries $1}/sg;
# Escape LaTeX special characters.
$content =~ s/#/'\#'/eg;
$content =~ s/\$/'\$'/eg;
$content =~ s/_/'\_'/eg;
$content =~ s/~/'\~'/eg;
$content =~ s/&/'\&'/eg;
$content =~ s/\^/'\^'/eg;
# Create tables.
$content =~ s/((?:(?:\| +[^|]+ +\| +(?:[^|]+ +\|)+\n)|(?:\|-[^\n]+\n))+)/create_table($1)/esg;
# Create inline code.
$content =~ s/(?: |\n)`([^`]+)`/create_code_inline($1)/esg;
$latex .= $content;
}
sub convert_heading_to_fragment {
my $heading = shift;
$heading =~ s/ /-/g;
$heading =~ s/\.//g;
$heading =~ s/\(|\)//g;
$heading =~ s/(.+)/lc($1)/e;
return $heading;
}
sub convert_path_to_hypertarget_base {
my $base = shift;
if ($base =~ m|index.md|) {
$base =~ m|(.+/index).md|;
$base = $1;
$base =~ s|/|-|g;
} else {
$base =~ m|(.+).md|;
$base = $1;
$base =~ s|/|-|g;
}
return $base;
}
sub create_blockquote {
my $blockquote = shift;
my $result;
$blockquote =~ s/>//g;
$blockquote =~ s/\n//g;
$result .= "\\begin{quote}\n";
$result .= $blockquote;
$result .= "\\end{quote}\n";
return $result;
}
sub create_codeblock {
my $codeblock = shift;
my $label;
my $result;
$codeblock_index++;
$label = 'handbook-codeblock-' . $codeblock_index;
$result .= "\\begin{lstlisting}[style=void]\n";
$result .= $codeblock;
$result .= "\n\\end{lstlisting}\n";
$codeblocks{$label} = $result;
# Mark places in document where codeblock will be re-inserted
# during postprocessing.
return $label;
}
sub create_code_inline {
my $code = shift;
my $label;
my $result;
$code_inline_index++;
$label = 'handbook-codeinline-' . $code_inline_index;
$result = " \\code{$code}";
$code_inline{$label} = $result;
# Mark places in document where code will be re-inserted
# during postprocessing.
return $label;
}
sub create_internal_link {
my $text = shift;
my $destination = shift;
my $current_section = shift;
my $current_directory;
my $base;
my $fragment;
my $hypertarget;
my $result;
if ($destination =~ /^#/) {
$base = $current_section . $destination;
$base =~ s|.md#.+$||;
} else {
$current_section =~ m|^(.+/)|;
$current_directory = $1;
$base = $destination;
$base =~ m|^(.+\.md)|;
$base = $1;
$base = $current_directory . $base;
$base = Cwd::abs_path("../../src/" . $base);
$base =~ s|^.+/src/||;
$base =~ s|.md||;
}
$base =~ s|/|-|g;
if ($destination =~ /#/) {
$destination =~ m|#(.+)$|;
$fragment = "-" . $1;
} else {
$fragment = "";
}
$text =~ s/\n/ /;
$hypertarget = $base . $fragment;
$result = "\\hyperlink{$hypertarget}{$text}";
return $result;
}
sub create_list {
my $list = shift;
my $result;
$result .= "\n\\begin{itemize}\n";
$list =~ s/^- /\\item /mg;
$result .= $list;
$result .= "\n\\end{itemize}\n";
return $result;
}
sub create_numbered_list {
my $list = shift;
my $result;
$result .= "\n\\begin{enumerate}\n";
$list =~ s/^\d+\. /\\item /mg;
$result .= $list;
$result .= "\n\\end{enumerate}\n";
return $result;
}
sub create_sectioning {
my $type = shift;
my $text = shift;
my $name = shift;
my $result;
if ($type ne "section") {
$name = $name . "-" . convert_heading_to_fragment($text);
$result .= "\n\\hypertarget{";
$result .= $name;
$result .= "}{}";
$result .= "\n\\$type\{$text\}\n";
} else {
$result .= "\n\\newpage\n";
$result .= "\n\\hypertarget{";
$result .= $name;
$result .= "}{}";
$result .= "\n\\$type\{$text\}\n";
}
return $result;
}
sub create_table {
my $table = shift;
my $result;
my @lines;
my $header;
my @body;
my $column_count;
@lines = split(/\n/, $table);
$header = $lines[0];
$header =~ s/[^|]//g;
$column_count = length($header) - 1;
$result .= "\n\\bigskip";
$result .= "\n\\begin{tabular}{ | ";
$result .= "l | " x ($column_count - 1);
$result .= "l | }\n";
$result .= "\\hline\n";
$header = $lines[0];
$header =~ s/^\|//;
$header =~ s/\|/&/g;
$header =~ s/&$//;
$result .= $header;
$result .= "\\\\ \\hline \\hline\n";
shift @lines;
foreach my $line (@lines) {
if ($line !~ /^\|-/) {
$line =~ s/^\|//;
$line =~ s/\|/&/g;
$line =~ s/&$//;
$result .= $line;
$result .= "\\\\ \\hline\n";
}
}
$result .= "\n\\end{tabular}\n";
$result .= "\n\\bigskip\n";
}