line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Pandoc::Filter::ImagesFromCode; |
2
|
1
|
|
|
1
|
|
762
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
3
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
28
|
|
4
|
1
|
|
|
1
|
|
6
|
use utf8; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
8
|
|
5
|
1
|
|
|
1
|
|
617
|
use Encode; |
|
1
|
|
|
|
|
9853
|
|
|
1
|
|
|
|
|
72
|
|
6
|
1
|
|
|
1
|
|
21
|
use 5.010; |
|
1
|
|
|
|
|
3
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '0.36'; |
9
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
5
|
use Digest::MD5 'md5_hex'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
66
|
|
11
|
1
|
|
|
1
|
|
8
|
use IPC::Run3; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
45
|
|
12
|
1
|
|
|
1
|
|
5
|
use File::Spec::Functions; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
78
|
|
13
|
1
|
|
|
1
|
|
559
|
use File::stat; |
|
1
|
|
|
|
|
6860
|
|
|
1
|
|
|
|
|
10
|
|
14
|
1
|
|
|
1
|
|
63
|
use Pandoc::Elements; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
259
|
|
15
|
1
|
|
|
1
|
|
8
|
use Scalar::Util 'reftype'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
48
|
|
16
|
1
|
|
|
1
|
|
8
|
use parent 'Pandoc::Filter', 'Exporter'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
8
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
our @EXPORT_OK = qw(read_file write_file); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub new { |
21
|
1
|
|
|
1
|
1
|
21
|
my ($class, %opts) = @_; |
22
|
|
|
|
|
|
|
|
23
|
1
|
|
50
|
|
|
4
|
$opts{from} //= 'code'; |
24
|
1
|
|
50
|
|
|
4
|
$opts{dir} //= '.'; |
25
|
1
|
|
|
|
|
4
|
$opts{dir} =~ s!/$!!; |
26
|
|
|
|
|
|
|
$opts{name} //= sub { |
27
|
1
|
50
|
|
1
|
|
10
|
$_[0]->id =~ /^[a-z0-9_]+$/i ? $_[0]->id |
28
|
|
|
|
|
|
|
: md5_hex( encode( 'utf8', $_[0]->content ) ); |
29
|
1
|
|
50
|
|
|
10
|
}; |
30
|
|
|
|
|
|
|
|
31
|
1
|
50
|
|
|
|
3
|
die "missing option: to\n" unless $opts{to}; |
32
|
|
|
|
|
|
|
|
33
|
1
|
50
|
33
|
|
|
24
|
if ('ARRAY' ne reftype $opts{run} or !@{$opts{run}}) { |
|
1
|
|
|
|
|
7
|
|
34
|
0
|
|
|
|
|
0
|
die "missing or empty option: run\n"; |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
1
|
|
|
|
|
4
|
bless \%opts, $class; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub to { |
41
|
1
|
|
|
1
|
1
|
3
|
my $to = $_[0]->{to}; |
42
|
1
|
|
|
|
|
2
|
my $format = $_[1]; |
43
|
1
|
50
|
|
|
|
5
|
if (ref $to) { |
|
|
50
|
|
|
|
|
|
44
|
0
|
|
|
|
|
0
|
return $to->($format); |
45
|
|
|
|
|
|
|
} elsif ($to) { |
46
|
1
|
|
|
|
|
5
|
return $to; |
47
|
|
|
|
|
|
|
} else { |
48
|
0
|
|
|
|
|
0
|
return 'png'; |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub action { |
53
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub { |
56
|
1
|
|
|
1
|
|
4
|
my ($e, $format, $m) = @_; |
57
|
|
|
|
|
|
|
|
58
|
1
|
50
|
|
|
|
9
|
return if $e->name ne 'CodeBlock'; |
59
|
|
|
|
|
|
|
|
60
|
1
|
|
|
|
|
29
|
my $code = $e->content; |
61
|
1
|
|
|
|
|
7
|
my $dir = $self->{dir}; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
my %args = ( |
64
|
|
|
|
|
|
|
name => $self->{name}->($e), |
65
|
|
|
|
|
|
|
from => $self->{from}, |
66
|
1
|
|
|
|
|
13
|
to => $self->to($format), |
67
|
|
|
|
|
|
|
); |
68
|
1
|
|
|
|
|
12
|
$args{infile} = catfile($self->{dir}, "$args{name}.$args{from}"); |
69
|
1
|
|
|
|
|
7
|
$args{outfile} = catfile($self->{dir}, "$args{name}.$args{to}"); |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# TODO: document or remove this experimental code. If keep, expand args |
72
|
1
|
|
|
|
|
8
|
my $kv = $e->keyvals; |
73
|
1
|
|
|
|
|
57
|
my @options = $kv->get_all('option'); |
74
|
1
|
|
|
|
|
24
|
push @options, map { split /\s+/, $_ } $kv->get_all('options'); |
|
0
|
|
|
|
|
0
|
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# TODO: print args in debug mode? |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# skip transformation if nothing has changed |
79
|
1
|
|
|
|
|
18
|
my $in = stat($args{infile}); |
80
|
1
|
|
|
|
|
100
|
my $out = stat($args{outfile}); |
81
|
1
|
0
|
33
|
|
|
81
|
if (!$self->{force} and $in and $out and $in->mtime <= $out->mtime) { |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
82
|
0
|
0
|
|
|
|
0
|
if ($code eq read_file($args{infile}, ':utf8')) { |
83
|
|
|
|
|
|
|
# no need to rebuild the same outfile |
84
|
0
|
|
|
|
|
0
|
return build_image($e, $args{outfile}); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
1
|
|
|
|
|
8
|
write_file($args{infile}, $code, ':utf8'); |
89
|
|
|
|
|
|
|
|
90
|
1
|
|
|
|
|
4
|
my ($stderr, $stdout); |
91
|
|
|
|
|
|
|
my @command = map { |
92
|
2
|
|
|
|
|
4
|
my $s = $_; |
93
|
|
|
|
|
|
|
#if ($args{substr $s, 1, -1}) |
94
|
2
|
|
33
|
|
|
10
|
$s =~ s|\$([^\$]+)\$| $args{$1} // $1 |eg; |
|
1
|
|
|
|
|
8
|
|
95
|
2
|
|
|
|
|
11
|
$s |
96
|
1
|
|
|
|
|
4
|
} @{$self->{run}}; |
|
1
|
|
|
|
|
5
|
|
97
|
1
|
|
|
|
|
3
|
push @command, @options; |
98
|
|
|
|
|
|
|
|
99
|
1
|
|
|
|
|
14
|
run3 \@command, \undef, \$stdout, \$stderr, |
100
|
|
|
|
|
|
|
{ |
101
|
|
|
|
|
|
|
binmode_stdin => ':utf8', |
102
|
|
|
|
|
|
|
binmode_stdout => ':raw', |
103
|
|
|
|
|
|
|
binmode_stderr => ':raw', |
104
|
|
|
|
|
|
|
}; |
105
|
|
|
|
|
|
|
|
106
|
1
|
50
|
|
|
|
7940
|
if ($self->{capture}) { |
107
|
1
|
|
|
|
|
23
|
write_file($args{outfile}, $stdout, ':raw'); |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# TODO: include $code or $stderr on error in debug mode |
111
|
|
|
|
|
|
|
# TODO: skip error if requested |
112
|
1
|
50
|
|
|
|
20
|
die $stderr if $stderr; |
113
|
|
|
|
|
|
|
|
114
|
1
|
|
|
|
|
27
|
return build_image($e, $args{outfile}); |
115
|
|
|
|
|
|
|
} |
116
|
1
|
|
|
|
|
9
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
# build_image( $element [, $filename ] ) |
119
|
|
|
|
|
|
|
# |
120
|
|
|
|
|
|
|
# Maps an element to an L element with attributes |
121
|
|
|
|
|
|
|
# from the given element. The attribute C, if available, is transformed |
122
|
|
|
|
|
|
|
# into image caption. This utility function is useful for filters that transform |
123
|
|
|
|
|
|
|
# content to images. See graphviz, tikz, lilypond and similar filters in the |
124
|
|
|
|
|
|
|
# L. |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub build_image { |
127
|
1
|
|
|
1
|
0
|
10
|
my $e = shift; |
128
|
1
|
|
50
|
|
|
16
|
my $filename = shift // ''; |
129
|
|
|
|
|
|
|
|
130
|
1
|
|
|
|
|
30
|
my $keyvals = $e->keyvals; |
131
|
1
|
|
50
|
|
|
114
|
my $title = $keyvals->get('title') // ''; |
132
|
1
|
|
|
|
|
27
|
my $img = Image attributes { id => $e->id, class => $e->class }, |
133
|
|
|
|
|
|
|
[], [$filename, $title]; |
134
|
|
|
|
|
|
|
|
135
|
1
|
|
50
|
|
|
13
|
my $caption = $keyvals->get('caption') // ''; |
136
|
1
|
50
|
|
|
|
28
|
if (defined $caption) { |
137
|
1
|
|
|
|
|
7
|
push @{$img->content}, Str($caption); |
|
1
|
|
|
|
|
30
|
|
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
1
|
|
|
|
|
12
|
return Plain [ $img ]; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub write_file { |
144
|
2
|
|
|
2
|
0
|
12
|
my ($file, $content, $encoding) = @_; |
145
|
|
|
|
|
|
|
|
146
|
2
|
50
|
|
|
|
177
|
open my $fh, ">$encoding", $file |
147
|
|
|
|
|
|
|
or die "failed to create file $file: $!\n"; |
148
|
2
|
|
|
|
|
51
|
print $fh $content; |
149
|
2
|
|
|
|
|
83
|
close $fh; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub read_file { |
153
|
2
|
|
|
2
|
0
|
1152
|
my ($file, $encoding) = @_; |
154
|
|
|
|
|
|
|
|
155
|
2
|
50
|
|
|
|
94
|
open my $fh, "<$encoding", $file |
156
|
|
|
|
|
|
|
or die "failed to open file: $file: $!\n"; |
157
|
|
|
|
|
|
|
|
158
|
2
|
|
|
|
|
6
|
my $content = do { local $/; <$fh> }; |
|
2
|
|
|
|
|
15
|
|
|
2
|
|
|
|
|
67
|
|
159
|
2
|
50
|
|
|
|
23
|
close $fh or die "failed to close file: $file: $!\n"; |
160
|
|
|
|
|
|
|
|
161
|
2
|
|
|
|
|
29
|
return $content; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
1; |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
__END__ |