|
65 | 65 | float: right; |
66 | 66 | cursor: pointer; |
67 | 67 | } |
68 | | -.re_warns { |
| 68 | +.re_output { |
69 | 69 | clear: both; |
| 70 | + background-color: rgba(234,234,234,255); |
| 71 | +} |
| 72 | +.re_warns { |
70 | 73 | background-color: rgba(255,255,200,255); |
71 | 74 | } |
72 | 75 | .re_errors { |
|
100 | 103 | use warnings; |
101 | 104 | use 5.028; |
102 | 105 | use WebPerl qw/js/; |
103 | | -use File::Temp qw/tempfile/; |
104 | 106 | use Data::Dumper (); |
105 | 107 | my $jq = js('jQuery'); |
106 | 108 |
|
|
111 | 113 |
|
112 | 114 | my $run_code_body = <<'END_CODE'; |
113 | 115 | my (@warns,@output); |
114 | | - #TODO Later: Capture STDOUT too? (and STDERR, instead of $SIG{__WARN__})? |
| 116 | + |
| 117 | + require File::Temp; |
| 118 | + my ($fh1,$fn1) = File::Temp::tempfile(); |
| 119 | + open my $oldout, '>&', \*STDOUT or die "dup STDOUT: $!"; |
| 120 | + open STDOUT, '>&', $fh1 or die "open STDOUT: $!"; |
| 121 | + my ($fh2,$fn2) = File::Temp::tempfile(); |
| 122 | + open my $olderr, '>&', \*STDERR or die "dup STDERR: $!"; |
| 123 | + open STDERR, '>&', $fh2 or die "open STDERR: $!"; |
| 124 | + |
115 | 125 | my $ok = do { |
116 | 126 | local $SIG{__WARN__} = sub { push @warns, shift }; |
117 | 127 | eval "package RunCode {$code\n};1" }; |
118 | 128 | my $err = $ok ? undef : $@||"Unknown error"; |
| 129 | + |
| 130 | + open STDERR, '>&', $olderr or die "dup \$olderr: $!"; |
| 131 | + close $fh2; |
| 132 | + open STDOUT, '>&', $oldout or die "dup \$oldout: $!"; |
| 133 | + close $fh1; |
| 134 | + my $stdout = do { open my $fh, '<', $fn1 or die $!; local $/; <$fh> }; |
| 135 | + my $stderr = do { open my $fh, '<', $fn2 or die $!; local $/; <$fh> }; |
| 136 | + unlink($fn1,$fn2)==2 or warn "unlink('$fn1','$fn2'): $!"; |
| 137 | + |
119 | 138 | defined && s/\bat .+? line \d+(?:\.$|,\h)//mg for (@warns,$err); |
120 | 139 | chomp(@warns); |
121 | | - my $rv = { ctx=>$context, warns=>\@warns, $ok ? (out=>\@output) : (err=>$err) }; |
| 140 | + my $rv = { ctx=>$context, warns=>\@warns, |
| 141 | + $ok ? (out=>\@output) : (err=>$err), |
| 142 | + stdout => $stdout, stderr => $stderr }; |
122 | 143 | END_CODE |
123 | 144 |
|
124 | 145 | my $runcode_iframe; |
|
200 | 221 | my $closebtn = $jq->('<div/>', {html=>"❎",class=>"closebtn", |
201 | 222 | title=>"Delete Sample"}); |
202 | 223 | $closebtn->appendTo($samp); |
| 224 | + $jq->('<pre/>', {class=>'re_output'})->appendTo($samp); |
203 | 225 | $jq->('<pre/>', {class=>'re_warns'})->appendTo($samp); |
204 | 226 | $jq->('<pre/>', {class=>'re_errors'})->appendTo($samp); |
205 | 227 | $samp->click(sub { |
|
239 | 261 | # $re_debug is actually a parameter to update()/actual_update(), but since |
240 | 262 | # we register &update as a event handler, it'll get passed varying parameters |
241 | 263 | our $re_debug=0; |
242 | | -my $ta_debugout = $jq->('#debugout'); |
243 | | -my $re_debug_hide = $jq->('#re_debug_hide'); |
244 | | -$jq->('#re_debug')->click(sub { |
245 | | - #TODO: re_debug no longer works in IFrame! (ugly "workaround" below) |
246 | | - # Not only this capturing, but also $re_debug is unset by the time the callback gets called |
247 | | - open my $olderr, '>&', \*STDERR or die "dup STDERR: $!"; |
248 | | - my ($fh,$fn) = tempfile(); |
249 | | - open STDERR, '>&', $fh or die "open STDERR: $!"; |
250 | | - |
251 | | - { local $re_debug=1; update(); } |
252 | | - |
253 | | - open STDERR, '>&', $olderr or die "dup \$olderr: $!"; |
254 | | - close $fh; |
255 | | - my $err = do { open my $fh, '<', $fn or die $!; local $/; <$fh> }; |
256 | | - unlink($fn)==1 or warn "unlink $fn: $!"; |
257 | | - |
258 | | - $err .= "\n### Please see the JavaScript console! ###\n" |
259 | | - if $RUN_CODE_IN_IFRAME; |
260 | | - $ta_debugout->val($err); |
261 | | - $ta_debugout->show; |
262 | | - $re_debug_hide->show; |
263 | | -}); |
264 | | -$re_debug_hide->click(sub{ |
265 | | - $re_debug_hide->hide; |
266 | | - $ta_debugout->hide; |
267 | | -}); |
268 | | -$re_debug_hide->hide; |
269 | | -$ta_debugout->hide; |
| 264 | +$jq->('#re_debug')->click(sub { local $re_debug=1; update() }); |
270 | 265 |
|
271 | 266 | my $sampcodebtn = $jq->('#sampcodebtn'); |
272 | 267 | my $codecopy = $jq->('#codecopy'); |
|
358 | 353 | my $precode = $precode_ta->is(':visible') ? $precode_ta->val : ''; |
359 | 354 | $precode .= "\n" if length $precode && substr($precode,-1) ne "\n"; |
360 | 355 | my $regex_str = 'm{'.$regex.'}'.$flags; |
361 | | - $re_debug and !length($regex) and say STDERR |
362 | | - "NOTE: The empty regex $regex_str requires a workaround with /(?:)/," # https://www.perlmonks.org/?node_id=1221517 |
363 | | - ."\n this will be reflected in the debug output"; |
364 | 356 |
|
365 | 357 | my $warn = ''; |
366 | | - $warn .= "Notice: The empty pattern has special behavior, see perlop!\n" |
367 | | - ." Here, a workaround is used so it acts as a true empty pattern.\n" unless length $regex; |
| 358 | + if (not length $regex) { |
| 359 | + $warn .= "Notice: The empty pattern has special behavior, see perlop!\n" |
| 360 | + ." Here, a workaround is used so it acts as a true empty pattern.\n"; |
| 361 | + if ($re_debug) # https://www.perlmonks.org/?node_id=1221517 |
| 362 | + { $warn .= " The workaround uses /(?:)/, which you will see in the debug output.\n" } |
| 363 | + } |
368 | 364 | $warn .= "\\n is recommended over literal newlines\n" if $regex=~/\n/ && $flags!~/x/; |
369 | 365 | $warn .= "\\t is recommended over literal tabs\n" if $regex=~/\t/ && $flags!~/x/; |
370 | 366 | state $warnmsgs = $jq->("#warnmsgs"); |
|
375 | 371 | my $samptxt = $sample->children('.samptxt'); |
376 | 372 | my $text = $samptxt->text; |
377 | 373 | push @samps, $text; # for use below |
378 | | - my $code = $precode . ($re_debug?'use re "debug";' |
379 | | - . 'say STDERR '.pp('##### ##### ##### '.pp($text).' =~ '.pp($regex_str).' ##### ##### #####').';':'') |
380 | | - . (length($regex)?'':"''=~/(?:)/$flags;") |
381 | | - . 'push @output,[[@-],[@+]] ' . ($flags=~/g/?'while':'if') . ' $input=~'.$regex_str; |
| 374 | + my $code = $precode . ( $re_debug ? "use re \"debug\";\n" : '' ) |
| 375 | + . ( length($regex) ? '' : "''=~/(?:)/$flags; # // workaround\n" ) |
| 376 | + . 'push @output,[[@-],[@+]] ' . ($flags=~/g/?'while':'if') . ' $input=~'.$regex_str.";\n"; |
| 377 | + $re_debug and |
| 378 | + $code = 'BEGIN{require Data::Dumper;' |
| 379 | + .'print(STDERR Data::Dumper->new([$input],["input"])->Indent(0)->Dump,' |
| 380 | + .'"\n-- Code --\n",' . pp($code) . ',"----\n")}' . "\n" |
| 381 | + . $code . "\n" |
| 382 | + . q{print STDERR "----\n",Data::Dumper->new([\@output],["*output"])->Indent(0)->Dump;}; |
382 | 383 | run_code($sample->attr('id'), $code, $text, \&run_code_callback); |
383 | 384 | } |
384 | 385 |
|
|
449 | 450 | if ( $rv->{out} && $rv->{out}->@* ) { |
450 | 451 | $samptxt->removeClass('nomatch'); |
451 | 452 | my %hi; |
452 | | - $re_debug and say STDERR '@-/@+ are ',pp($rv->{out}); |
453 | 453 | for my $i (0..$#{$rv->{out}}) { |
454 | 454 | my ($s,$e) = $rv->{out}[$i]->@*; |
455 | 455 | for my $j (0..$#$e) { # Use @+ to count all capture groups instead of @-! |
|
465 | 465 | } |
466 | 466 | } |
467 | 467 | } |
468 | | - $re_debug and say STDERR 'highlights are ',pp(\%hi); |
469 | 468 | my $html=''; |
470 | 469 | my $p=0; |
471 | 470 | my (%active_match,%active_caps); |
|
509 | 508 | { $errs = $rv->{err} } |
510 | 509 | $samptxt->text($text); |
511 | 510 | } |
| 511 | + my $stdoe = ''; |
| 512 | + for my $s (qw/stdout stderr/) { |
| 513 | + next unless length $rv->{$s} && $rv->{$s}=~/\S/; |
| 514 | + $rv->{$s} =~ s/\A\n+|\n+\z//g; |
| 515 | + $stdoe .= "### ".uc($s)." ###\n".$rv->{$s}."\n"; |
| 516 | + } |
| 517 | + $sample->children('.re_output')->text($stdoe); |
| 518 | + unshift @{ $rv->{warns} }, "### Warnings ###" if $rv->{warns}->@*; |
512 | 519 | $sample->children('.re_warns')->text( join "\n", $rv->{warns}->@* ); |
| 520 | + $errs = "### Errors ###\n$errs" if $errs=~/\S/; |
513 | 521 | $sample->children('.re_errors')->text($errs); |
514 | 522 | } |
515 | 523 |
|
|
586 | 594 | </div> |
587 | 595 |
|
588 | 596 | <div style="margin-top:0.5em"> |
589 | | - <div> |
590 | | - <button id="re_debug"><tt>use re "debug";</tt></button> |
591 | | - <button id="re_debug_hide">Hide</button> |
592 | | - </div> |
593 | | - <textarea id="debugout" rows="25" cols="80" readonly="readonly" style="display:none"></textarea> |
| 597 | + <button id="re_debug"><tt>use re "debug";</tt></button> |
594 | 598 | </div> |
595 | 599 |
|
596 | 600 | <div style="margin-top:0.5em"> |
|
0 commit comments