3fb3e2
From aa7a2c99bff2a8d02d75f6b9f7155483cc94318c Mon Sep 17 00:00:00 2001
3fb3e2
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
3fb3e2
Date: Tue, 13 Aug 2019 16:49:21 +0200
3fb3e2
Subject: [PATCH 2/2] Search for X<> in the whole perlop document
3fb3e2
MIME-Version: 1.0
3fb3e2
Content-Type: text/plain; charset=UTF-8
3fb3e2
Content-Transfer-Encoding: 8bit
3fb3e2
3fb3e2
perlop documents many operators before "Regexp Quote-Like Operators"
3fb3e2
(X<operator, regexp>) section. A change introduced with "Refactor
3fb3e2
search_perlop RT#86506" (d8b23dcb1a) commit started to ignore those
3fb3e2
operators. E.g. A search for '==' did not found anything. A search for
3fb3e2
'<>' returned too many text and broke POD syntax.
3fb3e2
3fb3e2
This patch searches for X<> index entries in all sections and
3fb3e2
considers =head keywords in addition to =item as section delimeters.
3fb3e2
3fb3e2
Because some X<> entries exists on more places, this patch implements
3fb3e2
this strategy: First =item section that contains the X<> entry is
3fb3e2
returned. If there is no =item sections, last =head section is
3fb3e2
returned. If the =item entry is empty (like for 'tr'), the the output
3fb3e2
continues up to and including a next non-empty =item. This strategy is
3fb3e2
implemented in one pass.
3fb3e2
3fb3e2
Signed-off-by: Petr Písař <ppisar@redhat.com>
3fb3e2
---
3fb3e2
 lib/Pod/Perldoc.pm        | 116 ++++++++++++++++++++++++++------------
3fb3e2
 t/03_builtin_pod_output.t |   8 +++
3fb3e2
 2 files changed, 89 insertions(+), 35 deletions(-)
3fb3e2
3fb3e2
diff --git a/lib/Pod/Perldoc.pm b/lib/Pod/Perldoc.pm
3fb3e2
index cd52aa2..b54cc23 100644
3fb3e2
--- a/lib/Pod/Perldoc.pm
3fb3e2
+++ b/lib/Pod/Perldoc.pm
3fb3e2
@@ -1153,6 +1153,20 @@ sub search_perlvar {
3fb3e2
 
3fb3e2
 #..........................................................................
3fb3e2
 
3fb3e2
+# Check whether an item POD section contains any documentation text. The POD
3fb3e2
+# section is passed as refernce to list of lines.
3fb3e2
+# If there is no text, return true; otherwise false.
3fb3e2
+sub item_has_no_text {
3fb3e2
+    for (@{$_[0]}) {
3fb3e2
+        next if /^=over\s/;
3fb3e2
+        next if /^=item\s/;
3fb3e2
+        next if /^X</;
3fb3e2
+        next if /^\s*$/;
3fb3e2
+        return 0;
3fb3e2
+    }
3fb3e2
+    return 1;
3fb3e2
+}
3fb3e2
+
3fb3e2
 sub search_perlop {
3fb3e2
   my ($self,$found_things,$pod) = @_;
3fb3e2
 
3fb3e2
@@ -1166,60 +1180,92 @@ sub search_perlop {
3fb3e2
 
3fb3e2
   my $thing = $self->opt_f;
3fb3e2
 
3fb3e2
-  my $previous_line;
3fb3e2
+  my @previous_lines;
3fb3e2
+  my $stop_line;
3fb3e2
+  my $wrap_into_over;
3fb3e2
   my $push = 0;
3fb3e2
-  my $seen_item = 0;
3fb3e2
-  my $skip = 1;
3fb3e2
+  my $pod_candidate = [];
3fb3e2
 
3fb3e2
   while( my $line = <$fh> ) {
3fb3e2
     $line =~ /^=encoding\s+(\S+)/ && $self->set_encoding($fh, $1);
3fb3e2
-    # only start search after we hit the operator section
3fb3e2
-    if ($line =~ m!^X<operator, regexp>!) {
3fb3e2
-        $skip = 0;
3fb3e2
-    }
3fb3e2
 
3fb3e2
-    next if $skip;
3fb3e2
-
3fb3e2
-    # strategy is to capture the previous line until we get a match on X<$thingy>
3fb3e2
-    # if the current line contains X<$thingy>, then we push "=over", the previous line, 
3fb3e2
-    # the current line and keep pushing current line until we see a ^X<some-other-thing>, 
3fb3e2
-    # then we chop off final line from @$pod and add =back
3fb3e2
+    # A strategy is to capture the previous lines from =head or =item until we
3fb3e2
+    # get a match on X<$thing>.  If the current line contains X<$thing>, then
3fb3e2
+    # we push "=over" (in case of =item), the previous lines, the current line
3fb3e2
+    # and keep pushing current line until we see a terminating POD keyworkd
3fb3e2
+    # (=head, =item, =over, corrsponding to the starting POD keyword). Then we
3fb3e2
+    # append =back (in case of =item).
3fb3e2
     #
3fb3e2
-    # At that point, Bob's your uncle.
3fb3e2
-
3fb3e2
-    if ( $line =~ m!X<+\s*\Q$thing\E\s*>+!) {
3fb3e2
-        if ( $previous_line ) {
3fb3e2
-            push @$pod, "=over 8\n\n", $previous_line;
3fb3e2
-            $previous_line = "";
3fb3e2
+    # If this was =item, we are done. If the =item was empty (like two
3fb3e2
+    # consequtive =item-s documented at once) we continue gathering other
3fb3e2
+    # =item-s until we get some content. Then we are done.
3fb3e2
+    #
3fb3e2
+    # If this was a =head, we stash the POD section and do another search in
3fb3e2
+    # hope we will found =item section. (=item sections tends to be more
3fb3e2
+    # focused on =X<$thing> than =head sections.) If did not found any =item
3fb3e2
+    # section, we will return the last found =head section.
3fb3e2
+
3fb3e2
+    if ( $line =~ m!X<+\s*\Q$thing\E\s*>+! ) {
3fb3e2
+        if ( @previous_lines ) {
3fb3e2
+            push @$pod_candidate, "=over 8\n\n" if $wrap_into_over;
3fb3e2
+            push @$pod_candidate, @previous_lines;
3fb3e2
+            @previous_lines = ();
3fb3e2
         }
3fb3e2
-        push @$pod, $line;
3fb3e2
+        push @$pod_candidate, $line;
3fb3e2
         $push = 1;
3fb3e2
 
3fb3e2
     }
3fb3e2
-    elsif ( $push and $line =~ m!^=item\s*.*$! ) {
3fb3e2
-        $seen_item = 1;
3fb3e2
-    }
3fb3e2
-    elsif ( $push and $seen_item and $line =~ m!^X<+\s*[ a-z,?-]+\s*>+!) {
3fb3e2
+    elsif ( $push and $line =~ m/$stop_line/ ) {
3fb3e2
         $push = 0;
3fb3e2
-        $seen_item = 0;
3fb3e2
-        last;
3fb3e2
+
3fb3e2
+        # X exists twice in perlop. Prefer =item location over =head
3fb3e2
+        # location. We assume =item is more specific.
3fb3e2
+        if ($wrap_into_over) {
3fb3e2
+            # However, the X =item section is empty (except of bunch of
3fb3e2
+            # X<> kewords) and documented in the next =item section. Thus
3fb3e2
+            # continue until the so far gathered text looks empty.
3fb3e2
+            if ($line =~ /^=item\s/ && item_has_no_text($pod_candidate)) {
3fb3e2
+                $push = 1;
3fb3e2
+                push @$pod_candidate, $line;
3fb3e2
+                # and continue appending following =item section
3fb3e2
+            } else {
3fb3e2
+                # We have an =item with a content.
3fb3e2
+                push @$pod_candidate, "\n\n=back\n";
3fb3e2
+                # Replace pod with the candidate
3fb3e2
+                @$pod = @$pod_candidate;
3fb3e2
+                last;
3fb3e2
+            }
3fb3e2
+        } else {
3fb3e2
+            # Copy the candidate to pod
3fb3e2
+            push @$pod, @$pod_candidate;
3fb3e2
+            $pod_candidate = [];
3fb3e2
+            # And search for another occurance of the X<> reference with the
3fb3e2
+            # prospect it will be an =item.
3fb3e2
+        }
3fb3e2
     }
3fb3e2
     elsif ( $push ) {
3fb3e2
-        push @$pod, $line;
3fb3e2
-    }
3fb3e2
-
3fb3e2
-    else {
3fb3e2
-        $previous_line = $line;
3fb3e2
+        push @$pod_candidate, $line;
3fb3e2
+    }
3fb3e2
+
3fb3e2
+    if ( !$push ) {
3fb3e2
+        # Gather a smallest block starting with "=head" or "=item"
3fb3e2
+        if ($line =~ /^=head([1234])\s/) {
3fb3e2
+            $stop_line = join('', 1..$1);
3fb3e2
+            $stop_line = qr/^=head[$stop_line]\s/;
3fb3e2
+            $wrap_into_over = 0;
3fb3e2
+            @previous_lines = ();
3fb3e2
+        } elsif ($line =~ /^=item\s/) {
3fb3e2
+            $stop_line = qr/^=(?:item\s|back\b)/;
3fb3e2
+            $wrap_into_over = 1;
3fb3e2
+            @previous_lines = ();
3fb3e2
+        }
3fb3e2
+        push @previous_lines, $line;
3fb3e2
     }
3fb3e2
 
3fb3e2
   } #end while
3fb3e2
 
3fb3e2
   # we overfilled by 1 line, so pop off final array element if we have any
3fb3e2
   if ( scalar @$pod ) {
3fb3e2
-    pop @$pod;
3fb3e2
-
3fb3e2
-    # and add the =back
3fb3e2
-    push @$pod, "\n\n=back\n";
3fb3e2
     DEBUG > 8 and print "PERLOP POD --->" . (join "", @$pod) . "<---\n";
3fb3e2
   }
3fb3e2
   else {
3fb3e2
diff --git a/t/03_builtin_pod_output.t b/t/03_builtin_pod_output.t
3fb3e2
index 70f8549..d42a242 100644
3fb3e2
--- a/t/03_builtin_pod_output.t
3fb3e2
+++ b/t/03_builtin_pod_output.t
3fb3e2
@@ -24,6 +24,14 @@ my %builtins = (
3fb3e2
         qr/\A\s+"tr\/\*SEARCHLIST\*\/\*REPLACEMENTLIST\*\/cdsr"\n/,
3fb3e2
         qr/\n\s+eval "tr\/\$oldlist\/\$newlist\/, 1" or die \$\@;\n\n\z/
3fb3e2
     ],
3fb3e2
+    '==' => [ # CPAN RT#126015
3fb3e2
+        qr/\A\s+Equality Operators\n/,
3fb3e2
+        qr/\n\s+if \( fc\(\$x\) eq fc\(\$y\) \) \{ \.\.\. \}\n\n\z/
3fb3e2
+    ],
3fb3e2
+    '<>' => [ # CPAN RT#126015
3fb3e2
+        qr/\A\s+I\/O Operators\n/,
3fb3e2
+        qr/\n\s+for its regular truth value\.\n\n\z/
3fb3e2
+    ]
3fb3e2
 );
3fb3e2
 
3fb3e2
 plan tests => 5 * scalar keys %builtins;
3fb3e2
-- 
3fb3e2
2.21.0
3fb3e2