1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-08-13 05:32:19 +02:00

doc: help2man: preserve layout of tables

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.
This commit is contained in:
Pádraig Brady
2026-05-08 19:39:00 +01:00
parent 77cf018777
commit ab18e90e8b
+78 -5
View File
@@ -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