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

Re: Segfault completing: for f in 1; do <[here] x



[Sorry, meant to send this on Friday, which would have helped Bart's
investigation.  Comments welcome.]


On Fri, 26 Jul 2013 11:20:52 +0100
solo-zsh@xxxxxxxxxxxxx wrote:
> I'm getting a segfault when trying to complete after the "<" in:
> for f in 1; do < x

Yes, this is easy to reproduce.

Unfortunately we're in one of those functions that nobody dares rewrite
because it never really got written properly in the first place.

The following tweaks fix the problem above and appear to be moderately safe.
The incomprehensible "ins < 2" test safeguards against hitting the
tricks used with completions after e.g. "repeat 2" which is done a hacky
way.  I don't understand why we need to set "ins" just to be able to
detect the DOLOOP token on the next word, but I definitely don't dare
change that.

Could do with some playing with in similar cases with complicated
syntax.

Anyone with some free time is welcome to have a go at this function and
report back even if they don't actually achieve any improvements (nobody
else ever has).

It's being so cheerful as keeps me going.

diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 78a9fa4..610055c 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -1095,6 +1095,7 @@ get_comp_string(void)
      * the command word is not at index zero in the array.
      */
     int redirpos;
+    int noword;
     char *s = NULL, *tmp, *p, *tt = NULL, rdop[20];
     char *linptr, *u;
 
@@ -1165,7 +1166,7 @@ get_comp_string(void)
     * and whatnot. */
 
     do {
-        qsub = 0;
+        qsub = noword = 0;
 
 	lincmd = ((incmdpos && !ins && !incond) ||
 		  (oins == 2 && wordpos == 2) ||
@@ -1239,6 +1240,19 @@ get_comp_string(void)
 	     * leave the loop.                                           */
 	    if (tt)
 		break;
+	    if (ins < 2) {
+		/*
+		 * Don't add this as a word, because we're about to start
+		 * a new command line: pretend there's no string here.
+		 * We don't dare do this if we're using one of the
+		 * *really* gross hacks with ins to get later words
+		 * to look like command words, because we don't
+		 * understand how they work.  Quite possibly we
+		 * should be using a mechanism like the one here rather
+		 * than the ins thing.
+		 */
+		noword = 1;
+	    }
 	    /* Otherwise reset the variables we are collecting data in. */
 	    wordpos = cp = rd = ins = redirpos = 0;
 	    tt0 = NULLTOK;
@@ -1253,6 +1267,14 @@ get_comp_string(void)
 	    /* If everything before is a redirection, don't reset the index */
 	    if (wordpos != redirpos)
 		wordpos = redirpos = 0;
+	} else if (tok == SEPER) {
+	    /*
+	     * A following DOLOOP should cause us to reset to the start
+	     * of the command line.  For some reason we only recognise
+	     * DOLOOP for this purpose (above) if ins is set.  Why?
+	     * Don't ask pointless questions.
+	     */
+	    ins = 1;
 	}
 	if (!lexflags && tt0 == NULLTOK) {
 	    /* This is done when the lexer reached the word the cursor is on. */
@@ -1322,7 +1344,7 @@ get_comp_string(void)
 	    else if (tok == DAMPER)
 		tokstr = "&&";
 	}
-	if (!tokstr)
+	if (!tokstr || noword)
 	    continue;
 	/* Hack to allow completion after `repeat n do'. */
 	if (oins == 2 && !wordpos && !strcmp(tokstr, "do"))


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