1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
#!/usr/bin/perl -w
=head1 NAME
pamphletangler - Extract code bits from LaTeX pamphlet files.
=cut
=head1 SYNOPSIS
B<pamphletangler> [OPTION...] I<FILE> I<CHUNKNAME>
=cut
=head1 DESCRIPTION
The clojure pamphlet system is a system based on the clojure literate
system. In the clojure's pamphlet system you have your main LaTeX file, which
can be compiled regularly. This file contains documentation and source code
(just like in other forms of literate programming). This code snippets are
wrapped in the 'chunk' environment, hence they can be recognized by the tangler
in order to extract them. Chunks can be included inside each other by the
'getchunk' command (which will be typesetted acordingly). Finally, you run your
LaTeX file through the tangler and get your desired chunk of code.
=cut
=head1 OPTIONS
=over 29
=item -L, --line=linetext
If set, this text will be inserted after jumps of lines, changing the string
inside "changetext" for the line number. This is used so that error report
refers to pamphlet line number instead of output line number
=item -C, --change=changetext
Defaults to "{}" this is the text that will be replaced with the line number if
the linetext option is specified
=item -?, --help
Give this help list
=item --usage
Give a short usage message
=item --man
Print manual page
=item -V, --version
Print program version
=back
=head1 LICENSE
Copyright (C) 2019 Ernesto Lanchares Sanchez.
The clojure-pamphlet tagler is free software; you can redistribute
it and/or modify it under the terms of the GNU Lesser General
Public License as published by the Free Software Foundation;
either version 3 of the License, or (at your option) any later
version.
The clojure-pamphlet tangler 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, see
L<http://www.gnu.org/licenses/>.
=head1 AUTHOR
Ernesto Lanchares <e.lancha98@gmail.com>
=head1 BUGS
Report bugs to e.lancha98@gmail.com
=cut
use strict;
use warnings;
use Getopt::Long;
use Pod::Usage qw(pod2usage);
use vars qw/$VERSION/;
BEGIN { $VERSION = '1.3' }
my $linetext = "";
my $changetext = "{}";
my $filename;
my $chunkname;
OPTS: {
GetOptions(
'usage' => sub { pod2usage( -verbose => 99, -sections => [ qw(SYNOPSIS) ]); },
'help|?' => sub { pod2usage( -verbose => 99, -sections => [ qw(SYNOPSIS DESCRIPTION OPTIONS BUGS) ]); },
'man' => sub { pod2usage( -verbose => 2) },
'version|V' => sub { print "$VERSION\n"; exit; },
'line|L=s' => \$linetext,
'change|C=s' => \$changetext
);
pod2usage( -message => "[ERROR]: Invalid number of arguments." )
if scalar(@ARGV) != 2;
$filename = shift;
$chunkname = shift;
}
open(my $file, "<", $filename) or die "Can't open $filename: $!";
my $file_contents = do { local $/; <$file> };
my %codeblocks;
while ($file_contents =~ /\\begin\{chunk\}\{([\w.]+)\}[\s\h\t]*\n?(.*?)\n?[\s\t\h]*\\end\{chunk\}/sg) {
$codeblocks{$1} = { source => $2, printing => undef };
}
open($file, "<", $filename) or die "Can't open $filename: $!";
my $index = 1;
while (my $line = <$file>) {
while ($line =~ /\\begin\{chunk\}\{([\w.]+)\}/g) {
$codeblocks{$1}{line} = $index+1;
}
$index++;
}
sub printchunk {
my ($chunk, $indent) = @_;
die "Chunk $chunk not found." if (!exists($codeblocks{$chunk}));
die "Cyclic reference found: $chunk" if $codeblocks{$chunk}{printing};
$codeblocks{$chunk}{printing} = 1;
my $localines = 1;
print $linetext =~ s/$changetext/$codeblocks{$chunk}{line}/gr, "\n";
foreach my $line (split(/\n/, $codeblocks{$chunk}{source})) {
if ($line =~ /([\s\t\h]*)\\getchunk\{([\w.]+)\}/) {
eval {
printchunk($2, $1); #$1 contains indent and $2 contains chunkname
print $linetext =~ s/$changetext/@{[$codeblocks{$chunk}{line} + $localines]}/gr, "\n";
1;
} or do {
if (rindex($@, "Cyclic reference found:", 0) == 0) {
$@ =~ /(.+?)( at .*)/s;
die "$1 <- $chunk";
}
die $@;
}
} else {
print $indent, $line, "\n";
}
$localines++;
}
$codeblocks{$chunk}{printing} = undef;
return 0;
}
printchunk($chunkname, "");
|