Hello Alejandro,

Alejandro Colomar wrote on Fri, Jun 06, 2025 at 01:16:27AM +0200:

> Talking about this,  I've now finished my changes, and was trying to
> pass the usual linters.  mandoc(1) is complaining:
> 
>       alx@devuan:~/tmp$ cat pp.man 
>       .TH A 7 2025-06-06 f
>       .SH g
>       foo
>       .P
>       .SY foo
>       bar
>       baz
>       .YS
>       alx@devuan:~/tmp$ mandoc -Tlint -man pp.man 
>       mandoc: pp.man:4:2: WARNING: skipping paragraph macro: PP empty

I can confirm that still happens with mandoc -current and i think
it's correct to throw that warning, for the following reason.

Your example formats byte-by-byte identically with mandoc
and with groff-1.23.0, with a single blank line between the two foos.

If i delete the .P macro from your example, it still formats
byte-by-byte identically with mandoc and with groff-1.23.0,
still with a single blank line between the two foos, completely
unchanged.

Consequently, the warning is correct.  Whatever the author hoped
that .P macro might do, it is not doing anything, and the author
should be warned that he is trying something that has no effect.

> I'm considering the following commit:
> 
>       commit a2524028e0cb358356f6c8574a4e8d3ded451a72
>       Author: Alejandro Colomar <a...@kernel.org>
>       Date:   Fri Jun 6 01:11:06 2025 +0200
> 
>           share/mk/lint/man/mandoc.ignore.grep: Ignore false positive
>           
>           It seems mandoc(1) considers a paragraph that consists
>           solely of SY/YS

That phrase is totally nonsensical.  In stark contrast to the mdoc(7)
language, the man(7) language does *not* have any concept of nesting
blocks.

>           to be empty.  It is not empty.

It absolutely is empty because the .SY block terminates the .P block.
That is a very fundamental aspect of the syntax of the man(7) language:

   $ mandoc -O noval -T tree pp.man
  [...]
  SH (body) 2:2
      foo (text) *3:1
      P (block) *4:2
        P (head) 4:2
        P (body) 4:2  # look here, i'm indeed empty.
      SY (block) *5:2
        SY (head) 5:2
            foo (text) 5:5
        SY (body) 5:2
            bar (text) *6:1
            baz (text) *7:1
      YS (elem) *8:2

For that reason, the validation stage deletes the empty paragraph
because it has no effect anyway:

   $ mandoc -T tree pp.man
  [...]
  SH (body) 2:2
      foo (text) *3:1
      SY (block) *5:2
        SY (head) 5:2
            foo (text) 5:5
        SY (body) 5:2
            bar (text) *6:1
            baz (text) *7:1
      YS (elem) *8:2

>  Let's ignore mandoc(1).

???

When you do that, you are almost certainly misunderstanding something.
While some other linters throw substantial amounts of warnings,
including occasionally false positives, i'm very careful to avoid
false positives in mandoc(1), and even more defensively for man(7)
than for mdoc(7).

>       +++ b/share/mk/lint/man/mandoc.ignore.grep
>       @@ -6,5 +6,6 @@ STYLE: referenced manual not found: Xr
>        UNSUPP: ignoring macro in table:
>        WARNING: empty block: UR
>        WARNING: missing date, using "": TH
>       +WARNING: skipping paragraph macro: PP empty
>        WARNING: undefined escape, printing literally: \\\\
>        WARNING: cross reference to self: Xr

Whoa, what the hell?  Why are you running -T lint at all just to
throw tons of stuff away?  These are all very serious mistakes
that should definitely be fixed, maybe with the exception of
the first one, which could be regarded as a missing feature in
mandoc(1) - though such an exceedingly difficult feature that
it won't get done any time soon, so probably manual pages
should back away from doing that kind of stuff, too.

Yours,
  Ingo

Reply via email to