@@ -601,6 +601,158 @@ sub parse_lines { # Usage: $parser->parse_lines(@lines)
601
601
602
602
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
603
603
604
+ sub _maybe_handle_element_start {
605
+ my $self = shift ;
606
+ return $self -> _handle_element_start(@_ )
607
+ if !$self -> {filter };
608
+
609
+ my ($element_name , $attr ) = @_ ;
610
+
611
+ if ($element_name =~ / \A head(\d )\z / ) {
612
+ $self -> {_in_head } = {
613
+ element => $element_name ,
614
+ level => $1 + 0,
615
+ events => [],
616
+ text => ' ' ,
617
+ };
618
+ }
619
+
620
+ if (my $head = $self -> {_in_head }) {
621
+ push @{ $head -> {events } }, [ ' _handle_element_start' , @_ ];
622
+ return ;
623
+ }
624
+
625
+ return
626
+ if !$self -> {_filter_allowed };
627
+
628
+ $self -> _handle_element_start(@_ );
629
+ }
630
+
631
+ sub _maybe_handle_element_end {
632
+ my $self = shift ;
633
+ return $self -> _handle_element_end(@_ )
634
+ if !$self -> {filter };
635
+
636
+ my ($element_name , $attr ) = @_ ;
637
+
638
+ if (my $head = $self -> {_in_head }) {
639
+ if ($element_name ne $head -> {element }) {
640
+ push @{ $head -> {events } }, [ ' _handle_element_end' , @_ ];
641
+ return ;
642
+ }
643
+
644
+ delete $self -> {_in_head };
645
+
646
+ my $headings = $self -> {_current_headings } ||= [];
647
+ @$headings = (@{$headings }[0 .. $head -> {level } - 2], $head -> {text });
648
+
649
+ my $allowed = $self -> {_filter_allowed } = $self -> _filter_allows(@$headings );
650
+
651
+ if ($allowed ) {
652
+ for my $event (@{ $head -> {events } }) {
653
+ my ($method , @args ) = @$event ;
654
+ $self -> $method (@args );
655
+ }
656
+ }
657
+ }
658
+
659
+ return
660
+ if !$self -> {_filter_allowed };
661
+
662
+ $self -> _handle_element_end(@_ );
663
+ }
664
+
665
+ sub _maybe_handle_text {
666
+ my $self = shift ;
667
+ return $self -> _handle_text(@_ )
668
+ if !$self -> {filter };
669
+
670
+ my ($text ) = @_ ;
671
+
672
+ if (my $head = $self -> {_in_head }) {
673
+ push @{ $head -> {events } }, [ ' _handle_text' , @_ ];
674
+ $head -> {text } .= $text ;
675
+ return ;
676
+ }
677
+
678
+ return
679
+ if !$self -> {_filter_allowed };
680
+
681
+ $self -> _handle_text(@_ );
682
+ }
683
+
684
+ sub _filter_allows {
685
+ my $self = shift ;
686
+ my @headings = @_ ;
687
+
688
+ my $filter = $self -> {filter }
689
+ or return 1;
690
+
691
+ SPEC: for my $spec ( @$filter ) {
692
+ for my $i (0 .. $# $spec ) {
693
+ my $regex = $spec -> [$i ];
694
+ my $heading = $headings [$i ];
695
+ $heading = ' '
696
+ if !defined $heading ;
697
+ next SPEC
698
+ if $heading !~ $regex ;
699
+ }
700
+ return 1;
701
+ }
702
+
703
+ return 0;
704
+ }
705
+
706
+ sub select {
707
+ my $self = shift ;
708
+ my (@selections ) = @_ ;
709
+
710
+ my $filter = $self -> {filter } ||= [];
711
+ if (@selections && $selections [0] eq ' +' ) {
712
+ shift @selections ;
713
+ }
714
+ else {
715
+ @$filter = ();
716
+ }
717
+
718
+ for my $spec (@selections ) {
719
+ eval {
720
+ push @$filter , $self -> _compile_heading_spec($spec );
721
+ 1;
722
+ } or do {
723
+ warn $@ ;
724
+ warn qq{ Ignoring section spec "$spec "!\n } ;
725
+ };
726
+ }
727
+ }
728
+
729
+ sub _compile_heading_spec {
730
+ my $self = shift ;
731
+ my ($spec ) = @_ ;
732
+
733
+ my @bad ;
734
+ my @parts = $spec =~ m { (?:\A |\G /)((?:[^/\\ ]|\\ .)*)} g ;
735
+ for my $part (@parts ) {
736
+ $part =~ s {\\ (.)} { $1 } g ;
737
+ my $negate = $part =~ s {\A !} {} ;
738
+ $part = ' .*'
739
+ if !length $part ;
740
+
741
+ eval {
742
+ $part = $negate ? qr { ^(?!$part $) } : qr { ^$part $} ;
743
+ 1;
744
+ } or do {
745
+ push @bad , qq{ Bad regular expression /$part / in "$spec ": $@ \n } ;
746
+ };
747
+ }
748
+
749
+ Carp::croak(join ' ' , @bad )
750
+ if @bad ;
751
+
752
+ return \@parts ;
753
+ }
754
+
755
+
604
756
sub _handle_encoding_line {
605
757
my ($self , $line ) = @_ ;
606
758
@@ -1346,7 +1498,7 @@ sub _ponder_begin {
1346
1498
DEBUG > 1 and print STDERR " Ignoring ignorable =begin\n " ;
1347
1499
} else {
1348
1500
$self -> {' content_seen' } ||= 1 unless $self -> {' ~tried_gen_errata' };
1349
- $self -> _handle_element_start ((my $scratch =' for' ), $para -> [1]);
1501
+ $self -> _maybe_handle_element_start ((my $scratch =' for' ), $para -> [1]);
1350
1502
}
1351
1503
1352
1504
return 1;
@@ -1414,7 +1566,7 @@ sub _ponder_end {
1414
1566
# what's that for?
1415
1567
1416
1568
$self -> {' content_seen' } ||= 1 unless $self -> {' ~tried_gen_errata' };
1417
- $self -> _handle_element_end ( my $scratch = ' for' , $para -> [1]);
1569
+ $self -> _maybe_handle_element_end ( my $scratch = ' for' , $para -> [1]);
1418
1570
}
1419
1571
DEBUG > 1 and print STDERR " Popping $curr_open ->[-1][0] $curr_open ->[-1][1]{'target'} because of =end $content \n " ;
1420
1572
pop @$curr_open ;
@@ -1536,7 +1688,7 @@ sub _ponder_over {
1536
1688
DEBUG > 1 and print STDERR " =over found of type $list_type \n " ;
1537
1689
1538
1690
$self -> {' content_seen' } ||= 1 unless $self -> {' ~tried_gen_errata' };
1539
- $self -> _handle_element_start ((my $scratch = ' over-' . $list_type ), $para -> [1]);
1691
+ $self -> _maybe_handle_element_start ((my $scratch = ' over-' . $list_type ), $para -> [1]);
1540
1692
1541
1693
return ;
1542
1694
}
@@ -1558,7 +1710,7 @@ sub _ponder_back {
1558
1710
# Expected case: we're closing the most recently opened thing
1559
1711
# my $over = pop @$curr_open;
1560
1712
$self -> {' content_seen' } ||= 1 unless $self -> {' ~tried_gen_errata' };
1561
- $self -> _handle_element_end ( my $scratch =
1713
+ $self -> _maybe_handle_element_end ( my $scratch =
1562
1714
' over-' . ( (pop @$curr_open )-> [1]{' ~type' } ), $para -> [1]
1563
1715
);
1564
1716
} else {
@@ -1843,19 +1995,19 @@ sub _traverse_treelet_bit { # for use only by the routine above
1843
1995
my($self , $name ) = splice @_ ,0,2;
1844
1996
1845
1997
my $scratch ;
1846
- $self ->_handle_element_start (($scratch =$name ), shift @_ );
1998
+ $self ->_maybe_handle_element_start (($scratch =$name ), shift @_ );
1847
1999
1848
2000
while (@_ ) {
1849
2001
my $x = shift;
1850
2002
if (ref($x )) {
1851
2003
&_traverse_treelet_bit($self , @$x );
1852
2004
} else {
1853
2005
$x .= shift while @_ && !ref($_ [0]);
1854
- $self ->_handle_text ($x );
2006
+ $self ->_maybe_handle_text ($x );
1855
2007
}
1856
2008
}
1857
2009
1858
- $self ->_handle_element_end ($scratch =$name );
2010
+ $self ->_maybe_handle_element_end ($scratch =$name );
1859
2011
return;
1860
2012
}
1861
2013
@@ -2426,7 +2578,7 @@ sub reinit {
2426
2578
foreach (qw( source_dead source_filename doc_has_started
2427
2579
start_of_pod_block content_seen last_was_blank paras curr_open
2428
2580
line_count pod_para_count in_pod ~tried_gen_errata all_errata errata errors_seen
2429
- Title) ) {
2581
+ Title _current_headings _in_head _filter_allowed ) ) {
2430
2582
2431
2583
delete $self -> {$_ };
2432
2584
}
0 commit comments