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

Re: zsh deep freeze (probably autocompletion-related)



On Mon, 07 Dec 2009 17:13:51 +0000
Peter Stephenson <pws@xxxxxxx> wrote:
> The backslash-newline is being swallowed in the input / lex code,
> causing ZLE to miscount the size of the string it's got back by 2.
> Ideally it should be included in qsub in the same way it handles
> RC_QUOTES.

I think the following is OK as far as it goes: it does fix up the string
that's being completed, since I can see that both uses of chuck(), on
the string from the lexer and the string going into the words array, are
coming out right.  Also, I haven't messed up completion later on in the
second line, i.e. in words after the one with the backslash-newline in
it.

However, it doesn't actually make completion work at that point.  That
doesn't surprise me much or worry me.  If anyone really has enough time
on their hands to get that to work they're welcome to look, but I think
the way the command line is split in two makes it virtually impossible
to do this without rewriting the line editor, nor do I consider it
within the spirit of completion to require it to work there.
Familiarise yourself with push-line-or-edit.

Most of the bulk of the patch is because I finally got fed up with "i"
being used sometimes as an internal loop variable and sometimes as the
index of the word being completed.

Index: Src/Zle/zle_tricky.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_tricky.c,v
retrieving revision 1.100
diff -u -r1.100 zle_tricky.c
--- Src/Zle/zle_tricky.c	15 Aug 2009 16:59:22 -0000	1.100
+++ Src/Zle/zle_tricky.c	7 Dec 2009 21:25:10 -0000
@@ -1067,6 +1067,10 @@
     int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins, ia, parct, varq = 0;
     int ona = noaliases;
     /*
+     * Index of word being considered
+     */
+    int wordpos;
+    /*
      * qsub fixes up the offset into the current completion word
      * for changes made by the lexer.  That currently means the
      * effect of RCQUOTES on embedded pairs of single quotes.
@@ -1141,7 +1145,7 @@
     lexsave();
     inpush(dupstrspace(linptr), 0, NULL);
     strinbeg(0);
-    i = tt0 = cp = rd = ins = oins = linarr = parct = ia = redirpos = 0;
+    wordpos = tt0 = cp = rd = ins = oins = linarr = parct = ia = redirpos = 0;
 
     /* This loop is possibly the wrong way to do this.  It goes through *
      * the previously massaged command line using the lexer.  It stores *
@@ -1154,8 +1158,9 @@
     do {
         qsub = 0;
 
-	lincmd = ((incmdpos && !ins && !incond) || (oins == 2 && i == 2) ||
-		  (ins == 3 && i == 1));
+	lincmd = ((incmdpos && !ins && !incond) ||
+		  (oins == 2 && wordpos == 2) ||
+		  (ins == 3 && wordpos == 1));
 	linredir = (inredir && !ins);
 	oins = ins;
 	/* Get the next token. */
@@ -1198,7 +1203,7 @@
                 strcpy(rdop, tokstrings[tok]);
             strcpy(rdstr, rdop);
 	    /* Record if we haven't had the command word yet */
-	    if (i == redirpos)
+	    if (wordpos == redirpos)
 		redirpos++;
         }
 	if (tok == DINPAR)
@@ -1208,7 +1213,7 @@
 	if (tok == ENDINPUT)
 	    break;
 	if ((ins && (tok == DOLOOP || tok == SEPER)) ||
-	    (ins == 2 && i == 2) || (ins == 3 && i == 3) ||
+	    (ins == 2 && wordpos == 2) || (ins == 3 && wordpos == 3) ||
 	    tok == BAR    || tok == AMPER     ||
 	    tok == BARAMP || tok == AMPERBANG ||
 	    ((tok == DBAR || tok == DAMPER) && !incond) ||
@@ -1226,7 +1231,7 @@
 	    if (tt)
 		break;
 	    /* Otherwise reset the variables we are collecting data in. */
-	    i = tt0 = cp = rd = ins = redirpos = 0;
+	    wordpos = tt0 = cp = rd = ins = redirpos = 0;
 	}
 	if (lincmd && (tok == STRING || tok == FOR || tok == FOREACH ||
 		       tok == SELECT || tok == REPEAT || tok == CASE)) {
@@ -1236,15 +1241,46 @@
 	    zsfree(cmdstr);
 	    cmdstr = ztrdup(tokstr);
 	    /* If everything before is a redirection, don't reset the index */
-	    if (i != redirpos)
-		i = redirpos = 0;
+	    if (wordpos != redirpos)
+		wordpos = redirpos = 0;
 	}
 	if (!zleparse && !tt0) {
 	    /* This is done when the lexer reached the word the cursor is on. */
 	    tt = tokstr ? dupstring(tokstr) : NULL;
 
+	    /*
+	     * If there was a proper interface between this
+	     * function and the lexical analyser, we wouldn't
+	     * have to fix things up.
+	     *
+	     * Fix up backslash-newline pairs in zlemetaline
+	     * that the lexer will have removed.  As we're
+	     * looking back at the zlemetaline version it's
+	     * still using untokenized quotes.
+	     */
+	    for (i = j = k = 0, u = zlemetaline + wb;
+		 u < zlemetaline + we; u++) {
+		if (*u == '`' && !(k & 1))
+		    i++;
+		else if (*u == '\"' && !(k & 1) && !(i & 1))
+		    j++;
+		else if (*u == '\'' && !(j & 1))
+		    k++;
+		else if (*u == '\\' && u[1] && !(k & 1))
+		{
+		    if (u[1] == '\n') {
+			/* Removed by lexer in tt */
+			qsub += 2;
+		    }
+		    u++;
+		}
+	    }
+	    /*
+	     * Fix up RCQUOTES quotes that the
+	     * the lexer will also have removed.
+	     */
             if (isset(RCQUOTES) && tt) {
-		char *tt1, *e = tt + zlemetacs - wb;
+		char *tt1, *e = tt + zlemetacs - wb - qsub;
 		for (tt1 = tt; *tt1; tt1++) {
 		    if (*tt1 == Snull) {
 			char *p;
@@ -1259,7 +1295,7 @@
 		chuck(tt + zlemetacs - wb - qsub);
 	    tt0 = tok;
 	    /* Store the number of this word. */
-	    clwpos = i;
+	    clwpos = wordpos;
 	    cp = lincmd;
 	    rd = linredir;
 	    ia = linarr;
@@ -1279,39 +1315,39 @@
 	if (!tokstr)
 	    continue;
 	/* Hack to allow completion after `repeat n do'. */
-	if (oins == 2 && !i && !strcmp(tokstr, "do"))
+	if (oins == 2 && !wordpos && !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.              */
-	if (i + 1 == clwsize) {
+	if (wordpos + 1 == clwsize) {
 	    int n;
 	    clwords = (char **)realloc(clwords,
 				       (clwsize *= 2) * sizeof(char *));
-	    for(n = clwsize; --n > i; )
+	    for(n = clwsize; --n > wordpos; )
 		clwords[n] = NULL;
 	}
-	zsfree(clwords[i]);
+	zsfree(clwords[wordpos]);
 	/* And store the current token string. */
-	clwords[i] = ztrdup(tokstr);
+	clwords[wordpos] = ztrdup(tokstr);
 	sl = strlen(tokstr);
 	/* Sometimes the lexer gives us token strings ending with *
 	 * spaces we delete the spaces.                           */
-	while (sl && clwords[i][sl - 1] == ' ' &&
-	       (sl < 2 || (clwords[i][sl - 2] != Bnull &&
-			   clwords[i][sl - 2] != Meta)))
-	    clwords[i][--sl] = '\0';
+	while (sl && clwords[wordpos][sl - 1] == ' ' &&
+	       (sl < 2 || (clwords[wordpos][sl - 2] != Bnull &&
+			   clwords[wordpos][sl - 2] != Meta)))
+	    clwords[wordpos][--sl] = '\0';
 	/* If this is the word the cursor is in and we added a `x', *
 	 * remove it.                                               */
-	if (clwpos == i++ && addedx) {
+	if (clwpos == wordpos++ && addedx) {
 	    zlemetacs_qsub = zlemetacs - qsub;
-	    chuck(&clwords[i - 1][((zlemetacs_qsub - wb) >= sl) ?
+	    chuck(&clwords[wordpos - 1][((zlemetacs_qsub - wb) >= sl) ?
 				 (sl - 1) : (zlemetacs_qsub - wb)]);
 	}
     } while (tok != LEXERR && tok != ENDINPUT &&
 	     (tok != SEPER || (zleparse && !tt0)));
     /* Calculate the number of words stored in the clwords array. */
-    clwnum = (tt || !i) ? i : i - 1;
+    clwnum = (tt || !wordpos) ? wordpos : wordpos - 1;
     zsfree(clwords[clwnum]);
     clwords[clwnum] = NULL;
     t0 = tt0;



-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



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