zsh-workers
 help / color / mirror / code / Atom feed
From: Peter Stephenson <pws@csr.com>
To: zsh-workers@sunsite.dk
Subject: Re: Please add pinfo completion
Date: Tue, 10 Oct 2006 18:59:59 +0100	[thread overview]
Message-ID: <20061010185959.c84c0b49.pws@csr.com> (raw)
In-Reply-To: <20061010142200.GC17674@prunille.vinc17.org>

Vincent Lefevre <vincent@vinc17.org> wrote:
> > compdef _gnu_generic pinfo
>
> One problem is that it doesn't give help text. So, is there a way
> to generate a completion file (to be completed), assuming that the
> command has the --help feature?

OK, here is _arguments updated to provide option descriptions from --help
text automatically.

It'll be a little slower since a horrible nested parameter substitution has
turned into a loop.  (I didn't even try to understand it in too much depth,
I just started again from scratch.)  However, there is in any case a cache,
and there was an external program to run at that point anyway, so I don't
think it'll make much difference.

In my case when using _gnu_generic for pinfo completion (with some
non-standard configuration settings; you're unlikely to get exactly the
same), "pinfo --^D" gives me

Completing option
--apropos                        # call apropos if nothing found
--clear-at-exit                  # clear screen at exit
--cut-man-headers                # cut out repeated man headers
--dont-handle-without-tag-table  # don't display texinfo pages without tag
--file                           # synonym for -r
--force-manual-tag-table         # force manual detection of tag table
--help                           # help
--long-manual-links              # use long link names in manuals
--manual                         # use man page
--node                           # jump directly to the node nodename
--plain-apropos                  # call only apropos
--raw-filename                   # use raw filename
--rcfile                         # use alternate rcfile
--squeeze-manlines               # cut empty lines from manual pages
--version                        # version

which certainly impressed me, I can tell you.

After fiddling with _arguments for an hour, I'd like to say "if there's a
problem, DEAL WITH IT", but since I'm now a professional software engineer,
I'll have a go at fixing any problems I've created with this change; there
are bound to be some.

Note in particular I found some problems with optional arguments like
"--option[=STUFF]" and tried to address them, but this isn't properly
tested.  It looked like somebody had fixed previous problems just by
treating them as mandatory arguments, but the code should have handled them
better than that.

I have to admit this was at least more tractable than the other problem
I've been tackling today.

Index: Completion/Base/Utility/_arguments
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Base/Utility/_arguments,v
retrieving revision 1.17
diff -u -r1.17 _arguments
--- Completion/Base/Utility/_arguments	27 Sep 2006 16:53:59 -0000	1.17
+++ Completion/Base/Utility/_arguments	10 Oct 2006 17:52:22 -0000
@@ -6,6 +6,7 @@
 local long cmd="$words[1]" descr mesg subopts opt usecc autod
 local oldcontext="$curcontext" hasopts rawret optarg singopt alwopt
 local setnormarg
+local -a match mbegin mend
 
 long=$argv[(I)--]
 if (( long )); then
@@ -68,32 +69,59 @@
     # those hyphens and anything from the space or tab after the
     # option up to the end.
 
-    lopts=("--${(@)${(@)^${(@)${(@)${(@M)${(@ps:\n:j:\n:)${(@)${(@M)${(@f)$(_call_program options ${~words[1]} --help 2>&1)//\[--/
---}:#[ 	]#-*}//,/
-}}:#[ 	]#--*}#*--}%%[]	 ]*}:#}//\[=/=}")
+   _call_program options ${~words[1]} --help 2>&1 | while read opt; do
+     tmp=()
+     while [[ $opt = [,[:space:]]#(#b)(-[^,[:space:]]#)(*) ]]; do
+       # We used to remove the brackets from "[=STUFF]",
+       # but later the code appears to handle it with the brackets
+       # present.  Maybe the problem was that the intervening code
+       # didn't.  If it's buggy without removing them, the problem
+       # probably is later, not here.
+       if [[ -z ${tmp[(r)${match[1]%%[^a-zA-Z0-9-]#}]} ]]; then
+	 tmp+=($match[1])
+       fi
+       opt=$match[2]
+     done
+     # If there's left over text, assume it's a description; it
+     # may be truncated but if it's too long it's no use anyway.
+     # There's one hiccup: we sometimes get descriptions like
+     # --foo fooarg   Do some foo stuff with foo arg
+     # and we need to remove fooarg.  Use whitespace for hints.
+     opt=${opt## [^[:space:]]##  }
+     opt=${opt##[[:space:]]##}
+     # Add description after a ":", converting any : in the description
+     # to a -.  Use RCQUOTES to append this to all versions of the option.
+     lopts+=("${^tmp[@]}"${opt:+:${opt//:/-}})
+   done
 
     # Remove options also described by user-defined specs.
 
     tmp=()
-    for opt in "${(@)${(@)lopts:#--}%%\=*}"; do
+    # Ignore any argument and description information when searching
+    # the long options array here and below.
+    for opt in "${(@)${(@)lopts:#--}%%[\[:=]*}"; do
 
       # Using (( ... )) gives a parse error.
 
       let "$tmpargv[(I)(|\([^\)]#\))(|\*)${opt}(|[-+]|=(|-))(|\[*\])(|:*)]" ||
-          tmp=( "$tmp[@]" "$lopts[(r)$opt(|=*)]" )
+          tmp=( "$tmp[@]" "$lopts[(r)$opt(|[\[:=]*)]" )
     done
     lopts=( "$tmp[@]" )
 
     # Now remove all ignored options ...
 
     while (( $#iopts )); do
-      lopts=( ${lopts:#$~iopts[1]} )
+      lopts=( ${lopts:#$~iopts[1](|[\[:=]*)} )
       shift iopts
     done
 
     # ... and add "same" options
 
     while (( $#sopts )); do
+      # This implements adding things like --disable-* based
+      # on the existence of --enable-*.
+      # TODO: there's no anchoring here, is that correct?
+      # If it's not, careful with the [\[:=]* stuff.
       lopts=( $lopts ${lopts/$~sopts[1]/$sopts[2]} )
       shift 2 sopts
     done
@@ -110,9 +138,15 @@
       # First, we get the pattern and the action to use and take them
       # from the positional parameters.
 
+      # This is the first bit of the arguments in the special form
+      # for converting --help texts, taking account of any quoting
+      # of colons.
       pattern="${${${(M)1#*[^\\]:}[1,-2]}//\\\\:/:}"
+      # Any action specifications that go with it.
       descr="${1#${pattern}}"
       if [[ "$pattern" = *\(-\) ]]; then
+	# This is the special form to disallow arguments
+	# in the next word.
         pattern="$pattern[1,-4]"
 	dir=-
       else
@@ -124,8 +158,10 @@
       # list we have built. If no option matches the pattern, we
       # continue with the next.
 
-      tmp=("${(@M)lopts:##$~pattern}")
-      lopts=("${(@)lopts:##$~pattern}")
+      # Ignore :descriptions at the ends of lopts for matching this;
+      # they aren't in the patterns.
+      tmp=("${(@M)lopts:##$~pattern(|:*)}")
+      lopts=("${(@)lopts:##$~pattern(|:*)}")
 
       (( $#tmp )) || continue
 
@@ -140,11 +176,28 @@
 
         if [[ "$descr" = :\=* ]]; then
           for opt in "$tmpo[@]"; do
-            cache=( "$cache[@]"
-                    "${${opt%%\=*}//[^a-zA-Z0-9-]}=::${(L)${opt%\]}#*\=}: " )
+	    # Look for --option:description and turn it into
+	    # --option[description].  We didn't do that above
+	    # since it could get confused with the [=ARG] stuff.
+	    if [[ $opt = (#b)(*):([^:]#) ]]; then
+	      opt=$match[1]
+	      descr="[${match[2]}]"
+	    else
+	      descr=
+	    fi
+            cache=(
+	      "$cache[@]"
+	      "${${opt%%\=*}//[^a-zA-Z0-9-]}=${descr}::${(L)${opt%\]}#*\=}: "
+	    )
           done
         else
-          tmpo=("${(@)${(@)tmpo%%\=*}//[^a-zA-Z0-9-]}")
+	  # We don't handle the [description] form here.
+	  # TODO: we could with a bit of rewriting.
+	  #
+	  # The "[" didn't get removed here until I added it.
+	  # This may be why we used to try to remove the square brackets
+	  # higher up.
+          tmpo=("${(@)${(@)tmpo%%\[\=*}//[^a-zA-Z0-9-]}")
           if [[ "$descr" = ::* ]]; then
 	    cache=( "$cache[@]" "${(@)^tmpo}=${dir}${descr}" )
           else
@@ -154,6 +207,8 @@
       fi
 
       # Descriptions with `=': mandatory argument.
+      # Basically the same as the foregoing.
+      # TODO: could they be combined?
 
       tmpo=("${(@M)tmp:#*\=*}")
       if (( $#tmpo )); then
@@ -161,8 +216,16 @@
 
         if [[ "$descr" = :\=* ]]; then
           for opt in "$tmpo[@]"; do
-            cache=( "$cache[@]"
-                    "${${opt%%\=*}//[^a-zA-Z0-9-]}=:${(L)${opt%\]}#*\=}: " )
+	    if [[ $opt = (#b)(*):([^:]#) ]]; then
+	      opt=$match[1]
+	      descr="[${match[2]}]"
+	    else
+	      descr=
+	    fi
+            cache=(
+	      "$cache[@]"
+	      "${${opt%%\=*}//[^a-zA-Z0-9-]}=${descr}:${(L)${opt%\]}#*\=}: "
+	    )
           done
         else
           tmpo=("${(@)${(@)tmpo%%\=*}//[^a-z0-9-]}")
@@ -175,7 +238,15 @@
       # as described by $descr.
 
       if (( $#tmp )); then
-        tmp=("${(@)tmp//[^a-zA-Z0-9-]}")
+        tmp=(
+	  # commands with a description of the option (as opposed
+	  # to the argument, which is what descr contains): needs to be
+	  # "option[description]".
+	  # Careful: \[ on RHS of substitution keeps the backslash,
+	  # I discovered after about half an hour, so don't do that.
+	  "${(@)^${(@)tmp:#^*:*}//:/[}]"
+	  # commands with no description
+	  "${(@)${(@)tmp:#*:*}//[^a-zA-Z0-9-]}")
         if [[ -n "$descr" && "$descr" != ': :  ' ]]; then
 	  cache=( "$cache[@]" "${(@)^tmp}${descr}" )
         else

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


To access the latest news from CSR copy this link into a web browser:  http://www.csr.com/email_sig.php


  parent reply	other threads:[~2006-10-10 18:00 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-10-07  1:35 Vincent Lefevre
2006-10-07 15:27 ` Nikolai Weibull
2006-10-08 21:13 ` Mikael Magnusson
2006-10-10 14:22   ` Vincent Lefevre
2006-10-10 15:29     ` Bart Schaefer
2006-10-11  1:03       ` Vincent Lefevre
2006-10-10 17:59     ` Peter Stephenson [this message]
2006-10-10 21:23       ` Peter Stephenson
2006-10-11  2:48       ` Andrey Borzenkov
     [not found]         ` <200610110933.k9B9XJTB021853@news01.csr.com>
2006-10-11 15:43           ` Andrey Borzenkov
2006-10-11 16:30             ` Peter Stephenson
2006-10-11  2:52       ` Andrey Borzenkov

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=20061010185959.c84c0b49.pws@csr.com \
    --to=pws@csr.com \
    --cc=zsh-workers@sunsite.dk \
    /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.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

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).