diff --git a/ChangeLog b/ChangeLog index 7eab7c1f8..4898d42aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2006-08-01 Peter Stephenson + * 22573: Functions/Zle/history-beginning-search-menu, + Doc/Zsh/params.yo: smooth the interface to the widget and + document how to quote metacharacters for reverse array + subscripting. + * 22572: Src/pattern.c, Test/D04parameter.ztst: use of (#m) was broken with pure strings. diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index 9212f8593..fe005ed21 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -211,6 +211,18 @@ example (assuming the option tt(KSH_ARRAYS) is not in effect): example([[ ${array[(i)pattern]} -le ${#array} ]]) If tt(KSH_ARRAYS) is in effect, the tt(-le) should be replaced by tt(-lt). + +Note that in subscripts with both `tt(r)' and `tt(R)' pattern characters +are active even if they were substituted for a parameter (regardless +of the setting of tt(GLOB_SUBST) which controls this feature in normal +pattern matching). It is therefore necessary to quote pattern characters +for an exact string match. Given a string in tt($key), and assuming +the tt(EXTENDED_GLOB) option is set, the following is sufficient to +match an element of an array tt($array) containing exactly the value of +tt($key): + +example(key2=${key//(#m)[\][+LPAR()+RPAR()\\*?#<>]/\\$MATCH} +print ${array[(R)$key2]}) ) item(tt(R))( Like `tt(r)', but gives the last match. For associative arrays, gives diff --git a/Functions/Zle/history-beginning-search-menu b/Functions/Zle/history-beginning-search-menu index 616cc7d7f..46a6a776b 100644 --- a/Functions/Zle/history-beginning-search-menu +++ b/Functions/Zle/history-beginning-search-menu @@ -45,7 +45,7 @@ if [[ $WIDGET = *-space* ]]; then # since they are otherwise active in the reverse subscript. # We need to avoid quoting other characters since they aren't # and just stay quoted, rather annoyingly. - search=${search//(#m)[*?#<>]/\\$MATCH/} + search=${search//(#m)[\][()\\*?#<>]/\\$MATCH/} search=${search// /*} fi @@ -69,8 +69,19 @@ integer i display=(${matches/(#m)*/${(l.$width..0.):-$((++i))} $MATCH}) zle -R "Enter digit${${width##1}:+s}:" $display -local chars -read -k$width chars +integer i +local char chars + +# Abort on first non-digit entry instead of requiring all +# characters to be typed (as "read -k$width chars" would do). +for (( i = 0; i < $width; i++ )); do + read -k char + if [[ $char != [[:digit:]] ]]; then + zle -R '' $display + return 1 + fi + chars+=$char +done # Hmmm... this isn't great. The only way of clearing the display # appears to be to overwrite it completely. I think that's because @@ -78,25 +89,37 @@ read -k$width chars # properly. display=(${display//?/ }) -if [[ $chars != [[:digit:]]## || $chars -eq 0 || $chars -gt $n ]]; then +if [[ $chars -eq 0 || $chars -gt $n ]]; then zle -R '' $display return 1 fi -if [[ $WIDGET = *-end* ]]; then - LBUFFER=${matches[$chars]} RBUFFER= -else - integer newcursor +integer newcursor +if [[ $WIDGET != *-end* ]]; then if (( ${+NUMERIC} )); then # Advance cursor so that it's still after the string typed local -a match mbegin mend if [[ $matches[$chars] = (#b)(*${LBUFFER})* ]]; then - newcursor=${#match[1]} + newcursor=${#match[1]} fi + else + # Maintain cursor + newcursor=$CURSOR fi +fi - BUFFER=${matches[$chars]} - (( newcursor )) && CURSOR=$newcursor +# Find the history lines that contain the matched string and +# go to the last one. This allows accept-line-and-down-history etc. +# to work. +local -a lines +local matchq=${matches[$chars]//(#m)[\][()\\*?#<>]/\\$MATCH} +lines=(${(kon)history[(R)$matchq]}) +HISTNO=$lines[-1] + +if (( newcursor )); then + CURSOR=$newcursor +elif [[ $WIDGET = *-end* ]]; then + CURSOR=${#BUFFER} fi zle -R '' $display