zsh-workers
 help / color / mirror / code / Atom feed
* Re: PATCH: file completion
@ 2000-02-10 11:53 Sven Wischnowsky
  0 siblings, 0 replies; 6+ messages in thread
From: Sven Wischnowsky @ 2000-02-10 11:53 UTC (permalink / raw)
  To: zsh-workers


Tanaka Akira wrote:

> In article <200002091625.RAA17482@beta.informatik.hu-berlin.de>,
>   Sven Wischnowsky <wischnow@informatik.hu-berlin.de> writes:
> 
> > This mainly makes _path_files a bit faster.
> > 
> > And then I finally got fed up with those longish while-getopts loops
> > and added a small builtin (zparseopts) that can be used to replace
> > such loops.
> 
> After 9635, "_path_files -S ''" doesn't work well.
> 
> Z(2):akr@is27e1u11% Src/zsh -f
> is27e1u11% bindkey -e; autoload -U compinit; compinit -D; compdef _tst tst
> is27e1u11% _tst () { _path_files -S '' }
> is27e1u11% tst D<TAB>
> ->
> is27e1u11% tst Doc-M
> 
> Of course, there is no file named as `Doc-M'.

I forgot to say: the patch I just send (improved zparseargs) fixes that.

Bye
 Sven


--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 6+ messages in thread

* PATCH: file completion
@ 2000-02-17  9:12 Sven Wischnowsky
  0 siblings, 0 replies; 6+ messages in thread
From: Sven Wischnowsky @ 2000-02-17  9:12 UTC (permalink / raw)
  To: zsh-workers


This was broken again when completing to the name of an empty
directory (if the word from the line ended with a slash).

Bye
 Sven

diff -ru ../z.old/Completion/Core/_path_files Completion/Core/_path_files
--- ../z.old/Completion/Core/_path_files	Wed Feb 16 17:42:57 2000
+++ Completion/Core/_path_files	Thu Feb 17 10:10:25 2000
@@ -253,6 +253,7 @@
 
     # Get the matching files by globbing.
 
+    tmp2=( "$tmp1[@]" )
     if [[ "$tpre$tsuf" = */* ]]; then
       if [[ ! -o globdots && "$PREFIX" = .* ]]; then
         tmp1=( ${^tmp1}${skipped}*(-/) ${^tmp1}${skipped}.*(-/) )
@@ -287,7 +288,6 @@
       # See which of them match what's on the line.
 
       if [[ -n "$_comp_correct" ]]; then
-        tmp2=( "$tmp1[@]" )
         builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
 
         if [[ $#tmp1 -eq 0 ]]; then
@@ -333,6 +333,7 @@
       # if none of the patterns match.
 
       if [[ -z "$tpre$tsuf" && -n "$pre$suf" ]]; then
+        tmp1=( "$tmp2[@]" )
 	pfxsfx=(-S '' "$pfxsfx[@]")
 	break
       elif [[ "$haspats" = no && -z "$tpre$tsuf" &&
@@ -382,7 +383,7 @@
     # There are more components, so skip over the next components and make a
     # slash be added.
 
-    tmp2="${(M)tpre##((.|..|)/)##}"   ###
+    tmp2="${(M)tpre##((.|..|)/)##}"
     if [[ -n "$tmp2" ]]; then
       skipped="/$tmp2"
       tpre="${tpre#$tmp2}"

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: file completion
@ 2000-02-10 11:51 Sven Wischnowsky
  0 siblings, 0 replies; 6+ messages in thread
From: Sven Wischnowsky @ 2000-02-10 11:51 UTC (permalink / raw)
  To: zsh-workers


Bart Schaefer wrote:

> ...
> 
> How about
> 
> 	zparseopts [ -a arraname | -A assocname | -D ] optspec ...
> 
> where optspec looks like
> 
> 	optionname["+"|":"]["="arrayname]
> 
> where of course + : = in optionname can be backslashed or whatever.

This does that. Including the double-colon thing.

> It's also not clear what happens when there's an argument parsing error
> of some sort; does zparseopts just quit then and ignore the rest of the 
> arguments, or what?

Yep. This was mentioned (rather indirectly) at the -D description.
I hope the patch for the docs makes this clear enough.

Bye
 Sven

diff -ru ../z.old/Completion/Core/_files Completion/Core/_files
--- ../z.old/Completion/Core/_files	Wed Feb  9 17:26:32 2000
+++ Completion/Core/_files	Thu Feb 10 12:00:30 2000
@@ -3,10 +3,9 @@
 local opts opt type=file glob group gopts dopts aopts tmp _file_pat_checked=yes
 local hasign ign
 
-zparseopts \
-    /tmp ftmp g+tmp \
-    qopts nopts 1opts 2opts P:opts S:opts r:opts R:opts W:opts X:opts M:opts \
-    F:opts J:group V:group
+zparseopts -a opts \
+    '/=tmp' 'f=tmp' 'g+:-=tmp' q n 1 2 P: S: r: R: W: X: M: F: \
+    'J:=group' 'V:=group'
 
 type="${(@j::M)${(@)tmp#-}#?}"
 [[ -n "$type" ]] || type=f
@@ -15,13 +14,15 @@
 else
   gopts=()
 fi
-(( $opts[(I)-F*] )) && hasign=yes
+(( $opts[(I)-F] )) && hasign=yes
 
-if [[ "$group[1]" = -?files ]]; then
+if [[ "$group[2]" = files ]]; then
   opts=("$opts[@]" "$group[@]")
   group=()
 fi
 
+ign=()
+
 if zstyle -s ":completion:${curcontext}:all-files" file-patterns tmp &&
    [[ -n "$tmp" ]]; then
   aopts=(-g "$tmp")
@@ -58,7 +59,7 @@
 while _tags; do
   if _requested all-files; then
     if (( $#group )); then
-      group[1]="${group[1][1,2]}all-files"
+      group[2]=all-files
       _setup all-files
       [[ -z "$hasign" ]] &&
         zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
@@ -69,7 +70,7 @@
   elif _requested directories; then
     if _requested globbed-files; then
       if (( $#group )); then
-        group[1]="${group[1][1,2]}globbed-files"
+        group[2]=globbed-files
 	_setup globbed-files
         [[ -z "$hasign" ]] &&
           zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
@@ -78,7 +79,7 @@
       _path_files "$opts[@]" "$ign[@]" "$dopts[@]" "$gopts[@]" && return 0
     else
       if (( $#group )); then
-        group[1]="${group[1][1,2]}directories"
+        group[2]=directories
 	_setup directories
         [[ -z "$hasign" ]] &&
           zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
@@ -88,7 +89,7 @@
     fi
   elif _requested globbed-files; then
     if (( $#group )); then
-      group[1]="${group[1][1,2]}globbed-files"
+      group[2]=globbed-files
       _setup globbed-files
       [[ -z "$hasign" ]] &&
         zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
diff -ru ../z.old/Completion/Core/_multi_parts Completion/Core/_multi_parts
--- ../z.old/Completion/Core/_multi_parts	Wed Feb  9 17:26:32 2000
+++ Completion/Core/_multi_parts	Thu Feb 10 12:00:51 2000
@@ -13,15 +13,13 @@
 
 # Get the options.
 
-zparseopts -D \
-    J:group V:group X:expl \
-    P:opts F:opts \
-    S:sopts r:sopts R:sopts qsopts 1sopts 2sopts nsopts \
-    M:match
+zparseopts -D -a sopts \
+    'J:=group' 'V:=group' 'X:=expl' 'P:=opts' 'F:=opts' \
+    S: r: R: q 1 2 n 'M:=match'
 
 sopts=( "$sopts[@]" "$opts[@]" )
 if (( $#match )); then
-  match="${match[1][3,-1]}"
+  match="${match[2]}"
 else
   match=''
 fi
diff -ru ../z.old/Completion/Core/_path_files Completion/Core/_path_files
--- ../z.old/Completion/Core/_path_files	Wed Feb  9 17:26:33 2000
+++ Completion/Core/_path_files	Thu Feb 10 12:34:55 2000
@@ -17,11 +17,10 @@
 
 # Get the options.
 
-zparseopts \
-    P:pfxsfx S:pfxsfx qpfxsfx r:pfxsfx R:pfxsfx \
-    W:prepaths F:ignore M+matcher \
-    J:mopts V:mopts X:mopts 1:mopts 2:mopts n:mopts \
-    ftmp1 /tmp1 g+tmp1
+zparseopts -a mopts \
+    'P:=pfxsfx' 'S:=pfxsfx' 'q=pfxsfx' 'r:=pfxsfx' 'R:=pfxsfx' \
+    'W:=prepaths' 'F:=ignore' 'M+=matcher' \
+    J: V: X: 1: 2: n: 'f=tmp1' '/=tmp1' 'g+:-=tmp1'
 
 sopt="-${(@j::M)${(@)tmp1#-}#?}"
 (( $tmp1[(I)-[/g]*] )) && haspats=yes
@@ -33,7 +32,7 @@
 fi
 
 if (( $#prepaths )); then
-  tmp1="${prepaths[1][3,-1]}"
+  tmp1="${prepaths[2]}"
   if [[ "$tmp1[1]" = '(' ]]; then
     prepaths=( ${^=tmp1[2,-2]%/}/ )
   elif [[ "$tmp1[1]" = '/' ]]; then
@@ -48,15 +47,14 @@
 fi
 
 if (( $#ignore )); then
-  tmp1="${ignore[1][3,-1]}"
-  if [[ "$tmp1[1]" = '(' ]]; then
-    ignore=( ${=tmp1[2,-2]} )
+  if [[ "${ignore[2]}" = \(* ]]; then
+    ignore=( ${=ignore[2][2,-2]} )
   else
-    ignore=( ${(P)tmp1} )
+    ignore=( ${(P)ignore[2]} )
   fi
 fi  
 
-(( $#matcher )) && mspec="${matcher[1][3,-1]}"
+(( $#matcher )) && mspec="${matcher[2]}"
 
 if [[ -z "$_file_pat_checked" ]] &&
    zstyle -s ":completion:${curcontext}:files" file-patterns tmp1 &&
@@ -84,7 +82,7 @@
   fi
 fi
 
-if (( ! $mopts[(I)-[JVX]*] )); then
+if (( ! $mopts[(I)-[JVX]] )); then
   local expl
 
   if [[ -z "$gopt" && "$sopt" = -/ ]]; then
@@ -165,7 +163,7 @@
 
 if (( $#ignore )); then
   _comp_ignore=( "$_comp_ignore[@]" "$ignore[@]" )
-  (( $mopts[(I)-F*] )) || mopts=( "$mopts[@]" -F _comp_ignore )
+  (( $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore )
 fi
 
 # Now let's have a closer look at the string to complete.
@@ -371,7 +369,7 @@
 	  [[ "$i" -ef "$PWD" ]] && _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
 	done
       fi
-      (( $#_comp_ignore && $mopts[(I)-F*] )) || mopts=( "$mopts[@]" -F _comp_ignore )
+      (( $#_comp_ignore && $mopts[(I)-F] )) || mopts=( "$mopts[@]" -F _comp_ignore )
     fi
 
     # Step over to the next component, if any.
diff -ru ../z.old/Completion/Core/_sep_parts Completion/Core/_sep_parts
--- ../z.old/Completion/Core/_sep_parts	Wed Feb  9 17:26:33 2000
+++ Completion/Core/_sep_parts	Thu Feb 10 12:02:02 2000
@@ -22,13 +22,11 @@
 
 # Get the options.
 
-zparseopts -D \
-    J:group V:group \
-    P:opts F:opts S:opts r:opts R:opts qopts 1opts 2opts nopts \
-    X:expl M:match
+zparseopts -D -a opts \
+    'J:=group' 'V=:group' P: F: S: r: R: q 1 2 n 'X:=expl' 'M:=match'
 
 if (( $#match )); then
-  match="${match[1][3,-1]}"
+  match="${match[2]}"
 else
   match=''
 fi
diff -ru ../z.old/Doc/Zsh/mod_zutil.yo Doc/Zsh/mod_zutil.yo
--- ../z.old/Doc/Zsh/mod_zutil.yo	Wed Feb  9 17:26:15 2000
+++ Doc/Zsh/mod_zutil.yo	Thu Feb 10 12:49:29 2000
@@ -111,28 +111,47 @@
 item(tt(zregexparse))(
 This implements the internals of the `tt(_regex_arguments)'.
 )
-item(tt(zparseopts) [ tt(-D) ] var(specs))(
-This builtin can be used to parse the positional arguments and put
-options found in them into separate arrays. Each var(spec) describes
-one option which is given as its first character. If the second
-character is either `tt(:)' or `tt(+)', the option takes an argument
-(either directly following the option in the same word or in the next
-word). After the option character or the `tt(:)' or `tt(+)' follows
-the name of the array in which the option should be stored. The only
-difference between the form with a `t(:)' and the one with a `tt(+)'
-is that in the first case the option and its argument will be put in
-the array only once (later occurrences overwriting earlier ones),
-whereas with `tt(+)' all occurrences are moved to the array.
+item(tt(zparseopts) [ tt(-D) ] [ tt(-a) var(array) ] [ tt(-A) var(assoc) ] var(specs))(
+This builtin simplifies the parsing of options in the positional
+parameters. Each var(spec) describes one option and should be of the
+form `var(name)[tt(+)][tt(:)[tt(:)][tt(-)]][tt(=)var(array)]'. The var(name)
+is the name of the option (without the leading `tt(-)'). If only that
+is given, the option takes no argument and if it is found in the
+positional parameters it will be placed in the var(array) given with
+the tt(-a) option. If the optional `tt(=)var(array)' is given, it will 
+be put into that array instead. If one or two colons are given, the
+option takes an argument. With one colon, this argument is mandatory
+and with two colons it is optional. The argument will be inserted into 
+the var(array), too. For mandatory arguments it is added as a separate 
+string and for optional arguments it is put into one string together
+with the option name unless the `tt(-)' option is given. In this case
+the argument will be put into the same word even for mandatory
+arguments (note that this makes empty strings as arguments
+indistinguishable). Finally, if the `tt(+)' is given and the option
+appears more than once in the positional parameters, it will be
+inserted more than once in the var(array), too. Without the `tt(+)'
+the option will be inserted only once in the var(array) with arguments 
+of later options overwriting earlier once. If any of the special
+character needs to appear in the option name it must be preceded by a
+backslash.
+
+If the tt(-A) option is given, the options and their values will also
+be put into an associative array with the option names as keys and the 
+arguments (if any) as the values. Note that it is an error to give
+var(specs) without a `tt(=)var(array)' and not use either the tt(-a)
+or tt(-A) option.
 
 If the tt(-D) option is given, all options found are removed from the
-positional parameters leaving only those strings that did not match
-any of the var(specs).
+positional parameters leaving only the strings from the first one that 
+was not described by any of the var(specs) to the last (note that this 
+is the usual rule used by tt(zparseopts) to find out when to stop
+processing options).
 
-For example, calling `tt(zparseopts afoo b:bar c+bar)' with the
+For example, calling `tt(zparseopts a=foo b:=bar c+:=bar)' with the
 strings `tt(-a)', `tt(-bx)', `tt(-c)', `tt(y)', `tt(-cz)', `tt(baz)'
 and `tt(-cend)' as positional arguments will set the array tt(foo) to
 contain the element `tt(-a)' and the array tt(bar) to the strings
-`tt(-bx)', `tt(-cy)' and `tt(-cz)'. The `tt(baz)' and any strings
-after it will not be used.
+`tt(-b)', `tt(x)', `tt(-c)', `tt(y)', `tt(-c)', and `tt(z)'. The
+`tt(baz)' and all strings after it will not be used.
 )
 enditem()
diff -ru ../z.old/Src/Modules/zutil.c Src/Modules/zutil.c
--- ../z.old/Src/Modules/zutil.c	Wed Feb  9 17:26:11 2000
+++ Src/Modules/zutil.c	Thu Feb 10 12:02:21 2000
@@ -1160,27 +1160,59 @@
 typedef struct zoptval *Zoptval;
 
 struct zoptdesc {
-    int arg;
+    Zoptdesc next;
+    char *name;
+    int flags;
     Zoptarr arr;
+    Zoptval vals, last;
 };
 
+#define ZOF_ARG  1
+#define ZOF_OPT  2
+#define ZOF_MULT 4
+#define ZOF_SAME 8
+
 struct zoptarr {
+    Zoptarr next;
     char *name;
     Zoptval vals, last;
-    Zoptarr next;
     int num;
 };
 
-#define ZOF_ARG 1
-#define ZOF_ADD 2
-
 struct zoptval {
+    Zoptval next, onext;
+    char *name;
+    char *arg;
     char *str;
-    Zoptval next;
 };
 
+static Zoptdesc opt_descs;
 static Zoptarr opt_arrs;
 
+static Zoptdesc
+get_opt_desc(char *name)
+{
+    Zoptdesc p;
+
+    for (p = opt_descs; p; p = p->next)
+	if (!strcmp(name, p->name))
+	    return p;
+
+    return NULL;
+}
+
+static Zoptdesc
+lookup_opt(char *str)
+{
+    Zoptdesc p;
+
+    for (p = opt_descs; p; p = p->next) {
+	if ((p->flags & ZOF_ARG) ? strpfx(p->name, str) : !strcmp(p->name, str))
+	    return p;
+    }
+    return NULL;
+}
+
 static Zoptarr
 get_opt_arr(char *name)
 {
@@ -1193,89 +1225,290 @@
     return NULL;
 }
 
+static void
+add_opt_val(Zoptdesc d, char *arg)
+{
+    Zoptval v = NULL;
+    char *n = dyncat("-", d->name);
+    int new = 0;
+
+    if (!(d->flags & ZOF_MULT))
+	v = d->vals;
+    if (!v) {
+	v = (Zoptval) zhalloc(sizeof(*v));
+	v->next = v->onext = NULL;
+	v->name = n;
+	new = 1;
+    }
+    v->arg = arg;
+    if ((d->flags & ZOF_ARG) && !(d->flags & (ZOF_OPT | ZOF_SAME))) {
+	v->str = NULL;
+	if (d->arr)
+	    d->arr->num += (arg ? 2 : 1);
+    } else if (arg) {
+	char *s = (char *) zhalloc(strlen(d->name) + strlen(arg) + 2);
+
+	*s = '-';
+	strcpy(s + 1, d->name);
+	strcat(s, arg);
+	v->str = s;
+	if (d->arr)
+	    d->arr->num += 1;
+    } else {
+	v->str = NULL;
+	if (d->arr)
+	    d->arr->num += 1;
+    }
+    if (new) {
+	if (d->arr) {
+	    if (d->arr->last)
+		d->arr->last->next = v;
+	    else
+		d->arr->vals = v;
+	    d->arr->last = v;
+	}
+	if (d->last)
+	    d->last->onext = v;
+	else
+	    d->vals = v;
+	d->last = v;
+    }
+}
+
 static int
 bin_zparseopts(char *nam, char **args, char *ops, int func)
 {
-    char *o, *n, **pp, *str, **aval;
-    Zoptdesc opts[256], d;
-    Zoptarr a;
+    char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL;
+    int del = 0, f;
+    Zoptdesc sopts[256], d;
+    Zoptarr a, defarr = NULL;
     Zoptval v;
 
-    memset(opts, 0, 256 * sizeof(Zoptdesc));
+    opt_descs = NULL;
     opt_arrs = NULL;
+    memset(sopts, 0, 256 * sizeof(Zoptdesc));
 
     while ((o = *args++)) {
-	if (opts[STOUC(*o)]) {
-	    zerrnam(nam, "option described more than once: %s", o, 0);
+	if (*o == '-') {
+	    switch (o[1]) {
+	    case '\0':
+		o = NULL;
+		break;
+	    case '-':
+		if (o[2])
+		    args--;
+		o = NULL;
+		break;
+	    case 'D':
+		if (o[2]) {
+		    args--;
+		    o = NULL;
+		    break;
+		}
+		del = 1;
+		break;
+	    case 'a':
+		if (defarr) {
+		    zerrnam(nam, "default array given more than once", NULL, 0);
+		    return 1;
+		}
+		if (o[2])
+		    n = o + 2;
+		else if (*args)
+		    n = *args++;
+		else {
+		    zerrnam(nam, "missing array name", NULL, 0);
+		    return 1;
+		}
+		defarr = (Zoptarr) zhalloc(sizeof(*defarr));
+		defarr->name = n;
+		defarr->num = 0;
+		defarr->vals = defarr->last = NULL;
+		defarr->next = NULL;
+		opt_arrs = defarr;
+		break;
+	    case 'A':
+		if (o[2]) 
+		    assoc = o + 2;
+		else if (*args)
+		    assoc = *args++;
+		else {
+		    zerrnam(nam, "missing array name", NULL, 0);
+		    return 1;
+		}
+		break;
+	    }
+	    if (!o)
+		break;
+	} else {
+	    args--;
+	    break;
+	}
+    }
+    while ((o = dupstring(*args++))) {
+	if (!*o) {
+	    zerrnam(nam, "invalid option description: %s", o, 0);
 	    return 1;
 	}
-	d = (Zoptdesc) zhalloc(sizeof(*d));
-	d->arg = (o[1] == ':' ? ZOF_ARG : (o[1] == '+' ? ZOF_ADD : 0));
-	if (!(a = get_opt_arr((n = o + (d->arg ? 2 : 1))))) {
-	    a = (Zoptarr) zhalloc(sizeof(*a));
-	    a->name = n;
-	    a->num = 0;
-	    a->vals = a->last = NULL;
-	    a->next = opt_arrs;
-	    opt_arrs = a;
+	f = 0;
+	for (p = o; *p; p++) {
+	    if (*p == '\\' && p[1])
+		p++;
+	    else if (*p == '+') {
+		f |= ZOF_MULT;
+		*p = '\0';
+		p++;
+		break;
+	    } else if (*p == ':' || *p == '=')
+		break;
 	}
+	if (*p == ':') {
+	    f |= ZOF_ARG;
+	    *p = '\0';
+	    if (*++p == ':') {
+		p++;
+		f |= ZOF_OPT;
+	    }
+	    if (*p == '-') {
+		p++;
+		f |= ZOF_SAME;
+	    }
+	}
+	a = NULL;
+	if (*p == '=') {
+	    *p++ = '\0';
+	    if (!(a = get_opt_arr(p))) {
+		a = (Zoptarr) zhalloc(sizeof(*a));
+		a->name = p;
+		a->num = 0;
+		a->vals = a->last = NULL;
+		a->next = opt_arrs;
+		opt_arrs = a;
+	    }
+	} else if (*p) {
+	    zerrnam(nam, "invalid option description: %s", args[-1], 0);
+	    return 1;
+	} else if (!(a = defarr) && !assoc) {
+	    zerrnam(nam, "no default array defined: %s", args[-1], 0);
+	    return 1;
+	}
+	for (p = n = o; *p; p++) {
+	    if (*p == '\\' && p[1])
+		p++;
+	    *n++ = *p;
+	}
+	if (get_opt_desc(o)) {
+	    zerrnam(nam, "option defined more than once: %s", o, 0);
+	    return 1;
+	}
+	d = (Zoptdesc) zhalloc(sizeof(*d));
+	d->name = o;
+	d->flags = f;
 	d->arr = a;
-	opts[STOUC(*o)] = d;
+	d->next = opt_descs;
+	d->vals = d->last = NULL;
+	opt_descs = d;
+	if (!o[1])
+	    sopts[STOUC(*o)] = d;
     }
     for (pp = pparams; (o = *pp); pp++) {
 	if (*o != '-')
 	    break;
-	while (*++o) {
-	    if (!(d = opts[STOUC(*o)]))
-		break;
-	    if (d->arg) {
-		if (o[1]) {
-		    str = (char *) zhalloc(strlen(o) + 2);
-		    str[0] = '-';
-		    strcpy(str + 1, o);
-		} else if (!pp[1]) {
-		    zerrnam(nam, "missing argument for option: -%c", NULL, *o);
-		    return 1;
-		} else {
-		    str = (char *) zhalloc(strlen(pp[1]) + 3);
-		    str[0] = '-';
-		    str[1] = *o;
-		    strcpy(str + 2, pp[1]);
-		    pp++;
-		}
-		o = "" - 1;
-	    } else {
-		str = (char *) zhalloc(3);
-		str[0] = '-';
-		str[1] = *o;
-		str[2] = '\0';
-	    }
-	    if (d->arg != ZOF_ADD) {
-		for (v = d->arr->vals; v; v = v->next) {
-		    if (str[1] == v->str[1]) {
-			v->str = str;
-			str = NULL;
+	if (!o[1] || (o[1] == '-' && !o[2])) {
+	    pp++;
+	    break;
+	}
+	if (!(d = lookup_opt(o + 1))) {
+	    while (*++o) {
+		if (!(d = sopts[STOUC(*o)])) {
+		    o = NULL;
+		    break;
+		}
+		if (d->flags & ZOF_ARG) {
+		    if (o[1]) {
+			add_opt_val(d, o + 1);
 			break;
+		    } else if (!(d->flags & ZOF_OPT)) {
+			if (!pp[1]) {
+			    zerrnam(nam, "missing argument for option: %s",
+				    d->name, 0);
+			    return 1;
+			}
+			add_opt_val(d, *++pp);
+		    } else
+			add_opt_val(d, NULL);
+		} else
+		    add_opt_val(d, NULL);
+	    }
+	    if (!o)
+		break;
+	} else {
+	    if (d->flags & ZOF_ARG) {
+		char *e = o + strlen(d->name) + 1;
+
+		if (*e)
+		    add_opt_val(d, e);
+		else if (!(d->flags & ZOF_OPT)) {
+		    if (!pp[1]) {
+			zerrnam(nam, "missing argument for option: %s",
+				d->name, 0);
+			return 1;
 		    }
-		}
+		    add_opt_val(d, *++pp);
+		} else
+		    add_opt_val(d, NULL);
+	    } else
+		add_opt_val(d, NULL);
+	}
+    }
+    for (a = opt_arrs; a; a = a->next) {
+	aval = (char **) zalloc((a->num + 1) * sizeof(char *));
+	for (ap = aval, v = a->vals; v; ap++, v = v->next) {
+	    if (v->str)
+		*ap = ztrdup(v->str);
+	    else {
+		*ap = ztrdup(v->name);
+		if (v->arg)
+		    *++ap = ztrdup(v->arg);
 	    }
-	    if (str) {
-		v = (Zoptval) zhalloc(sizeof(*v));
-		v->str = str;
-		v->next = NULL;
-
-		if (d->arr->last)
-		    d->arr->last->next = v;
-		else
-		    d->arr->vals = v;
-		d->arr->last = v;
-		d->arr->num++;
+	}
+	*ap = NULL;
+	setaparam(a->name, aval);
+    }
+    if (assoc) {
+	int num;
+
+	for (num = 0, d = opt_descs; d; d = d->next)
+	    if (d->vals)
+		num++;
+
+	aval = (char **) zalloc(((num * 2) + 1) * sizeof(char *));
+	for (ap = aval, d = opt_descs; d; d = d->next) {
+	    if (d->vals) {
+		*ap++ = n = (char *) zalloc(strlen(d->name) + 2);
+		*n = '-';
+		strcpy(n + 1, d->name);
+
+		for (num = 1, v = d->vals; v; v = v->onext) {
+		    num += (v->arg ? strlen(v->arg) : 0);
+		    if (v->next)
+			num++;
+		}
+		*ap++ = n = (char *) zalloc(num);
+		for (v = d->vals; v; v = v->onext) {
+		    if (v->arg) {
+			strcpy(n, v->arg);
+			n += strlen(v->arg);
+		    }
+		    *n = ' ';
+		}
+		*n = '\0';
 	    }
 	}
-	if (*o)
-	    break;
+	*ap = NULL;
+	sethparam(assoc, aval);
     }
-    if (ops['D']) {
+    if (del) {
 	PERMALLOC {
 	    pp = arrdup(pp);
 	} LASTALLOC;
@@ -1283,13 +1516,6 @@
 	freearray(pparams);
 	pparams = pp;
     }
-    for (a = opt_arrs; a; a = a->next) {
-	aval = (char **) zalloc((a->num + 1) * sizeof(char *));
-	for (pp = aval, v = a->vals; v; pp++, v = v->next)
-	    *pp = ztrdup(v->str);
-	*pp = NULL;
-	setaparam(a->name, aval);
-    }
     return 0;
 }
 
@@ -1297,7 +1523,7 @@
     BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL),
     BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL),
     BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL),
-    BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, "D", NULL),
+    BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, NULL, NULL),
 };
 
 

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: file completion
  2000-02-09 16:25 Sven Wischnowsky
  2000-02-09 18:50 ` Bart Schaefer
@ 2000-02-09 21:54 ` Tanaka Akira
  1 sibling, 0 replies; 6+ messages in thread
From: Tanaka Akira @ 2000-02-09 21:54 UTC (permalink / raw)
  To: zsh-workers

In article <200002091625.RAA17482@beta.informatik.hu-berlin.de>,
  Sven Wischnowsky <wischnow@informatik.hu-berlin.de> writes:

> This mainly makes _path_files a bit faster.
> 
> And then I finally got fed up with those longish while-getopts loops
> and added a small builtin (zparseopts) that can be used to replace
> such loops.

After 9635, "_path_files -S ''" doesn't work well.

Z(2):akr@is27e1u11% Src/zsh -f
is27e1u11% bindkey -e; autoload -U compinit; compinit -D; compdef _tst tst
is27e1u11% _tst () { _path_files -S '' }
is27e1u11% tst D<TAB>
->
is27e1u11% tst Doc-M

Of course, there is no file named as `Doc-M'.
-- 
Tanaka Akira


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: file completion
  2000-02-09 16:25 Sven Wischnowsky
@ 2000-02-09 18:50 ` Bart Schaefer
  2000-02-09 21:54 ` Tanaka Akira
  1 sibling, 0 replies; 6+ messages in thread
From: Bart Schaefer @ 2000-02-09 18:50 UTC (permalink / raw)
  To: Sven Wischnowsky, zsh-workers

On Feb 9,  5:25pm, Sven Wischnowsky wrote:
} Subject: PATCH: file completion
}
} I finally got fed up with those longish while-getopts loops
} and added a small builtin (zparseopts) that can be used to replace
} such loops.

This is not a bad idea, but I repeat my frequent plea that we stop
placing so much emphasis on compact syntax.  nopts qopts 1opts 2opts ?
It's like reading Dr. Suess.

Besides, it can't support long options, which somebody at some point
is going to start yelling for.

How about

	zparseopts [ -a arraname | -A assocname | -D ] optspec ...

where optspec looks like

	optionname["+"|":"]["="arrayname]

where of course + : = in optionname can be backslashed or whatever.

The -a option would mean to use that arrayname for any optspec where
the =arrayname part was left off; the -A assocname would mean to set
assocname[optionname] with the same semantics that getopts sets OPTARG.

It could also use the GNU getopt double-colon syntax for whether an
option takes a required (one colon) or optional (two colons) argument.

It's also not clear what happens when there's an argument parsing error
of some sort; does zparseopts just quit then and ignore the rest of the 
arguments, or what?

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com


^ permalink raw reply	[flat|nested] 6+ messages in thread

* PATCH: file completion
@ 2000-02-09 16:25 Sven Wischnowsky
  2000-02-09 18:50 ` Bart Schaefer
  2000-02-09 21:54 ` Tanaka Akira
  0 siblings, 2 replies; 6+ messages in thread
From: Sven Wischnowsky @ 2000-02-09 16:25 UTC (permalink / raw)
  To: zsh-workers


This mainly makes _path_files a bit faster.

And then I finally got fed up with those longish while-getopts loops
and added a small builtin (zparseopts) that can be used to replace
such loops.

But still, _path_files could do with some more support by C-code. But I
have problems finding things that are a) important and b) general
enough to be moved into C...

Bye
 Sven

diff -ru ../z.old/Completion/Core/_description Completion/Core/_description
--- ../z.old/Completion/Core/_description	Wed Feb  9 09:30:54 2000
+++ Completion/Core/_description	Wed Feb  9 14:19:42 2000
@@ -1,14 +1,11 @@
 #autoload
 
-local name gropt format gname hidden hide match ign
+local name gropt=-J format gname hidden hide match opts
 
-gropt=(-J)
-hide=()
-match=()
-ign=()
+opts=()
 
 if [[ "$1" = -([12]|)[VJ] ]]; then
-  gropt=("$1")
+  gropt="$1"
   shift
 fi
 
@@ -24,14 +21,14 @@
 zstyle -s ":completion:${curcontext}:$1" hidden hidden
 if [[ "$hidden" = (all|yes|true|1|on) ]]; then
   [[ "$hidden" = all ]] && format=''
-  hide=(-n)
+  opts=(-n)
 fi
 zstyle -s ":completion:${curcontext}:$1" group-name gname &&
     [[ -z "$gname" ]] && gname="$1"
 zstyle -s ":completion:${curcontext}:$1" matcher match &&
-    match=(-M "${(q)match}")
+    opts=($opts -M "${(q)match}")
 if zstyle -a ":completion:${curcontext}:$1" ignored-patterns _comp_ignore; then
-  ign=(-F _comp_ignore)
+  opts=( $opts -F _comp_ignore)
 else
   _comp_ignore=()
 fi
@@ -41,15 +38,15 @@
 
 if [[ -n "$gname" ]]; then
   if [[ -n "$format" ]]; then
-    eval "${name}=($hide $match $ign $gropt ${(q)gname} -X \"${format}\")"
+    eval "${name}=($opts $gropt ${(q)gname} -X \"${format}\")"
   else
-    eval "${name}=($hide $match $ign $gropt ${(q)gname})"
+    eval "${name}=($opts $gropt ${(q)gname})"
   fi
 else
   if [[ -n "$format" ]]; then
-    eval "${name}=($hide $match $ign $gropt -default- -X \"${format}\")"
+    eval "${name}=($opts $gropt -default- -X \"${format}\")"
   else
-    eval "${name}=($hide $match $ign $gropt -default-)"
+    eval "${name}=($opts $gropt -default-)"
   fi
 fi
 
diff -ru ../z.old/Completion/Core/_files Completion/Core/_files
--- ../z.old/Completion/Core/_files	Wed Feb  9 09:30:55 2000
+++ Completion/Core/_files	Wed Feb  9 16:57:42 2000
@@ -3,24 +3,21 @@
 local opts opt type=file glob group gopts dopts aopts tmp _file_pat_checked=yes
 local hasign ign
 
-opts=()
-group=()
-gopts=()
-dopts=(-/)
-aopts=(-f)
-ign=()
-while getopts "P:S:qr:R:W:F:J:V:X:f/g:M:12n" opt; do
-  case "$opt" in
-  /)      type="${type}dir"                               ;;
-  g)      type="${type}glob"; gopts=(-g "$OPTARG")        ;;
-  [qn12]) opts=("$opts[@]" "-$opt"          )             ;;
-  [JV])   group=(          "-$opt" "$OPTARG")             ;;
-  F)      opts=("$opts[@]" "-$opt" "$OPTARG"); hasign=yes ;;
-  [^f])   opts=("$opts[@]" "-$opt" "$OPTARG")             ;;
-  esac
-done
+zparseopts \
+    /tmp ftmp g+tmp \
+    qopts nopts 1opts 2opts P:opts S:opts r:opts R:opts W:opts X:opts M:opts \
+    F:opts J:group V:group
 
-if [[ "$group[2]" = files ]]; then
+type="${(@j::M)${(@)tmp#-}#?}"
+[[ -n "$type" ]] || type=f
+if (( $tmp[(I)-g*] )); then
+  gopts=( -g ${(j: :)${(M)tmp:#-g*}#-g} )
+else
+  gopts=()
+fi
+(( $opts[(I)-F*] )) && hasign=yes
+
+if [[ "$group[1]" = -?files ]]; then
   opts=("$opts[@]" "$group[@]")
   group=()
 fi
@@ -32,36 +29,36 @@
 if zstyle -s ":completion:${curcontext}:directories" file-patterns tmp &&
    [[ -n "$tmp" ]]; then
   dopts=(-g "$tmp")
-  if [[ "$type" = (*dir*glob*|*glob*dir*) ]]; then
-    type=glob
-  elif [[ "$type" != *(dir|glob)* ]]; then
-    type="${type}dir"
+  if [[ "$type" = (*/*g*|*g*/*) ]]; then
+    type=g
+  elif [[ "$type" != *[/g]* ]]; then
+    type="${type}/"
   fi
 fi
 if zstyle -s ":completion:${curcontext}:globbed-files" file-patterns tmp &&
    [[ -n "$tmp" ]]; then
   gopts=(-g "$tmp")
-  if [[ "$type" != (*dir*glob*|*glob*dir*) ]]; then
-    if [[ "$type" = *(dir|glob)* ]]; then
-      type=glob
+  if [[ "$type" != (*/*g*|*g*/*) ]]; then
+    if [[ "$type" = *[g/]* ]]; then
+      type=g
     else
-      type=globall
+      type=ga
     fi
   fi
 fi
 
 case "$type" in
-*dir*glob*|*glob*dir*) _tags globbed-files all-files             ;;
-*all*glob*|*glob*all*) _tags globbed-files all-files             ;;
-*glob*)                _tags globbed-files directories all-files ;;
-*dir*)                 _tags directories all-files               ;;
-*)                     _tags all-files                           ;;
+*/*g*|*g*/*) _tags globbed-files all-files             ;;
+*a*g*|*g*a*) _tags globbed-files all-files             ;;
+*g*)         _tags globbed-files directories all-files ;;
+*/*)         _tags directories all-files               ;;
+*)           _tags all-files                           ;;
 esac
 
 while _tags; do
   if _requested all-files; then
     if (( $#group )); then
-      group[2]=all-files
+      group[1]="${group[1][1,2]}all-files"
       _setup all-files
       [[ -z "$hasign" ]] &&
         zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
@@ -72,7 +69,7 @@
   elif _requested directories; then
     if _requested globbed-files; then
       if (( $#group )); then
-        group[2]=globbed-files
+        group[1]="${group[1][1,2]}globbed-files"
 	_setup globbed-files
         [[ -z "$hasign" ]] &&
           zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
@@ -81,7 +78,7 @@
       _path_files "$opts[@]" "$ign[@]" "$dopts[@]" "$gopts[@]" && return 0
     else
       if (( $#group )); then
-        group[2]=directories
+        group[1]="${group[1][1,2]}directories"
 	_setup directories
         [[ -z "$hasign" ]] &&
           zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
@@ -91,13 +88,13 @@
     fi
   elif _requested globbed-files; then
     if (( $#group )); then
-      group[2]=globbed-files
+      group[1]="${group[1][1,2]}globbed-files"
       _setup globbed-files
       [[ -z "$hasign" ]] &&
         zstyle -a ":completion:${curcontext}:all-files" ignored-patterns _comp_ignore &&
 	  ign=(-F _comp_ignore)
     fi
-    if [[ "$type" = (*dir*glob*|*glob*dir*) ]]; then
+    if [[ "$type" = (*/*g*|*g*/*) ]]; then
       _path_files "$opts[@]" "$ign[@]" "$dopts[@]" "$gopts[@]" && return 0
     else
       _path_files "$opts[@]" "$ign[@]" "$gopts[@]" && return 0
diff -ru ../z.old/Completion/Core/_multi_parts Completion/Core/_multi_parts
--- ../z.old/Completion/Core/_multi_parts	Wed Feb  9 09:30:55 2000
+++ Completion/Core/_multi_parts	Wed Feb  9 16:37:54 2000
@@ -13,22 +13,18 @@
 
 # Get the options.
 
-group=()
-expl=()
-opts=()
-sopts=()
-while getopts "J:V:X:P:F:S:r:R:qM:12n" opt; do
-  case "$opt" in
-  [JV])   group=("-$opt" "$OPTARG");;
-  X)      expl=(-X "$OPTARG");;
-  [PF])   opts=( "$opts[@]" "-$opt" "$OPTARG")
-          sopts=( "$sopts[@]" "-$opt" "$OPTARG");;
-  [SrR])  sopts=( "$sopts[@]" -P "$OPTARG");;
-  [q12n]) sopts=( "$sopts[@]" "-$opt");;
-  M)      match="$OPTARG";;
-  esac
-done
-shift OPTIND-1
+zparseopts -D \
+    J:group V:group X:expl \
+    P:opts F:opts \
+    S:sopts r:sopts R:sopts qsopts 1sopts 2sopts nsopts \
+    M:match
+
+sopts=( "$sopts[@]" "$opts[@]" )
+if (( $#match )); then
+  match="${match[1][3,-1]}"
+else
+  match=''
+fi
 
 # Get the arguments, first the separator, then the array. The array is 
 # stored in `matches'. Further on this array will always contain those 
diff -ru ../z.old/Completion/Core/_path_files Completion/Core/_path_files
--- ../z.old/Completion/Core/_path_files	Wed Feb  9 09:30:56 2000
+++ Completion/Core/_path_files	Wed Feb  9 17:06:29 2000
@@ -3,9 +3,9 @@
 # Utility function for in-path completion. This allows `/u/l/b<TAB>'
 # to complete to `/usr/local/bin'.
 
-local linepath realpath donepath prepath testpath exppath skips
+local linepath realpath donepath prepath testpath exppath skips skipped
 local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre
-local pats haspats=no ignore group expl addpfx addsfx remsfx rem remt
+local pats haspats=no ignore pfxsfx rem remt sopt gopt opt
 local nm=$compstate[nmatches] menu mspec matcher mopts atmp sort match
 
 typeset -U prepaths exppaths
@@ -13,73 +13,50 @@
 setopt localoptions nullglob rcexpandparam
 unsetopt markdirs globsubst shwordsplit nounset
 
-local sopt='-' gopt='' opt
 exppaths=()
-prepaths=('')
-ignore=()
-group=()
-pats=()
-addpfx=()
-addsfx=()
-remsfx=()
-expl=()
-matcher=()
-mopts=()
 
 # Get the options.
 
-while getopts "P:S:qr:R:W:F:J:V:X:f/g:M:12n" opt; do
-  case "$opt" in
-  [12n]) mopts=( "$mopts[@]" "-$opt" )
-         ;;
-  P)     addpfx=(-P "$OPTARG")
-         ;;
-  S)     addsfx=(-S "$OPTARG")
-         ;;
-  q)     tmp1=yes
-         ;;
-  [rR])  remsfx=("-$opt" "$OPTARG")
-         ;;
-  W)     tmp1="$OPTARG"
-         if [[ "$tmp1[1]" = '(' ]]; then
-           prepaths=( ${^=tmp1[2,-2]%/}/ )
-	 elif [[ "$tmp1[1]" = '/' ]]; then
-           prepaths=( "$tmp1/" )
-         else
-	   # In this case the variable should be an array, so
-	   # don't use an extra ${=...}.
-           prepaths=( ${(P)^tmp1%/}/ )
-           (( ! $#prepaths )) && prepaths=( ${tmp1%/}/ )
-         fi
-         (( ! $#prepaths )) && prepaths=( '' )
-         ;;
-  F)     tmp1="$OPTARG"
-         if [[ "$tmp1[1]" = '(' ]]; then
-           ignore=( ${=tmp1[2,-2]} )
-         else
-           ignore=( ${(P)tmp1} )
-         fi
-         ;;
-  [JV])  group=("-$opt" "$OPTARG")
-         ;;
-  X)     expl=(-X "$OPTARG")
-         ;;
-  f)     sopt="${sopt}f"
-         pats=("$pats[@]" '*')
-	 ;;
-  /)     sopt="${sopt}/"
-         pats=("$pats[@]" '*(-/)')
-	 haspats=yes
-	 ;;
-  g)     gopt='-g'
-         pats=("$pats[@]" ${=OPTARG})
-	 haspats=yes
-	 ;;
-  M)     mspec="$OPTARG"
-         matcher=(-M "$OPTARG")
-         ;;
-  esac
-done
+zparseopts \
+    P:pfxsfx S:pfxsfx qpfxsfx r:pfxsfx R:pfxsfx \
+    W:prepaths F:ignore M+matcher \
+    J:mopts V:mopts X:mopts 1:mopts 2:mopts n:mopts \
+    ftmp1 /tmp1 g+tmp1
+
+sopt="-${(@j::M)${(@)tmp1#-}#?}"
+(( $tmp1[(I)-[/g]*] )) && haspats=yes
+(( $tmp1[(I)-g*] )) && gopt=yes
+if (( $tmp1[(I)-/] )); then
+  pats=( '*(-/)' ${=${(M)tmp1:#-g*}#-g} )
+else
+  pats=( "${(@)=${(@M)tmp1:#-g*}#-g}" )
+fi
+
+if (( $#prepaths )); then
+  tmp1="${prepaths[1][3,-1]}"
+  if [[ "$tmp1[1]" = '(' ]]; then
+    prepaths=( ${^=tmp1[2,-2]%/}/ )
+  elif [[ "$tmp1[1]" = '/' ]]; then
+    prepaths=( "$tmp1/" )
+  else
+    prepaths=( ${(P)^tmp1%/}/ )
+    (( ! $#prepaths )) && prepaths=( ${tmp1%/}/ )
+  fi
+  (( ! $#prepaths )) && prepaths=( '' )
+else
+  prepaths=( '' )
+fi
+
+if (( $#ignore )); then
+  tmp1="${ignore[1][3,-1]}"
+  if [[ "$tmp1[1]" = '(' ]]; then
+    ignore=( ${=tmp1[2,-2]} )
+  else
+    ignore=( ${(P)tmp1} )
+  fi
+fi  
+
+(( $#matcher )) && mspec="${matcher[1][3,-1]}"
 
 if [[ -z "$_file_pat_checked" ]] &&
    zstyle -s ":completion:${curcontext}:files" file-patterns tmp1 &&
@@ -88,20 +65,34 @@
     gopt=''
     sopt=-/
   else
-    gopt='-g'
+    gopt=yes
     sopt=-
   fi
   pats=( $=tmp1 )
   haspats=yes
 fi
 
-if (( ! ( $#group + $#expl ) )); then
+# If we were given no file selection option, we behave as if we were given
+# a `-f'.
+
+if [[ "$sopt" = -(f|) ]]; then
+  if [[ -z "$gopt" ]]; then
+    sopt='-f'
+    pats=('*')
+  else
+    unset sopt
+  fi
+fi
+
+if (( ! $mopts[(I)-[JVX]*] )); then
+  local expl
+
   if [[ -z "$gopt" && "$sopt" = -/ ]]; then
     _description directories expl directory
   else
     _description files expl file
   fi
-  tmp1=$expl[(I)-M]
+  tmp1=$expl[(I)-M*]
   if (( tmp1 )); then
     mspec="$mspec $expl[1+tmp1]"
     if (( $#matcher )); then
@@ -110,20 +101,7 @@
       matcher=(-M "$expl[1+tmp1]")
     fi
   fi
-fi
-
-[[ -n "$tmp1" && $#addsfx -ne 0 ]] && addsfx[1]=-qS
-
-# If we were given no file selection option, we behave as if we were given
-# a `-f'.
-
-if [[ "$sopt" = - ]]; then
-  if [[ -z "$gopt" ]]; then
-    sopt='-f'
-    pats=('*')
-  else
-    unset sopt
-  fi
+  mopts=( "$mopts[@]" "$expl[@]" )
 fi
 
 if zstyle -s ":completion:${curcontext}:files" sort tmp1; then
@@ -140,8 +118,7 @@
   if [[ "$sort" = on ]]; then
     sort=''
   else
-    group=( "${(@)group/#-J/-V}" )
-    expl=( "${(@)expl/#-J/-V}" )
+    mopts=( "${(@)mopts/#-J/-V}" )
 
     tmp2=()
     for tmp1 in "$pats[@]"; do
@@ -157,9 +134,15 @@
   fi
 fi
 
-# Skip over sequences of slashes.
+# Check if we have to skip over sequences of slashes. The value of $skips
+# is used below to match the pathname components we always have to accept
+# immediatly.
 
-zstyle -t ":completion:${curcontext}:paths" squeeze-slashes && skips=yes
+if zstyle -t ":completion:${curcontext}:paths" squeeze-slashes; then
+  skips='((.|..|)/)##'
+else
+  skips='((.|..)/)##'
+fi
 
 # We get the prefix and the suffix from the line and save the whole
 # original string. Then we see if we will do menucompletion.
@@ -182,7 +165,7 @@
 
 if (( $#ignore )); then
   _comp_ignore=( "$_comp_ignore[@]" "$ignore[@]" )
-  (( $expl[(I)-F] )) || expl=( "$expl[@]" -F _comp_ignore )
+  (( $mopts[(I)-F*] )) || mopts=( "$mopts[@]" -F _comp_ignore )
 fi
 
 # Now let's have a closer look at the string to complete.
@@ -256,25 +239,12 @@
   tsuf="$suf"
   testpath="$donepath"
 
-  tmp1=( "$prepath$realpath$donepath" )
-
-  while true; do
-
-    # Skip over `./' and `../'.
-
-    if [[ "$tpre" = (.|..)/* ]]; then
-      tmp1=( ${^tmp1}${tpre%%/*}/ )
-      tpre="${tpre#*/}"
-      continue
-    fi
+  tmp2="${(M)tpre##${~skips}}"
+  tpre="${tpre#$tmp2}"
 
-    # Skip over multiple slashes?
+  tmp1=( "$prepath$realpath$donepath$tmp2" )
 
-    if [[ -n "$skips" && "$tpre" = /* ]]; then
-      tmp1=( ${^tmp1}/ )
-      tpre="${tpre#/}"
-      continue
-    fi
+  while true; do
 
     # Get the prefix and suffix for matching.
 
@@ -289,45 +259,24 @@
     # Get the matching files by globbing.
 
     if [[ "$tpre$tsuf" = */* ]]; then
-      tmp2=( ${^tmp1}*(-/) )
-      [[ ! -o globdots && "$PREFIX" = .* ]] &&
-          tmp2=( "$tmp2[@]" ${^tmp1}.*(-/) )
+      if [[ ! -o globdots && "$PREFIX" = .* ]]; then
+        tmp1=( ${^tmp1}${skipped}*(-/) ${^tmp1}${slash}.*(-/) )
+      else
+        tmp1=( ${^tmp1}${skipped}*(-/) )
+      fi
       if [[ -o globdots || "$PREFIX" = .* ]] &&
          zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then
 	if [[ "$atmp" = (yes|true|1|on) ]]; then
-	  tmp2=( "$tmp2[@]" . .. )
+	  tmp1=( "$tmp1[@]" . .. )
 	elif [[ "$atmp" = .. ]]; then
-	  tmp2=( "$tmp2[@]" .. )
+	  tmp1=( "$tmp1[@]" .. )
         fi
       fi
     else
-      tmp2=( ${^tmp1}${^~pats} )
-      [[ ! -o globdots && "$PREFIX" = .* ]] &&
-          tmp2=( "$tmp2[@]" ${^tmp1}.${^~pats} )
-      if (( $#tmp2 )) &&
-         zstyle -s ":completion:${curcontext}:files" ignore-parents rem &&
-	 [[ ( "$rem" != *dir* || "$pats" = '*(-/)' ) &&
-	    ( "$rem" != *..* || "$tmp1" = *../* ) ]]; then
-        if [[ "$rem" = *parent* ]]; then
-	  for i in "$tmp2[@]"; do
-	    if [[ -d "$i" && "$i" = */* ]]; then
-	      remt="${i%/*}"
-	      while [[ "$remt" = */* ]]; do
-		[[ "$remt" -ef "$i" ]] && break
-		remt="${remt%/*}"
-	      done
-	      [[ "$remt" = */* || "$remt" -ef "$i" ]] &&
-	          _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
-	    fi
-	  done
-        fi
-        if [[ "$rem" = *pwd* ]]; then
-          for i in "$tmp2[@]"; do
-	    [[ "$i" -ef "$PWD" ]] && _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
-	  done
-        fi
-       (( $#_comp_ignore )) && (( $expl[(I)-F] )) ||
-           expl=( "$expl[@]" -F _comp_ignore )
+      if [[ ! -o globdots && "$PREFIX" = .* ]]; then
+        tmp1=( ${^tmp1}${skipped}${^~pats} ${^tmp1}${slash}.${^~pats} )
+      else
+        tmp1=( ${^tmp1}${skipped}${^~pats} )
       fi
       if [[ "$sopt" = *[/f]* && ( -o globdots || "$PREFIX" = .* ) ]] &&
 	  zstyle -s ":completion:${curcontext}:paths" special-dirs atmp; then
@@ -338,22 +287,28 @@
         fi
       fi
     fi
-    tmp1=( "$tmp2[@]" )
 
     if [[ -n "$PREFIX$SUFFIX" ]]; then
       # See which of them match what's on the line.
 
-      builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
+      if [[ -n "$_comp_correct" ]]; then
+        tmp2=( "$tmp1[@]" )
+        builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
+
+        if [[ $#tmp1 -eq 0 && -n "$_comp_correct" ]]; then
+          tmp1=( "$tmp2[@]" )
+	  compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}"
+        fi
+      else
+        [[ "$tmp1[1]" = */* ]] && tmp2=( "$tmp1[@]" )
 
-      if [[ $#tmp1 -eq 0 && -n "$_comp_correct" ]]; then
-        tmp1=( "$tmp2[@]" )
-	compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}"
+        builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
       fi
 
       # If no file matches, save the expanded path and continue with
       # the outer loop.
 
-      if [[ $#tmp1 -eq 0 ]]; then
+      if (( ! $#tmp1 )); then
  	if [[ "$tmp2[1]" = */* ]]; then
 	  tmp2=( "${(@)tmp2#${prepath}${realpath}}" )
 	  if [[ "$tmp2[1]" = */* ]]; then
@@ -384,8 +339,7 @@
 
       if [[ -z "$tpre$tsuf" && -n "$pre$suf" ]]; then
         tmp1=( "$tmp2[@]" )
-	addsfx=(-S '')
-	remsfx=()
+	pfxsfx=(-S '' "$pfxsfx[@]")
 	break;
       elif [[ "$haspats" = no && -z "$tpre$tsuf" &&
 	"$pre" = */ && -z "$suf" ]]; then
@@ -397,6 +351,29 @@
       continue 2
     fi
 
+    if [[ "$tpre$tsuf" != */* && $#tmp1 -ne 0 ]] &&
+       zstyle -s ":completion:${curcontext}:files" ignore-parents rem &&
+       [[ ( "$rem" != *dir* || "$pats" = '*(-/)' ) &&
+	  ( "$rem" != *..* || "$tmp1" = *../* ) ]]; then
+      if [[ "$rem" = *parent* ]]; then
+	for i in ${(M)^tmp1:#*/*}(-/); do
+	  remt="${${i#$prepath$realpath$donepath}%/*}"
+	  while [[ "$remt" = */* ]]; do
+	    [[ "$prepath$realpath$donepath$remt" -ef "$i" ]] && break
+	    remt="${remt%/*}"
+	  done
+	  [[ "$remt" = */* || "$remt" -ef "$i" ]] &&
+	      _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
+	done
+      fi
+      if [[ "$rem" = *pwd* ]]; then
+        for i in ${^tmp1}(-/); do
+	  [[ "$i" -ef "$PWD" ]] && _comp_ignore=( "$_comp_ignore[@]" "${(q)i}" )
+	done
+      fi
+      (( $#_comp_ignore && $mopts[(I)-F*] )) || mopts=( "$mopts[@]" -F _comp_ignore )
+    fi
+
     # Step over to the next component, if any.
 
     if [[ "$tpre" = */* ]]; then
@@ -408,10 +385,16 @@
       break
     fi
 
-    # There are more components, so add a slash to the files we are
-    # collecting.
+    # There are more components, so skip over the next components and make a
+    # slash be added.
 
-    tmp1=( ${^tmp1}/ )
+    tmp2="${(M)tpre##((.|..|)/)##}"   ###
+    if [[ -n "$tmp2" ]]; then
+      skipped="/$tmp2"
+      tpre="${tpre#$tmp2}"
+    else
+      skipped=/
+    fi
   done
 
   # The next loop searches the first ambiguous component.
@@ -471,30 +454,30 @@
         if [[ "$tmp3" = */* ]]; then
 	  compadd -Qf "$mopts[@]" -p "$linepath$tmp2" -s "/${tmp3#*/}" \
 	          -W "$prepath$realpath$testpath" \
-		  "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-                  -M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \
+		  "$pfxsfx[@]" \
+                  -M "r:|/=* r:|=* $mspec" \
 		  - "${(@)tmp1%%/*}"
 	else
 	  compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \
 	          -W "$prepath$realpath$testpath" \
-		   "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-                   -M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \
+		   "$pfxsfx[@]" \
+                   -M "r:|/=* r:|=* $mspec" \
 		   - "$tmp1[@]"
 	fi
       else
         if [[ "$tmp3" = */* ]]; then
 	  atmp=( -Qf "$mopts[@]" -p "$linepath$tmp2"
 	         -W "$prepath$realpath$testpath"
-	         "$addpfx[@]" "$addsfx[@]" "$remsfx[@]"
-                 -M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" )
+	         "$pfxsfx[@]" \
+                 -M "r:|/=* r:|=* $mspec" )
           for i in "$tmp1[@]"; do
 	    compadd "$atmp[@]" -s "/${i#*/}" - "${i%%/*}"
 	  done
         else
 	  compadd -Qf "$mopts[@]" -p "$linepath$tmp2" \
 		  -W "$prepath$realpath$testpath" \
-		  "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-                  -M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \
+		  "$pfxsfx[@]" \
+                  -M "r:|/=* r:|=* $mspec" \
 		  - "$tmp1[@]"
         fi
       fi
@@ -543,8 +526,8 @@
     compquote tmp4 tmp1
     compadd -Qf "$mopts[@]" -p "$linepath$tmp4" \
 	    -W "$prepath$realpath$testpath" \
-	    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-            -M "r:|/=* r:|=* $mspec" "$group[@]" "$expl[@]" \
+	    "$pfxsfx[@]" \
+            -M "r:|/=* r:|=* $mspec" \
 	    - "$tmp1[@]"
   fi
 done
@@ -553,14 +536,17 @@
 # expanded paths that are different from the string on the line, we add
 # them as possible matches.
 
-exppaths=( "${(@)exppaths:#$eorig}" )
-
 if zstyle -t ":completion:${curcontext}:paths" expand prefix &&
-   [[ $#exppaths -gt 0 && nm -eq compstate[nmatches] ]]; then
-  PREFIX="${opre}"
-  SUFFIX="${osuf}"
-  compadd -Q "$mopts[@]" -S '' "$group[@]" "$expl[@]" \
-          -M "r:|/=* r:|=* $mspec" -p "$linepath" - "$exppaths[@]"
+   [[ nm -eq compstate[nmatches] ]]; then
+
+  exppaths=( "${(@)exppaths:#$eorig}" )
+
+  if (( $#exppaths )); then
+    PREFIX="${opre}"
+    SUFFIX="${osuf}"
+    compadd -Q "$mopts[@]" -S '' \
+            -M "r:|/=* r:|=* $mspec" -p "$linepath" - "$exppaths[@]"
+  fi
 fi
 
 [[ nm -ne compstate[nmatches] ]]
diff -ru ../z.old/Completion/Core/_sep_parts Completion/Core/_sep_parts
--- ../z.old/Completion/Core/_sep_parts	Wed Feb  9 09:30:56 2000
+++ Completion/Core/_sep_parts	Wed Feb  9 16:40:52 2000
@@ -22,19 +22,16 @@
 
 # Get the options.
 
-group=()
-expl=()
-opts=()
-while getopts "J:V:X:P:F:S:r:R:qM:12n" opt; do
-  case "$opt" in
-  [JV])   group=("-$opt" "$OPTARG");;
-  X)      expl=(-X "$OPTARG");;
-  [q12n]) opts=( "$opts[@]" "-$opt" );;
-  M)      match="$OPTARG";;
-  *)      opts=( "$opts[@]" "-$opt" "$OPTARG" );;
-  esac
-done
-shift OPTIND-1
+zparseopts -D \
+    J:group V:group \
+    P:opts F:opts S:opts r:opts R:opts qopts 1opts 2opts nopts \
+    X:expl M:match
+
+if (( $#match )); then
+  match="${match[1][3,-1]}"
+else
+  match=''
+fi
 
 # Get the string from the line.
 
diff -ru ../z.old/Doc/Zsh/mod_zutil.yo Doc/Zsh/mod_zutil.yo
--- ../z.old/Doc/Zsh/mod_zutil.yo	Wed Feb  9 09:30:36 2000
+++ Doc/Zsh/mod_zutil.yo	Wed Feb  9 17:19:37 2000
@@ -111,4 +111,28 @@
 item(tt(zregexparse))(
 This implements the internals of the `tt(_regex_arguments)'.
 )
+item(tt(zparseopts) [ tt(-D) ] var(specs))(
+This builtin can be used to parse the positional arguments and put
+options found in them into separate arrays. Each var(spec) describes
+one option which is given as its first character. If the second
+character is either `tt(:)' or `tt(+)', the option takes an argument
+(either directly following the option in the same word or in the next
+word). After the option character or the `tt(:)' or `tt(+)' follows
+the name of the array in which the option should be stored. The only
+difference between the form with a `t(:)' and the one with a `tt(+)'
+is that in the first case the option and its argument will be put in
+the array only once (later occurrences overwriting earlier ones),
+whereas with `tt(+)' all occurrences are moved to the array.
+
+If the tt(-D) option is given, all options found are removed from the
+positional parameters leaving only those strings that did not match
+any of the var(specs).
+
+For example, calling `tt(zparseopts afoo b:bar c+bar)' with the
+strings `tt(-a)', `tt(-bx)', `tt(-c)', `tt(y)', `tt(-cz)', `tt(baz)'
+and `tt(-cend)' as positional arguments will set the array tt(foo) to
+contain the element `tt(-a)' and the array tt(bar) to the strings
+`tt(-bx)', `tt(-cy)' and `tt(-cz)'. The `tt(baz)' and any strings
+after it will not be used.
+)
 enditem()
diff -ru ../z.old/Src/Modules/zutil.c Src/Modules/zutil.c
--- ../z.old/Src/Modules/zutil.c	Wed Feb  9 09:57:11 2000
+++ Src/Modules/zutil.c	Wed Feb  9 15:34:22 2000
@@ -1155,10 +1155,149 @@
     return ret;
 }
 
+typedef struct zoptdesc *Zoptdesc;
+typedef struct zoptarr *Zoptarr;
+typedef struct zoptval *Zoptval;
+
+struct zoptdesc {
+    int arg;
+    Zoptarr arr;
+};
+
+struct zoptarr {
+    char *name;
+    Zoptval vals, last;
+    Zoptarr next;
+    int num;
+};
+
+#define ZOF_ARG 1
+#define ZOF_ADD 2
+
+struct zoptval {
+    char *str;
+    Zoptval next;
+};
+
+static Zoptarr opt_arrs;
+
+static Zoptarr
+get_opt_arr(char *name)
+{
+    Zoptarr p;
+
+    for (p = opt_arrs; p; p = p->next)
+	if (!strcmp(name, p->name))
+	    return p;
+
+    return NULL;
+}
+
+static int
+bin_zparseopts(char *nam, char **args, char *ops, int func)
+{
+    char *o, *n, **pp, *str, **aval;
+    Zoptdesc opts[256], d;
+    Zoptarr a;
+    Zoptval v;
+
+    memset(opts, 0, 256 * sizeof(Zoptdesc));
+    opt_arrs = NULL;
+
+    while ((o = *args++)) {
+	if (opts[STOUC(*o)]) {
+	    zerrnam(nam, "option described more than once: %s", o, 0);
+	    return 1;
+	}
+	d = (Zoptdesc) zhalloc(sizeof(*d));
+	d->arg = (o[1] == ':' ? ZOF_ARG : (o[1] == '+' ? ZOF_ADD : 0));
+	if (!(a = get_opt_arr((n = o + (d->arg ? 2 : 1))))) {
+	    a = (Zoptarr) zhalloc(sizeof(*a));
+	    a->name = n;
+	    a->num = 0;
+	    a->vals = a->last = NULL;
+	    a->next = opt_arrs;
+	    opt_arrs = a;
+	}
+	d->arr = a;
+	opts[STOUC(*o)] = d;
+    }
+    for (pp = pparams; (o = *pp); pp++) {
+	if (*o != '-')
+	    break;
+	while (*++o) {
+	    if (!(d = opts[STOUC(*o)]))
+		break;
+	    if (d->arg) {
+		if (o[1]) {
+		    str = (char *) zhalloc(strlen(o) + 2);
+		    str[0] = '-';
+		    strcpy(str + 1, o);
+		} else if (!pp[1]) {
+		    zerrnam(nam, "missing argument for option: -%c", NULL, *o);
+		    return 1;
+		} else {
+		    str = (char *) zhalloc(strlen(pp[1]) + 3);
+		    str[0] = '-';
+		    str[1] = *o;
+		    strcpy(str + 2, pp[1]);
+		    pp++;
+		}
+		o = "" - 1;
+	    } else {
+		str = (char *) zhalloc(3);
+		str[0] = '-';
+		str[1] = *o;
+		str[2] = '\0';
+	    }
+	    if (d->arg != ZOF_ADD) {
+		for (v = d->arr->vals; v; v = v->next) {
+		    if (str[1] == v->str[1]) {
+			v->str = str;
+			str = NULL;
+			break;
+		    }
+		}
+	    }
+	    if (str) {
+		v = (Zoptval) zhalloc(sizeof(*v));
+		v->str = str;
+		v->next = NULL;
+
+		if (d->arr->last)
+		    d->arr->last->next = v;
+		else
+		    d->arr->vals = v;
+		d->arr->last = v;
+		d->arr->num++;
+	    }
+	}
+	if (*o)
+	    break;
+    }
+    if (ops['D']) {
+	PERMALLOC {
+	    pp = arrdup(pp);
+	} LASTALLOC;
+
+	freearray(pparams);
+	pparams = pp;
+    }
+    for (a = opt_arrs; a; a = a->next) {
+	aval = (char **) zalloc((a->num + 1) * sizeof(char *));
+	for (pp = aval, v = a->vals; v; pp++, v = v->next)
+	    *pp = ztrdup(v->str);
+	*pp = NULL;
+	setaparam(a->name, aval);
+    }
+    return 0;
+}
+
 static struct builtin bintab[] = {
     BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL),
     BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL),
     BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL),
+    BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, "D", NULL),
 };
 
 
diff -ru ../z.old/Src/Modules/zutil.mdd Src/Modules/zutil.mdd
--- ../z.old/Src/Modules/zutil.mdd	Wed Feb  9 09:57:11 2000
+++ Src/Modules/zutil.mdd	Wed Feb  9 17:21:43 2000
@@ -4,4 +4,4 @@
 
 objects="zutil.o"
 
-autobins="zformat zstyle"
+autobins="zformat zstyle zregexparse zparseopts"

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2000-02-17  9:12 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-02-10 11:53 PATCH: file completion Sven Wischnowsky
  -- strict thread matches above, loose matches on Subject: below --
2000-02-17  9:12 Sven Wischnowsky
2000-02-10 11:51 Sven Wischnowsky
2000-02-09 16:25 Sven Wischnowsky
2000-02-09 18:50 ` Bart Schaefer
2000-02-09 21:54 ` Tanaka Akira

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