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

Re: Completion weirdity after `for'



Peter Stephenson wrote:

> 
> After
> 
> for f in <TAB>
> 
> completion takes place as if the command name is `in', not `for'.
> This showed up because I have a function called `in' such that `in dir
> cmdlist' executes cmdlist in directory dir, so I have the first word
> after `in' complete directories, which is not what is wanted here.
> 
> The natural way to handle this would be such that everything up to and
> including the list were treated as words of a fictitious `for'
> command, so e.g. you can specify special behaviour for arguments 1 and
> 2 and default for the rest.  This is possible to fix, but like most
> things to do with get_comp_string() the fix could be a little ad hoc.
> Maybe other reserved words need some fix-up, but for and foreach are
> the worst offenders since others tend to be followed by a specific
> command which then works in the expected way.

The patch below is my attempt at this. With it you can define things
like:

  compctl -v -x 'p[2]' -k '(in)' - 'p[3,-1]' -f -- for

(or whatever you like to complete).

This is done for `for', `foreach', `select', `repeat', and `case'. The 
thing for `repeat' was a bi more complicated to make completion after
`repeat x ' and after `repeat x do' work. For `case' I haven't done
any special handling yet, so this still fails utterly (try completion
after a pattern, you'll get default completion, not command
completion). Due to the way the lexer reports things for the `case'
construct making this work right may get a bit more complicated
(though I have the feeling that we should make this work, too, so I
may come back to this).

Anyway, I would like to hear about any problems you encounter with
patch...

Bye
 Sven

*** os/Zle/zle_tricky.c	Wed Jan 20 09:09:56 1999
--- Src/Zle/zle_tricky.c	Wed Jan 20 12:01:43 1999
***************
*** 890,896 ****
  static char *
  get_comp_string(void)
  {
!     int t0, tt0, i, j, k, cp, rd, sl, ocs;
      char *s = NULL, *linptr, *tmp, *p, *tt = NULL;
  
      zsfree(brbeg);
--- 890,896 ----
  static char *
  get_comp_string(void)
  {
!     int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins;
      char *s = NULL, *linptr, *tmp, *p, *tt = NULL;
  
      zsfree(brbeg);
***************
*** 950,956 ****
  	inpush(dupstrspace((char *) linptr), 0, NULL);
  	strinbeg();
  	stophist = 2;
! 	i = tt0 = cp = rd = 0;
  
  	/* This loop is possibly the wrong way to do this.  It goes through *
  	 * the previously massaged command line using the lexer.  It stores *
--- 950,956 ----
  	inpush(dupstrspace((char *) linptr), 0, NULL);
  	strinbeg();
  	stophist = 2;
! 	i = tt0 = cp = rd = ins = oins = 0;
  
  	/* This loop is possibly the wrong way to do this.  It goes through *
  	 * the previously massaged command line using the lexer.  It stores *
***************
*** 964,971 ****
  	 * this would be to pass the command line through the parser too,   *
  	 * and get the arguments that way.  Maybe in 3.1...                 */
  	do {
! 	    lincmd = incmdpos;
! 	    linredir = inredir;
  	    /* Get the next token. */
  	    ctxtlex();
  	    if (tok == DINPAR)
--- 964,973 ----
  	 * this would be to pass the command line through the parser too,   *
  	 * and get the arguments that way.  Maybe in 3.1...                 */
  	do {
! 	    lincmd = ((incmdpos && !ins) || (oins == 2 && i == 2) ||
! 		      (ins == 3 && i == 1));
! 	    linredir = (inredir && !ins);
! 	    oins = ins;
  	    /* Get the next token. */
  	    ctxtlex();
  	    if (tok == DINPAR)
***************
*** 974,980 ****
  	    /* We reached the end. */
  	    if (tok == ENDINPUT)
  		break;
! 	    if (tok == BAR    || tok == AMPER     ||
  		tok == BARAMP || tok == AMPERBANG ||
  		((tok == DBAR || tok == DAMPER) && !incond)) {
  		/* This is one of the things that separate commands.  If we  *
--- 976,984 ----
  	    /* We reached the end. */
  	    if (tok == ENDINPUT)
  		break;
! 	    if ((ins && (tok == DO || tok == SEPER)) ||
! 		(ins == 2 && i == 2) ||	(ins == 3 && i == 3) ||
! 		tok == BAR    || tok == AMPER     ||
  		tok == BARAMP || tok == AMPERBANG ||
  		((tok == DBAR || tok == DAMPER) && !incond)) {
  		/* This is one of the things that separate commands.  If we  *
***************
*** 983,993 ****
  		if (tt)
  		    break;
  		/* Otherwise reset the variables we are collecting data in. */
! 		i = tt0 = cp = rd = 0;
  	    }
! 	    if (lincmd && tok == STRING) {
  		/* The lexer says, this token is in command position, so *
  		 * store the token string (to find the right compctl).   */
  		zsfree(cmdstr);
  		cmdstr = ztrdup(tokstr);
  		i = 0;
--- 987,999 ----
  		if (tt)
  		    break;
  		/* Otherwise reset the variables we are collecting data in. */
! 		i = tt0 = cp = rd = ins = 0;
  	    }
! 	    if (lincmd && (tok == STRING || tok == FOR || tok == FOREACH ||
! 			   tok == SELECT || tok == REPEAT || tok == CASE)) {
  		/* The lexer says, this token is in command position, so *
  		 * store the token string (to find the right compctl).   */
+ 		ins = (tok == REPEAT ? 2 : (tok != STRING));
  		zsfree(cmdstr);
  		cmdstr = ztrdup(tokstr);
  		i = 0;
***************
*** 1008,1013 ****
--- 1014,1022 ----
  	    }
  	    if (!tokstr)
  		continue;
+ 	    /* Hack to allow completion after `repeat n do'. */
+ 	    if (oins == 2 && !i && !strcmp(tokstr, "do"))
+ 		ins = 3;
  	    /* We need to store the token strings of all words (for some of *
  	     * the more complicated compctl -x things).  They are stored in *
  	     * the clwords array.  Make this array big enough.              */

--
Sven Wischnowsky                         wischnow@xxxxxxxxxxxxxxxxxxxxxxx



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