line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mojolicious::Plugin::PPI; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
3765
|
use Mojo::Base 'Mojolicious::Plugin'; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
35
|
|
4
|
|
|
|
|
|
|
|
5
|
5
|
|
|
5
|
|
992
|
use Mojo::Util; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
236
|
|
6
|
5
|
|
|
5
|
|
33
|
use Mojo::ByteStream 'b'; |
|
5
|
|
|
|
|
5
|
|
|
5
|
|
|
|
|
292
|
|
7
|
|
|
|
|
|
|
|
8
|
5
|
|
|
5
|
|
25
|
use File::Basename (); |
|
5
|
|
|
|
|
6
|
|
|
5
|
|
|
|
|
66
|
|
9
|
5
|
|
|
5
|
|
31
|
use File::Spec; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
137
|
|
10
|
|
|
|
|
|
|
|
11
|
5
|
|
|
5
|
|
1117
|
use PPI::HTML; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $VERSION = '0.07'; |
14
|
|
|
|
|
|
|
$VERSION = eval $VERSION; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
has 'line_numbers' => 1; |
17
|
|
|
|
|
|
|
has 'no_check_file' => 0; |
18
|
|
|
|
|
|
|
has 'ppi_html_on' => sub { PPI::HTML->new( line_numbers => 1 ) }; |
19
|
|
|
|
|
|
|
has 'ppi_html_off' => sub { PPI::HTML->new( line_numbers => 0 ) }; |
20
|
|
|
|
|
|
|
has 'src_folder'; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
has style => <<'END'; |
23
|
|
|
|
|
|
|
.ppi-code { |
24
|
|
|
|
|
|
|
display: inline-block; |
25
|
|
|
|
|
|
|
min-width: 400px; |
26
|
|
|
|
|
|
|
background-color: #F8F8F8; |
27
|
|
|
|
|
|
|
border-radius: 10px; |
28
|
|
|
|
|
|
|
padding: 15px; |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
END |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
has class_style => sub {{ |
33
|
|
|
|
|
|
|
line_number_on => { display => 'inline' }, |
34
|
|
|
|
|
|
|
line_number_off => { display => 'none' }, |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
cast => '#339999', |
37
|
|
|
|
|
|
|
comment => '#008080', |
38
|
|
|
|
|
|
|
core => '#FF0000', |
39
|
|
|
|
|
|
|
double => '#999999', |
40
|
|
|
|
|
|
|
heredoc_content => '#FF0000', |
41
|
|
|
|
|
|
|
interpolate => '#999999', |
42
|
|
|
|
|
|
|
keyword => '#BD2E2A', |
43
|
|
|
|
|
|
|
line_number => '#666666', |
44
|
|
|
|
|
|
|
literal => '#999999', |
45
|
|
|
|
|
|
|
magic => '#0099FF', |
46
|
|
|
|
|
|
|
match => '#9900FF', |
47
|
|
|
|
|
|
|
number => '#990000', |
48
|
|
|
|
|
|
|
operator => '#DD7700', |
49
|
|
|
|
|
|
|
pod => '#008080', |
50
|
|
|
|
|
|
|
pragma => '#A33AF7', |
51
|
|
|
|
|
|
|
regex => '#9900FF', |
52
|
|
|
|
|
|
|
single => '#FF33FF', |
53
|
|
|
|
|
|
|
substitute => '#9900FF', |
54
|
|
|
|
|
|
|
symbol => '#389A7D', |
55
|
|
|
|
|
|
|
transliterate => '#9900FF', |
56
|
|
|
|
|
|
|
word => '#999999', |
57
|
|
|
|
|
|
|
}}; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub register { |
60
|
|
|
|
|
|
|
my ($plugin, $app) = (shift, shift); |
61
|
|
|
|
|
|
|
$plugin->initialize($app, @_); |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
push @{$app->static->classes}, __PACKAGE__; |
64
|
|
|
|
|
|
|
push @{$app->renderer->classes}, __PACKAGE__; |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
$app->helper( ppi => sub { |
67
|
|
|
|
|
|
|
return $plugin if @_ == 1; |
68
|
|
|
|
|
|
|
return $plugin->convert(@_); |
69
|
|
|
|
|
|
|
}); |
70
|
|
|
|
|
|
|
$app->helper( ppi_css => sub { $_[0]->ppi->generate_css(@_) } ); |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub initialize { |
74
|
|
|
|
|
|
|
my ($plugin, $app) = (shift, shift); |
75
|
|
|
|
|
|
|
my %opts = @_ == 1 ? %{$_[0]} : @_; |
76
|
|
|
|
|
|
|
my @unknown; |
77
|
|
|
|
|
|
|
foreach my $key (keys %opts) { |
78
|
|
|
|
|
|
|
my $code = $plugin->can($key); |
79
|
|
|
|
|
|
|
unless ($code) { |
80
|
|
|
|
|
|
|
push @unknown, $key; |
81
|
|
|
|
|
|
|
next; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
$plugin->$code($opts{$key}); |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
if ( @unknown ) { |
87
|
|
|
|
|
|
|
warn "Unknown option(s): " . join(", ", @unknown) . "\n"; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub convert { |
92
|
|
|
|
|
|
|
my $plugin = shift; |
93
|
|
|
|
|
|
|
my $c = shift; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
my %opts = $plugin->process_converter_opts(@_); |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
my $converter = |
98
|
|
|
|
|
|
|
$opts{line_numbers} |
99
|
|
|
|
|
|
|
? $plugin->ppi_html_on |
100
|
|
|
|
|
|
|
: $plugin->ppi_html_off; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
my $id = $plugin->generate_id($c); |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
my @tag = ( |
105
|
|
|
|
|
|
|
$opts{inline} ? 'code' : 'pre', |
106
|
|
|
|
|
|
|
id => $id, |
107
|
|
|
|
|
|
|
class => 'ppi-code ' . ($opts{inline} ? 'ppi-inline' : 'ppi-block'), |
108
|
|
|
|
|
|
|
); |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
if ($opts{line_numbers}) { |
111
|
|
|
|
|
|
|
push @tag, ondblclick => "ppi_toggleLineNumbers('$id')"; |
112
|
|
|
|
|
|
|
$c->stash('ppi.js.required' => 1); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
my %render_opts = ( |
116
|
|
|
|
|
|
|
'ppi.code' => $converter->html( $opts{file} ? $opts{file} : \$opts{string} ), |
117
|
|
|
|
|
|
|
'ppi.tag' => \@tag, |
118
|
|
|
|
|
|
|
); |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
#TODO use render_to_string once Mojo 5.00 is required |
121
|
|
|
|
|
|
|
return $c->include('ppi_template', %render_opts); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub generate_id { |
125
|
|
|
|
|
|
|
my ($plugin, $c) = @_; |
126
|
|
|
|
|
|
|
return 'ppi' . $c->stash->{'ppi.id'}++; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub check_file { |
130
|
|
|
|
|
|
|
my ($self, $file) = @_; |
131
|
|
|
|
|
|
|
return undef if $self->no_check_file; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
if ( my $folder = $self->src_folder ) { |
134
|
|
|
|
|
|
|
die "Could not find folder $folder\n" unless -d $folder; |
135
|
|
|
|
|
|
|
$file = File::Spec->catfile( $folder, $file ); |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
return -e $file ? $file : undef; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub process_converter_opts { |
142
|
|
|
|
|
|
|
my $plugin = shift; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
my $string = do { |
145
|
|
|
|
|
|
|
no warnings 'uninitialized'; |
146
|
|
|
|
|
|
|
if (ref $_[-1] eq 'CODE') { |
147
|
|
|
|
|
|
|
Mojo::Util::trim pop->(); |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
}; |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
my %opts; |
152
|
|
|
|
|
|
|
if (ref $_[-1]) { |
153
|
|
|
|
|
|
|
%opts = %{ pop() }; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
if ( @_ % 2 ) { |
157
|
|
|
|
|
|
|
die "Cannot specify both a string and a block\n" if $string; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
$string = shift; |
160
|
|
|
|
|
|
|
$opts{file} = $plugin->check_file($string); |
161
|
|
|
|
|
|
|
unless ( $opts{file} ) { |
162
|
|
|
|
|
|
|
$opts{inline} //= 1; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
%opts = (%opts, @_) if @_; |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
$opts{string} = $string unless defined $opts{file}; |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
$opts{line_numbers} //= 0 if $opts{inline}; |
172
|
|
|
|
|
|
|
$opts{line_numbers} //= $plugin->line_numbers; |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
return %opts; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub generate_css { |
178
|
|
|
|
|
|
|
my ($plugin, $c) = @_; |
179
|
|
|
|
|
|
|
my $sheet = b("pre.ppi-code br { display: none; }\n"); |
180
|
|
|
|
|
|
|
$$sheet .= $plugin->style."\n"; |
181
|
|
|
|
|
|
|
my $cs = $plugin->class_style; |
182
|
|
|
|
|
|
|
foreach my $key (sort keys %$cs) { |
183
|
|
|
|
|
|
|
my $value = $cs->{$key}; |
184
|
|
|
|
|
|
|
$value = { color => $value } unless ref $value; |
185
|
|
|
|
|
|
|
$$sheet .= ".ppi-code .$key { "; |
186
|
|
|
|
|
|
|
foreach my $prop ( sort keys %$value ) { |
187
|
|
|
|
|
|
|
$$sheet .= "$prop: $value->{$prop}; "; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
$$sheet .= "}\n"; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
return $c->stylesheet(sub{$sheet}); |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
1; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
__DATA__ |