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

Completion for gtar



Well, I've had a proper play with completion (while waiting for a long
recompile), and come up with this completion pattern for the things I
most often do with gtar.  This certainly doesn't do everything---it
just fills in a few bits that I've found irritating.

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

taropts expands to:

ztvpf ztvf ztpf ztf zxvpf zxvf zxpf zxf zcvpf zcvf zcpf zcf tvpf tvf
tpf tf xvpf xvf xpf xf cvpf cvf cpf cf

of course.

A next obvious idea is to complete the second argument specially:

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

Yuck.  After matching the 'p[2] W[1,*z*]', how do I say there are a
few possibilities?  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.

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

Ah, I see.  Obviously the - is special (so I can't say "-g - -g
'*.tar'"), but I *can* have multiple options.  So in this case, I can
write:

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

which is a little clearer.  And I can also stick -k options and things:

compctl -x 'p[1]' -/g '*.gz' -k "(a b c)" -- foo

This will have the first argument to foo expanding to .gz files
(anywhere), or a, b or c.

And another thing: why isn't there any sense of exclusive ors?  The
second two lines are exclusive: either the second argument contains a
z (and I want to match compressed files) or it doesn't (and I don't).
How can I best express this kind of thing?  Is this what alternation
is about?

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

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

I don't want to try listing archives from stdin, hence the W[2,^-].

And the function:

function gtar_files {
	local args opt
	read -Ac args
	if [[ $args[2] == *z* ]]; then
		opt=ztf
	else
		opt=tf
	fi
	reply=($(gtar $opt $args[3]))
}

The "read -Ac args" isn't entirely obvious from the docs.  It's pretty
clear from looking at the examples.

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

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

The structure is a bit confusing---I haven't used alternation here,
and I'm not sure how it fits into the rest.

Specifying a file matching a pattern is a bit strange: -/g '*.gz'.  I
can live with it, though.  Perhaps it ought to be mentioned in the
documentation, so it's more obvious that that's what you're supposed
to do, since this is a really common thing to want to do.  I guess the
very end of 4.2 of the FAQ sort of mentions it, but I missed it at
first reading.

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?  In the
function, I just guessed at the numbering.



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