Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Completion for gtar

On Aug 25,  4:29pm, Bruce Stephens wrote:
} Subject: Completion for gtar

Have you looked at PWS's tar completion in Misc/compctl-examples in 3.1.4?
It even has a function to extract completable file names from the tar file.

} So, a quick approach is to complete the first argument specially, and
} have the rest just as files:
} taropts=({z,}{t,x,c}{v,}{p,}f)
} compctl -f -x 'p[1]' -k "($taropts)" -- gtar

You can just do

	compctl -f -x 'p[1]' -k taropts -- gtar

unless you want to unset taropts and not have it hanging around.

} Here, I want to match either a -, or any file
} (anywhere in the filestore) ending in .tar.gz or .tar.Z.  -g allows
} several patterns separated by spaces, so that's not a problem.

I don't think that means what you think it means.  If you put the "-"
in the list of -g patterns, then it's treated as a file name.  It just
so happens that, because it has no wildcards, it never gets dropped
from the list of completions.  So you'll find that you can complete
e.g. like this:

zsh% gtar zxf ~/<TAB>
zsh% gtar zxf ~/-

even when there's no file named "-" in your home dir.

If you think you need to complete "-" (which boggles me, as it's only
one character; just type it!) you probably want:

	compctl -f -x 'p[1]' -k taropts \
	        - 'p[2] W[1,*z*]' -/g '*.tar.(gz|Z)' -k '(-)' \
		-- gtar

BTW, don't you want to add W[1,*f*] to that?  You don't want to complete
file names if there's no "f" option.

} My first guess, using -g '**/*.tar.(gz|Z)' doesn't work at all well:
} it's really slow.  Obviously my thinking was wrong.

Zsh handles all the path completion for you internally, so you don't
need the **/ unless you want to have a single TAB complete tarfile names
that are some unknown number of intervening directories below the current
directory.  The -g pattern is matched against files in the directory to
which you have completed so far, so you only need the tail.

} compctl -f -x 'p[1]' -k "($taropts)" \
} 	- 'p[2] W[1,*z*]' -/g '- *.tar.(gz|Z)' \
} 	- 'p[2] W[1,^*z*]' -/g '- *.tar' -- gtar
} And another thing: why isn't there any sense of exclusive ors?

All -x options are exclusive, or more accurately, they're short-circuited.
So as soon as 'p[2] W[1,*z*]' has matched, no other -x pattern is tried.
Thus you could have written:

	compctl -f -x 'p[1]' -k taropts \
		- 'p[2] W[1,*z*] W[1,*f*]' -/g '*.tar.(gz|Z)' -k '(-)' \
		- 'p[2] W[1,*f*]' -/g '*.tar' -k '(-)' \
	 	-- gtar

} How can I best express this kind of thing?  Is this what alternation
} is about?

That is what alternation is about, but alternation works differently.
The -x branches are short-circuited on whether their patterns match, so
once you take a -x branch you can never see completions from any of the
other branches, even if no completions result from the branch where the
patterns matched.

Alternation with "+", on the other hand, short-circuits on whether the
list of possible completions is empty, so it'll keep trying until it
runs out of alternatives or finds one that produces something.

} Lastly, sometimes I want to extract specific files from a tarfile, so
} it would be nice for completion to be available for that (using a
} function, in this case, but perhaps I could use -s in some wacky
} fashion?).

You can't really use -s because there's no way to get at the other parts
of the command line (to get the name of the tarfile itself) during the -s

} The "read -Ac args" isn't entirely obvious from the docs.

There probably should be mention of -A made under the -c description.

} The function just lists the files in the archive (which is,
} confusingly, the third in the args array, but the second argument in
} the compctl pattern).  Similarly, the check to see whether the archive
} is compressed or not has to check $args[2], whereas it's 'p[1]' in the
} compctl.

Add to the function
	setopt localoptions ksharrays
and then $args[1] and -x 'p[1]' will match up.  There may be some other
ksh array behavior that you don't want, though, so ....

} And how can I arrange a fallback: suppose the archive
} doesn't exist---how can I get the equivalent of -f or something in
} this case?  Do I write
} 	reply=($1*$2*)
} or something?  (Setting NULL_GLOB as a local option in the function.)

Yes, that should do it.

} I'm not sure how this feeds back to the compctl discussion (on
} zsh-workers).

Additions discussed on zsh-workers would include letting you "factor
out" the -k '(-)' from the last of my examples above.  Otherwise there
isn't much that overlaps.

} Specifying a file matching a pattern is a bit strange: -/g '*.gz'.

As I said in another post, the -/ is one option (match directories), the
-g is another.

} I don't think it's clear how the arguments are numbered.  In the
} compctl, is -1 the last argument?


} I assume it is, or is it 0?

0 is the command name.

} In the function, I just guessed at the numbering.

Zsh array indices are 1-based, so when you read the input line into args
with `read -Ac args` you've put the command (compctl position 0) into
the first array element (array index 1).  If you setopt ksharrays, the
array indices become 0-based, the same as the compctl.  In all cases,
numbering from the "wrong" end -1,-2,etc. starts with the last argument.

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

Messages sorted by: Reverse Date, Date, Thread, Author