Hello Stefan,

Stefan Hagen wrote on Sun, Sep 03, 2023 at 04:19:07PM +0100:

> I think Espies suggestion is more discoverable because the user gets a
> message on install he might see.

Granted.  Then again, rumour has it that people rarely heed post-install
messages from pkg_add(1).

> Ingos suggestion is technically "more correct". However, I asked 6 devs
> and only one knew what -a/w does. So I don't think this is used.

Interesting and astonishing to me.  The -w option originated in
VersionĀ 7 AT&T UNIX and -w in 4.3BSD-Tahoe.  I certainly use both of
them *very* often, usually many times every day, and feel surprised
that people apparently get along without using them.  Still, useful
to know for the maintainer of a tool if an option is known to and
used by few people.

> From a user perspective, I think it would be nice if we cold make the
> manpage display a tiny bit dynamic and show the output of man -w at the
> bottom.
> 
> Example....
> 
> MANPAGE VERSIONS:
>     fvwm3-FvwmButtons(1), FvwmButtons(1)

Hm, that's an interesting idea, and i kind of like it.

However, showing such information at the bottom feels like a dubious
choice to me, in particular if many people are unaware of the -w and
-a options.  If there is more than one match, the user may be about to
read the wrong one, and they likely want that information up front,
rather than first reading the whole thing and then being told at the
end:  "Got you! This wasn't the page you were looking for."

In addition to that, showing the complete list from man -w would
force man(1) to do additional work, slowing down display of the
manual page.  When any of the -w, -a, or -k options is given, man(1)
always searches through the whole MANPATH.  By contrast, in standard
mode, i.e. without any of these three options, it ends the search
after the first database that returns a match and displays that
match right away.  For example, if you type "man printf", only the
base system manual page database is inspected and you do not have to
wait for a scan of the Xenocara and ports databases.

So, here is a patch that displays a heads-up message up front -
but only if more than one result is found in the same database.
Besides, nothing changes in -w, -a, and -k mode, this only
tweaks the default mode.

For example:

   $ man printf
  Showing:  /usr/share/man/man1/printf.1
  See also: /usr/share/man/man3/printf.3
  See also: /usr/share/man/man9/printf.9

  PRINTF(1)              General Commands Manual             PRINTF(1)

  NAME
     printf - formatted output
  [...]

   $ man chmod chown
  Showing:  /usr/share/man/man1/chmod.1
  See also: /usr/share/man/man2/chmod.2

  CHMOD(1)               General Commands Manual              CHMOD(1)

  NAME
     chmod - change file modes
  [...]
  BUGS
     There's no perm option for the naughty bits.

  OpenBSD 7.3               September 2, 2019              OpenBSD 7.3

  --------------------------------------------------------------------

  Showing:  /usr/share/man/man8/chown.8
  See also: /usr/share/man/man2/chown.2

  CHOWN(8)               System Manager's Manual              CHOWN(8)

  NAME
     chown - change file owner and group
  [...]

   $ man boot
  Showing:  /usr/share/man/man8/amd64/boot.8
  See also: /usr/share/man/man9/boot.9

  BOOT(8)            System Manager's Manual (amd64)           BOOT(8)

  NAME
     boot, boot.conf - amd64-specific second-stage bootstrap
  [...]

As a matter of fact, that's slightly similar to what man.openbsd.org
has already been doing for quite some time, even though some details
regarding presentation and priorities differ, consider:

  https://man.openbsd.org/printf
  https://man.openbsd.org/boot

Even with the patch, such headers will *not* be displayed with explict
commands like

   $ man 3 printf
   $ man -s 2 chmod chown
   $ man -S luna88k 8 boot

or when there is only one match, like in

   $ man ls
   $ man -S sparc64 boot

Does this make sense to you?

By the way, i think showing the full path (just like in man -w)
is better than just showing printf(1), printf(3), and printf(9).
In complicated cases, for example when architecture dependent,
preformatted, or compressed pages, or sections with suffixes are
involved, seeing the full path may help the user to understand at
first sight what is going on.  Even in simple cases, seing right
away whether the clash happens in base, Xenocara, ports, or in some
custom tree (which can be configured via man.conf(5), MANPATH, -m,
or -M) may also help.  On the other hand, its trivial to figure out
that to get at /usr/share/man/man3/printf.3, "man 3 printf" will work.

Then again, if people insist on showing "printf(1), printf(3), ..."
only, i can certainly tweak the patch.

Similarly, moving the information after each manual page is
trivial, but not better IMHO.

> This would bring discoverability to Ingos solution. And we could freely 
> rename manpages, because our man(1) is clever enough to find them 
> anyway. (compared to linux man, which can't do this)

True, i'm unaware of other man(1) implementations able to look up
manual pages by names that are not filenames - at least not without
using -k.

> Another idea would be to print something to stderr when more than one 
> manpage for the search term is available. Either before the pager is 
> started or after the pager is closed.

I don't really like that idea.  Even if printed before the pager is
started, the user won't typically see it until they exit the pager.
Again, quite annoying to be told you just read the wrong manual page
only after you are done reading it.

Besides, i don't think this is stderr matter.  There is no failure or
error.  Different manual pages with the same name exist by design
and are perfectly legitimate.

I think the right stream to print such information to is stdout.
This information can be considered part of the documentation:
"You ask for a manual page for 'printf'.  Actually, there is more
than one, here is a list.  And now, here comes the content of the
one that i consider as having the highest priority: ..."

> I don't like what some linuxes do: SuSE for example shows the user a 
> list and asks which one to display. This is annoying.

Indeed, no way we are going to do anything like that.

Yours,
  Ingo


Index: main.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/main.c,v
retrieving revision 1.262
diff -u -p -r1.262 main.c
--- main.c      4 Oct 2021 21:28:50 -0000       1.262
+++ main.c      3 Sep 2023 17:30:19 -0000
@@ -136,6 +136,7 @@ main(int argc, char *argv[])
        char            *auxpaths;      /* -m: additional manpaths. */
        char            *oarg;          /* -O: output option string. */
        char            *tagarg;        /* -O tag: default value. */
+       char            *cp;
        unsigned char   *uc;
        size_t           ressz;         /* Number of elements in res[]. */
        size_t           resnsz;        /* Number of elements in resn[]. */
@@ -532,6 +533,19 @@ main(int argc, char *argv[])
                                best_prio = prio;
                                ib = i;
                        }
+                       if (resnsz > 1) {
+                               mandoc_asprintf(&resn[ib].seealso,
+                                   "Showing:  %s\n", resn[ib].file);
+                               for (i = 0; i < resnsz; i++) {
+                                       if (i == ib)
+                                               continue;
+                                       cp = resn[ib].seealso;
+                                       mandoc_asprintf(&resn[ib].seealso,
+                                           "%sSee also: %s\n",
+                                           cp, resn[i].file);
+                                       free(cp);
+                               }
+                       }
                        res = mandoc_reallocarray(res, ressz + 1,
                            sizeof(*res));
                        memcpy(res + ressz++, resn + ib, sizeof(*resn));
@@ -705,6 +719,7 @@ fs_append(char **file, size_t filesz, in
                page->file = copy ? mandoc_strdup(*file) : *file;
                page->names = NULL;
                page->output = NULL;
+               page->seealso = NULL;
                page->bits = NAME_FILE & NAME_MASK;
                page->ipath = ipath;
                page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
@@ -896,6 +911,8 @@ process_onefile(struct mparse *mp, struc
                        outdata_alloc(outst, &conf->output);
                terminal_sepline(outst->outdata);
        }
+       if (resp->seealso != NULL && outst->outtype <= OUTT_TREE)
+               printf("%s\n", resp->seealso);
 
        if (resp->form == FORM_SRC)
                parse(mp, fd, resp->file, outst, conf);
Index: mansearch.c
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/mansearch.c,v
retrieving revision 1.67
diff -u -p -r1.67 mansearch.c
--- mansearch.c 26 Dec 2022 19:16:02 -0000      1.67
+++ mansearch.c 3 Sep 2023 17:30:19 -0000
@@ -196,6 +196,7 @@ mansearch(const struct mansearch *search
                        }
                        mpage->names = buildnames(page);
                        mpage->output = buildoutput(outkey, page);
+                       mpage->seealso = NULL;
                        mpage->bits = search->firstmatch ? rp->bits : 0;
                        mpage->ipath = i;
                        mpage->sec = *page->sect - '0';
@@ -394,6 +395,7 @@ mansearch_free(struct manpage *res, size
                free(res[i].file);
                free(res[i].names);
                free(res[i].output);
+               free(res[i].seealso);
        }
        free(res);
 }
Index: mansearch.h
===================================================================
RCS file: /cvs/src/usr.bin/mandoc/mansearch.h,v
retrieving revision 1.24
diff -u -p -r1.24 mansearch.h
--- mansearch.h 30 Apr 2019 18:48:26 -0000      1.24
+++ mansearch.h 3 Sep 2023 17:30:19 -0000
@@ -92,6 +92,7 @@ struct        manpage {
        char            *file; /* to be prefixed by manpath */
        char            *names; /* a list of names with sections */
        char            *output; /* user-defined additional output */
+       char            *seealso; /* preamble in OUTMODE_ONE */
        uint64_t         bits; /* name type mask */
        size_t           ipath; /* number of the manpath */
        int              sec; /* section number, 10 means invalid */

Reply via email to