discuss@mandoc.bsd.lv
 help / color / mirror / Atom feed
From: Ingo Schwarze <schwarze@usta.de>
To: Paul Onyschuk <ptmelville@gmail.com>
Cc: discuss@mdocml.bsd.lv
Subject: man(1) replacement
Date: Sun, 10 Aug 2014 03:23:05 +0200	[thread overview]
Message-ID: <20140810012305.GB32716@iris.usta.de> (raw)
In-Reply-To: <20140809190923.aa172f22b838ade5621fe601@gmail.com>

Hi Paul,

Paul Onyschuk wrote on Sat, Aug 09, 2014 at 07:09:23PM +0200:

> I also have additional question.  Are there any plans for providing
> man(1) command also?  This would make mdocml a possible, standalone
> replacement for groff and man-db combination (typical in Linux
> distributions).

Well, that's almost ready, actually; not for 1.13.1, though.

The file implementing it is manpage.c.  Try this:

  make clean
  make
  sudo ./makewhatis
  make manpage
  ./manpage setitimer

Ironically, there isn't a manpage for manpage(1).  ;-)

What it does is basically this:

It takes the same options and arguments as apropos(1), except that
the -O option is not available.

If it finds exactly one result, it shows that manual, just like the
traditional man(1).

If it finds more than one result, it shows the list of manuals,
similar to apropos(1), but with serial numbers in front.
When running on a terminal, it interactively asks you to
select one of the numbers, defaulting to number 1, then shows
that manual.

I dislike the interactive prompting so much that i never enabled
it in the build, but when you say "make manpage", it does build
and run.

Obviously, commands like

  manpage ls

are almost useless, and

  manpage Nm~^ls\$

which is equivalent to "man ls", is hard to type.

Having reconsidered all this, here is what i will do for 1.13.2:

 * Provide one single binary program, integrating all the
   functionality of mandoc(1), man(1), apropos(1), and whatis(1).

 * Provide four argument input modes:
    - filenames:   ["mandoc"]
      Each argument is a relative or absolute pathname to a file,
      like in traditional mandoc(1).
    - names:   ["man"]
      Each argument is a complete, literal name of a manual,
      like in traditional man(1).
    - words:   ["man -f"]
      Each argument is a literal string and will be matched against
      whole words in manual names, like in traditional whatis(1).
    - expressions:   ["man -k"]
      Arguments are full apropos(1) expressions.
      As a special case, arguments containing neither '=' nor '~'
      are literal strings and will be matched against substrings in
      manual names and descriptions, like in traditional apropos(1).

 * Provide five output modes:
    - one:   ["man"]
      Among the matching files, one will be selected according
      to traditional precedence rules, and this one file will
      be formatted and shown.  If on a terminal, the command is man,
      and -c was not given, a pager is used.
    - all:   ["man -a"]
      All matching files will be formatted and shown one after
      the other, using a pager as above.
    - filenames:   ["man -w"]
      Only the filenames of all matching files are shown.
    - list:   ["man -k", "man -f"]
      The names and descriptions of all matching files will be
      listed like in traditional apropos(1) and whatis(1).
    - ask:   ["man -i"]
      If there is exactly one matching file, it will be formatted
      and shown.  If there is more than one, the names and
      descriptions will be listed, and if on a terminal, the user
      will be asked for a choice, like in manpage(1).

The following combinations are useful:

  arguments    output     command  alias       comment
  ---------    ------     -------  -----       -------
  filenames    all        mandoc               no change
  names        one        man                  new in mandoc
  names        ask        man -i               completely new
  names        all        man -a               new in mandoc
  names        filenames  man -w               new in mandoc
  words        list       man -f   whatis      no change
  words        ask        man -fi  whatis -i   completely new
  words        all        man -fa  whatis -a   completely new 
  words        filenames  man -fw  whatis -w   completely new
  expressions  list       man -k   apropos     no change
  expressions  ask        man -ki  apropos -i  replaces manpage(1)
  expressions  all        man -ka  apropos -a  completely new
  expressions  filenames  man -kw  apropos -w  completely new

That looks like a compact, consistent, and feature-complete interface:

 * man(1) defaults to arguments:names, output:one as before
 * -f switches to arguments:words, output:list as before
 * -k switches to arguments:expressions, output:list as before
 * -i switches to output:ask in all three cases (new)
 * -a switches to output:all in all three cases (new for -fk)
 * -w switches to output:filenames in all three cases (new for -fk)
 * output:one would be useless with -f and -k
 * all except output:all would be useless with mandoc(1)

I'm not likely to turn into an avid user of -i, but in that complete
feature set, i no longer dislike it so much that i feel unwilling
to integrate it: in that set, it looks like a reasonable companion
of the names/one standard mode.  Going from names to expressions,
the following naturally correspond to each other:

  man -w  ->  man -kw
  man -a  ->  man -ka
  man     ->  man -ki

Without -i, there would be an ugly hole in the lower right corner
of the table, no sane way to get from an expression search to the
display of one single page...

Arguably, -i alone is rarely useful, nobody will type "man -i chmod"
instead of "man 2 chmod" (when remembering chmod as ambiguous) or
instead of just "man chmod" (when forgetting about the ambiguity).
So -i could be made to imply -k, making life easier for people who
want to use man -ki.  Then again, that makes the interface less
consistent, and some people may wish to set "alias man='man -i'"
as long as that doesn't imply -k; but nobody is likely to want -k
by default.  So i tend to have -i not imply -k.

Implementing all this looks nearly trivial:  Basically, all the
required code is already available in main.c, apropos.c, and
manpage.c, it merely needs some reshuffling and polishing.

So, thanks for asking that question.  :-)

If you switch to that system when 1.13.2 comes out, you just have
to remember one thing: It strictly requires keeping the mandoc.db(5)
files up-to-date in all your manual trees.  If you manually copy a
new page to /usr/local/man/man1/foo.1 and forget to run "makewhatis
-d /usr/local/man man1/foo.1" then "man foo" will *not* find your
new page!

And, admittedly, it causes some slowdown.  Querying a database
is not for free.  On my notebook:

 $ time sh -c 'for i in `jot 100`; do man -w ksh; done > /dev/null'  
    0m1.47s real     0m0.32s user     0m1.12s system
 $ time sh -c 'for i in `jot 100`; do whatis ksh; done > /dev/null' 
    0m2.53s real     0m1.74s user     0m0.78s system

 $ time sh -c 'for i in `jot 100`; do mandoc cat.1; done > /dev/null'  
    0m0.58s real     0m0.24s user     0m0.29s system
 $ time sh -c 'for i in `jot 100`; do mandoc ksh.1; done > /dev/null'  
    0m5.12s real     0m4.08s user     0m0.97s system
 $ time sh -c 'for i in `jot 100`; do man ksh; done > /dev/null'  
    0m5.89s real     0m4.23s user     0m1.58s system

So:

 - find a manual with traditional man:  15 milliseconds
 - find a manual in the SQL database:   25 milliseconds
 - format a small manual:                5 milliseconds
 - format a huge manual:                50 milliseconds

That looks like roughly a 50% increase in man page serving
time, 15+5=20 -> 25+5=30 milliseconds, very imprecisely.
Not relevant on modern hardware, but likely noticable
on a VAX...

Yours,
  Ingo
--
 To unsubscribe send an email to discuss+unsubscribe@mdocml.bsd.lv

  parent reply	other threads:[~2014-08-10  1:23 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-09 10:38 Portability of fts() functions Paul Onyschuk
2014-08-09 15:49 ` Ingo Schwarze
2014-08-09 17:09   ` Paul Onyschuk
2014-08-09 21:59     ` Ingo Schwarze
2014-08-09 23:26       ` Paul Onyschuk
2014-08-10  2:46         ` Ingo Schwarze
2014-08-10  1:23     ` Ingo Schwarze [this message]
2014-08-10 10:53   ` Paul Onyschuk
2014-08-11  3:28     ` Ingo Schwarze

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140810012305.GB32716@iris.usta.de \
    --to=schwarze@usta.de \
    --cc=discuss@mdocml.bsd.lv \
    --cc=ptmelville@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).