This is useful in many man pages like date , dd, od, tr, ...
where there are tables presented, where extraneous lines
between each entry are best avoided.

* man/help2man: Use .PD 0 (Paragraph Distance)
to avoid extraneous blank lines within .TP delineated tables.
Also use explicit widths with .TP in such tables,
to preserve the alignment from the --help output.
---
 man/help2man | 83 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 78 insertions(+), 5 deletions(-)

diff --git a/man/help2man b/man/help2man
index 1aad1ad4d..9c45d3e39 100755
--- a/man/help2man
+++ b/man/help2man
@@ -49,6 +49,8 @@ sub program_basename;
 sub get_option_value;
 sub convert_option;
 sub fix_italic_spacing;
+sub generic_indented_tag_line;
+sub indented_tag_line;
 sub set_indent;
 sub visual_length;
 
@@ -277,6 +279,10 @@ my $program = program_basename $ARGV[0];
 my $package = $program;
 my $version;
 
+# Normalize help text that embeds argv[0], so examples are formatted
+# using the displayed program name rather than a temporary build path.
+$help_text =~ s/\Q$ARGV[0]\E/$program/g if $ARGV[0] ne $program;
+
 if ($opt_output)
 {
     unlink $opt_output or kark N_("%s: can't unlink %s (%s)"),
@@ -448,27 +454,33 @@ s/([^\n])\n($PAT_BUGS|$PAT_AUTHOR|$PAT_SEE_ALSO) 
/$1\n\n$2 /og;
 s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
 
 my $require_mono = 0;
+my $compact_indented_tags = 0;
+my $blank_before_paragraph = 0;
 while (length)
 {
     # Convert some standard paragraph names.
     if (s/^($PAT_OPTIONS): *\n+//o)
     {
        $sect = _('OPTIONS');
+       $blank_before_paragraph = 0;
        next;
     }
     if (s/^($PAT_ENVIRONMENT): *\n+//o)
     {
        $sect = _('ENVIRONMENT');
+       $blank_before_paragraph = 0;
        next;
     }
     if (s/^($PAT_FILES): *\n+//o)
     {
        $sect = _('FILES');
+       $blank_before_paragraph = 0;
        next;
     }
     elsif (s/^($PAT_EXAMPLES): *\n+//o)
     {
        $sect = _('EXAMPLES');
+       $blank_before_paragraph = 0;
        next;
     }
 
@@ -478,6 +490,7 @@ while (length)
        $sect = uc $1;
        $sect =~ tr/*/ /;  # also accept *Section*Name*
        push @sections, $sect;
+       $blank_before_paragraph = 0;
        next;
     }
 
@@ -533,6 +546,8 @@ while (length)
 
     my $indent = 0;
     my $content = '';
+    my $tag_line_indent;
+    my $tag_line_width;
 
     # Option with description.
     if (s/^( {1,10}([+-]\S.*?))(?:(  +(?!-))|\n( {7,}))(\S.*)\n//)
@@ -556,11 +571,14 @@ while (length)
     }
 
     # Indented paragraph with tag.
-    elsif (s/^( +(\S.*?)  +)(\S.*)\n//)
+    elsif (s/^(( +)(\S.*?)  +)(\S.*)\n//)
     {
        $matched .= $& if %append_match;
-       $indent = set_indent visual_length $1;
-       $content = ".TP\n\x84$2\n\x84$3\n";
+       $tag_line_width = (visual_length $1) - (visual_length $2);
+       $tag_line_width = 1 if $tag_line_width < 1;
+       $indent = set_indent $tag_line_width;
+       $content = ".TP\n\x84$3\n\x84$4\n";
+       $tag_line_indent = $2;
     }
 
     # Indented paragraph.
@@ -587,8 +605,42 @@ while (length)
        $content .= "\x84$1\n";
     }
 
-    # Move to next paragraph.
-    s/^\n+//;
+    # Consecutive generic tagged rows are dense tables.  Keep .TP's
+    # hanging indentation, but suppress inter-paragraph distance.
+    my $is_indented_tag = $content =~ /^\.TP\n/ && defined $tag_line_indent;
+    my $next_indented_tag = $is_indented_tag
+       && indented_tag_line ($_, $tag_line_indent);
+    my $compact_this_tag = $is_indented_tag
+       && ($compact_indented_tags || $next_indented_tag);
+    my $preserve_blank_after = 0;
+
+    if ($compact_this_tag)
+    {
+       $content =~ s/^\.TP\n/.TP $tag_line_width\n/;
+       unless ($compact_indented_tags)
+       {
+           $content = ".PD 0\n$content";
+           $content = ".PP\n$content" if $blank_before_paragraph;
+           $compact_indented_tags = 1;
+       }
+       unless ($next_indented_tag)
+       {
+           $content .= ".PD\n";
+           (my $next_paragraph = $_) =~ s/^\n+//;
+           $preserve_blank_after = /^\n/
+               && generic_indented_tag_line $next_paragraph;
+           $content .= ".PP\n" if $preserve_blank_after;
+           $compact_indented_tags = 0;
+       }
+    }
+    elsif ($compact_indented_tags)
+    {
+       $content = ".PD\n$content";
+       $compact_indented_tags = 0;
+    }
+
+    $blank_before_paragraph = s/^\n+//;
+    $blank_before_paragraph = 0 if $preserve_blank_after;
 
     for ($content)
     {
@@ -859,6 +911,27 @@ sub fix_italic_spacing
     return $_;
 }
 
+# Return true if text starts with a generic indented tag row using
+# the same leading indentation.  Option rows are handled separately.
+sub generic_indented_tag_line
+{
+    my $text = shift;
+
+    return 0 unless $text =~ /^ +\S.*?  +\S.*\n/;
+    return 0 if $text
+       =~ /^( {1,10}[+-]\S.*?)(?:(  +(?!-))|\n( {7,}))(\S.*)\n/;
+    return 0 if $text =~ /^ {1,10}[+-]\S.*\n/;
+    return 1;
+}
+
+sub indented_tag_line
+{
+    my ($text, $leading_indent) = @_;
+
+    return $text =~ /^\Q$leading_indent\E/
+       && generic_indented_tag_line $text;
+}
+
 # Return indent to use: either the value passed in, or $v,$v+4 if
 # loose index matching is used.  The resulting string is used in a
 # regex as " {$indent}", so will match either the exact number of
-- 
2.54.0


Reply via email to