From 8aac69241f5882e379509b3688c2f8e78cc71171 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 6 Oct 2010 08:27:09 +0000 Subject: 28319: (z) splitting oddities --- ChangeLog | 5 ++- Src/hist.c | 106 ++++++++++++++++++++++++++++++++++++++++--------- Test/D04parameter.ztst | 28 +++++++++++++ 3 files changed, 120 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 66b3fa65c..3a026c313 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2010-10-06 Peter Stephenson + * 28319: Src/hist.c, Test/D04parameter.ztst: ${(z)...} + splitting oddities and some tests for consistency. + * 28285: Doc/Zsh/zle.yo, Src/Zle/zle_hist.c: add zle-isearch-update and zle-isearch-exit hooks. @@ -13700,5 +13703,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5094 $ +* $Revision: 1.5095 $ ***************************************************** diff --git a/Src/hist.c b/Src/hist.c index b9f315280..6cb7e1d31 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -2869,6 +2869,7 @@ bufferwords(LinkList list, char *buf, int *index) int num = 0, cur = -1, got = 0, ne = noerrs; int owb = wb, owe = we, oadx = addedx, ozp = zleparse, onc = nocomments; int ona = noaliases, ocs = zlemetacs, oll = zlemetall; + int forloop = 0; char *p, *addedspaceptr; if (!list) @@ -2942,25 +2943,84 @@ bufferwords(LinkList list, char *buf, int *index) ctxtlex(); if (tok == ENDINPUT || tok == LEXERR) break; - if (tokstr && *tokstr) { - untokenize((p = dupstring(tokstr))); - if (ingetptr() == addedspaceptr + 1) { - /* - * Whoops, we've read past the space we added, probably - * because we were expecting a terminator but when - * it didn't turn up we shrugged our shoulders thinking - * it might as well be a complete string anyway. - * So remove the space. C.f. below for the case - * where the missing terminator caused a lex error. - * We use the same paranoid test. - */ - int plen = strlen(p); - if (plen && p[plen-1] == ' ' && - (plen == 1 || p[plen-2] != Meta)) - p[plen-1] = '\0'; + if (tok == FOR) { + /* + * The way for (( expr1 ; expr2; expr3 )) is parsed is: + * - a FOR tok + * - a DINPAR with no tokstr + * - two DINPARS with tokstr's expr1, expr2. + * - a DOUTPAR with tokstr expr3. + * + * We'll decrement the variable forloop as we verify + * the various stages. + * + * Don't ask me, ma'am, I'm just the programmer. + */ + forloop = 5; + } else { + switch (forloop) { + case 1: + if (tok != DOUTPAR) + forloop = 0; + break; + + case 2: + case 3: + case 4: + if (tok != DINPAR) + forloop = 0; + break; + + default: + /* nothing to do */ + break; + } + } + if (tokstr) { + switch (tok) { + case ENVARRAY: + p = dyncat(tokstr, "=("); + break; + + case DINPAR: + if (forloop) { + /* See above. */ + p = dyncat(tokstr, ";"); + } else { + /* + * Mathematical expressions analysed as a single + * word. That's correct because it behaves like + * double quotes. Whitespace in the middle is + * similarly retained, so just add the parentheses back. + */ + p = tricat("((", tokstr, "))"); + } + break; + + default: + p = dupstring(tokstr); + break; + } + if (*p) { + untokenize(p); + if (ingetptr() == addedspaceptr + 1) { + /* + * Whoops, we've read past the space we added, probably + * because we were expecting a terminator but when + * it didn't turn up we shrugged our shoulders thinking + * it might as well be a complete string anyway. + * So remove the space. C.f. below for the case + * where the missing terminator caused a lex error. + * We use the same paranoid test. + */ + int plen = strlen(p); + if (plen && p[plen-1] == ' ' && + (plen == 1 || p[plen-2] != Meta)) + p[plen-1] = '\0'; + } + addlinknode(list, p); + num++; } - addlinknode(list, p); - num++; } else if (buf) { if (IS_REDIROP(tok) && tokfd >= 0) { char b[20]; @@ -2973,6 +3033,16 @@ bufferwords(LinkList list, char *buf, int *index) num++; } } + if (forloop) { + if (forloop == 1) { + /* + * Final "))" of for loop to match opening, + * since we've just added the preceding element. + */ + addlinknode(list, dupstring("))")); + } + forloop--; + } if (!got && !zleparse) { got = 1; cur = num - 1; diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index 4594e62fd..fe978263f 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -389,6 +389,34 @@ >) >ten( more + strings=( + 'foo=(1 2 3)' + '(( 3 + 1 == 8 / 2 ))' + 'for (( i = 1 ; i < 10 ; i++ ))' + ) + for string in $strings; do + array=(${(z)string}) + for (( i = 1; i <= ${#array}; i++ )); do + print -r -- "${i}:${array[i]}:" + done + done +0:Some syntactical expressions that are hard to split into words with (z). +>1:foo=(: +>2:1: +>3:2: +>4:3: +>5:): +>1:(( 3 + 1 == 8 / 2 )): +>1:for: +>2:((: +# Leading whitespace is removed, because the word proper hasn't started; +# trailing whitespace is left because the word is terminated by the +# semicolon or double parentheses. Bit confusing but sort of consistent. +>3:i = 1 ;: +>4:i < 10 ;: +>5:i++ : +>6:)): + psvar=(dog) setopt promptsubst foo='It shouldn'\''t $(happen) to a %1v.' -- cgit 1.4.1