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

Re: Question about completeion.

On Jul 25,  3:47pm, Andrej Borsenkow wrote:
} Subject: Question about completeion.
} Now I would like to write small wrapper around cd, so that
} % cd /u/l/l/t<RETURN>
} would change dir into /usr/local/lib/texmf iff the match is unique;
} otherweise expand argument and leave me in MENU mode. 

This is not currently possible in zsh.

Zsh lacks two features necessary for this to work:

First, although zsh has `print -z', any characters inserted into the
input by this method are implicitly quoted; so you can't (for example)
use "print -Pz '\eA'" to cause zsh to execute accept-and-hold.  Instead
you get a escape character and an `A' inserted into the zle buffer.

(An alternative, which I would love to have, would be a way to shove a
zle command onto the input BY NAME, even when it is not bound to any
keystroke; e.g. `print -Zz accept-line'.)

Second, there's no way to cause a `bindkey -s' sequence to abort in the
middle.  E.g. in vi, if a `map' macro contains an impossible motion or
any other failed action, the entire macro aborts at the point of failure.
In zsh, the keystrokes keep right on going as if nothing was wrong, so
you have to be very careful with `bindkey -s' to avoid doing anything
destructive after a sequence that might not always succeed.

Either of these alone would make what you want possible, but zsh has

} I am not so skillfull in zsh programming; also, I am not sure if I can
} call completion from inside of shell function.

No, you cannot.

The approach would have to be to rebind RETURN to do expand-or-complete
followed by accept-line, e.g. bindkey -s '^M' '\t^J'.  However, there's
no way to stop the accept-line from happening when the expand-or-complete
doesn't find a unique match.

I suppose you could reverse the procedure ...

	bindkey -s '^M' '^J\t'
	cd () {
	    local d=()
	    eval d=( "*${1:gs@/@*/*@}*" )	# Crude stand-in for multicomp;
						# you should use the real thing
						# (modified to avoid "read -c")
	    [[ $#d -eq 1 ]] && builtin cd $d
	    [[ $#d -ne 1 ]] && print -z cd $1
	alias cd="noglob cd"			# Let globbing happen inside

Then when you hit return, your cd wrapper would execute.  If it finds a
directory to switch to, it switches there, otherwise it shoves the original
command back and then the \t from the bindkey completes it.

However, this leaves you with a leading tab on the next command line for
every command other than an unsuccessful cd, which is probably annoying.

So the closest you could get to what you want is to use a cd wrapper like
the one above (with print -z on failure) and DO NOT rebind RETURN.  Then
when your cd fails you get the command line back and you can manually type
TAB to begin menu completion.

Bart Schaefer                             Brass Lantern Enterprises
http://www.well.com/user/barts            http://www.nbn.com/people/lantern

New male in /home/schaefer:
>N  2 Justin William Schaefer  Sat May 11 03:43  53/4040  "Happy Birthday"

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