From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22633 invoked from network); 10 Oct 2006 18:00:24 -0000 X-Spam-Checker-Version: SpamAssassin 3.1.6 (2006-10-03) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-2.4 required=5.0 tests=AWL,BAYES_00, FORGED_RCVD_HELO autolearn=ham version=3.1.6 Received: from news.dotsrc.org (HELO a.mx.sunsite.dk) (130.225.247.88) by ns1.primenet.com.au with SMTP; 10 Oct 2006 18:00:24 -0000 Received-SPF: none (ns1.primenet.com.au: domain at sunsite.dk does not designate permitted sender hosts) Received: (qmail 60009 invoked from network); 10 Oct 2006 18:00:18 -0000 Received: from sunsite.dk (130.225.247.90) by a.mx.sunsite.dk with SMTP; 10 Oct 2006 18:00:18 -0000 Received: (qmail 6659 invoked by alias); 10 Oct 2006 18:00:15 -0000 Mailing-List: contact zsh-workers-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 22858 Received: (qmail 6650 invoked from network); 10 Oct 2006 18:00:15 -0000 Received: from news.dotsrc.org (HELO a.mx.sunsite.dk) (130.225.247.88) by sunsite.dk with SMTP; 10 Oct 2006 18:00:15 -0000 Received: (qmail 59693 invoked from network); 10 Oct 2006 18:00:15 -0000 Received: from cluster-d.mailcontrol.com (217.69.20.190) by a.mx.sunsite.dk with SMTP; 10 Oct 2006 18:00:13 -0000 Received: from cameurexb01.EUROPE.ROOT.PRI ([62.189.241.200]) by rly09d.srv.mailcontrol.com (MailControl) with ESMTP id k9AI01Hk016341 for ; Tue, 10 Oct 2006 19:00:03 +0100 Received: from news01.csr.com ([10.103.143.38]) by cameurexb01.EUROPE.ROOT.PRI with Microsoft SMTPSVC(6.0.3790.1830); Tue, 10 Oct 2006 18:59:59 +0100 Date: Tue, 10 Oct 2006 18:59:59 +0100 From: Peter Stephenson To: zsh-workers@sunsite.dk Subject: Re: Please add pinfo completion Message-Id: <20061010185959.c84c0b49.pws@csr.com> In-Reply-To: <20061010142200.GC17674@prunille.vinc17.org> References: <20061007013551.GE8188@prunille.vinc17.org> <237967ef0610081413v291de92ck71f45c8990bf67ae@mail.gmail.com> <20061010142200.GC17674@prunille.vinc17.org> Organization: Cambridge Silicon Radio X-Mailer: Sylpheed version 2.2.9 (GTK+ 2.8.20; i386-redhat-linux-gnu) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit X-OriginalArrivalTime: 10 Oct 2006 17:59:59.0535 (UTC) FILETIME=[E6EF1BF0:01C6EC95] X-Scanned-By: MailControl A-07-04-02 (www.mailcontrol.com) on 10.68.0.119 Vincent Lefevre 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 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