From 3a97920199accf4f63b622645ea208ccad42d07b Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 14 Aug 2006 16:14:41 +0000 Subject: 22606: add match-word-context. Remove workaround from match-words-by-style --- ChangeLog | 5 ++++ Doc/Zsh/contrib.yo | 37 ++++++++++++++++++++++++++--- Functions/Zle/.distfiles | 1 + Functions/Zle/match-word-context | 48 ++++++++++++++++++++++++++++++++++++++ Functions/Zle/match-words-by-style | 26 +++++---------------- 5 files changed, 94 insertions(+), 23 deletions(-) create mode 100644 Functions/Zle/match-word-context diff --git a/ChangeLog b/ChangeLog index eb1bb8c17..1c4d0309f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2006-08-14 Peter Stephenson + * 22606: Doc/Zsh/contrib.yo, Functions/Zle/match-word-context, + Functions/Zle/match-words-by-style, Functions/Zle/.distfiles: new + word-context style for word matching, remove out-of-date handling + for bug. + * 22605: Src/Zle/complist.c: bug in 22597 noticed by Bart when not printing. diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index ca71bbd61..d6b4a9ef6 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -384,12 +384,13 @@ tindex(capitalize-word-match) tindex(up-case-word-match) tindex(down-case-word-match) tindex(select-word-style) +tindex(match-word-context) tindex(match-words-by-style) xitem(tt(forward-word-match), tt(backward-word-match)) xitem(tt(kill-word-match), tt(backward-kill-word-match)) xitem(tt(transpose-words-match), tt(capitalize-word-match)) xitem(tt(up-case-word-match), tt(down-case-word-match)) -item(tt(select-word-style), tt(match-words-by-style))( +item(tt(select-word-style), tt(match-word-context), tt(match-words-by-style))( The eight `tt(-match)' functions are drop-in replacements for the builtin widgets without the suffix. By default they behave in a similar way. However, by the use of styles and the function tt(select-word-style), @@ -463,7 +464,7 @@ Words are whitespace-delimited strings of characters. ) enditem() -The first three of those styles usually use tt($WORDCHARS), but the value +The first three of those rules usually use tt($WORDCHARS), but the value in the parameter can be overridden by the style tt(word-chars), which works in exactly the same way as tt($WORDCHARS). In addition, the style tt(word-class) uses character class syntax to group characters and takes @@ -474,7 +475,7 @@ alphanumerics plus the characters `tt(-)' and `tt(:)'. Be careful including `tt(])', `tt(^)' and `tt(-)' as these are special inside character classes. -The final style is tt(skip-chars). This is mostly useful for +The style tt(skip-chars) is mostly useful for tt(transpose-words) and similar functions. If set, it gives a count of characters starting at the cursor position which will not be considered part of the word and are treated as space, regardless of what they actually @@ -486,6 +487,17 @@ has been set, and tt(transpose-words-match) is called with the cursor on the var(X) of tt(foo)var(X)tt(bar), where var(X) can be any character, then the resulting expression is tt(bar)var(X)tt(foo). +Finer grained control can be obtained by setting the style +tt(word-context) to an array of pairs of entries. Each pair of entries +consists of a var(pattern) and a var(subcontext). The word the cursor is on is +matched against each var(pattern) in turn until one matches; if it does, +the context is extended by a colon and the corresponding var(subcontext). +Note that the test is made against the original word on the line, with +no stripping of quotes. If the cursor is at the end of the line +the test is maded against an empty string; if it is on whitespace +between words the test is made against a single space. Some examples +are given below. + Here are some examples of use of the styles, actually taken from the simplified interface in tt(select-word-style): @@ -501,6 +513,21 @@ example(style ':zle:*kill*' word-style space) Uses space-delimited words for widgets with the word `kill' in the name. Neither of the styles tt(word-chars) nor tt(word-class) is used in this case. +Here are some examples of use of the tt(word-context) style to extend +the context. + +example(zstyle ':zle:*' word-context "[[:space:]]" whitespace "*/*" file +zstyle ':zle:transpose-words:whitespace' word-style shell +zstyle ':zle:transpose-words:filename' word-style normal +zstyle ':zle:transpose-words:filename' word-chars '') + +This provides two different ways of using tt(transpose-words) depending on +whether the cursor is on whitespace between words or on a filename, here +any word containing a tt(/). On whitespace, complete arguments as defined +by standard shell rules will be transposed. In a filename, only +alphanumerics will be transposed. Elsewhere, words will be transposed +using the default style for tt(:zle:transpose-words). + The word matching and all the handling of tt(zstyle) settings is actually implemented by the function tt(match-words-by-style). This can be used to create new user-defined widgets. The calling function should set the local @@ -527,6 +554,10 @@ endsitem() For example, tt(match-words-by-style -w shell -c 0) may be used to extract the command argument around the cursor. + +The tt(word-context) style is implemented by the function +tt(match-word-context). This should not usually need to be called +directly. ) tindex(delete-whole-word-match) item(tt(delete-whole-word-match))( diff --git a/Functions/Zle/.distfiles b/Functions/Zle/.distfiles index fdf282ab5..276f17b33 100644 --- a/Functions/Zle/.distfiles +++ b/Functions/Zle/.distfiles @@ -11,6 +11,7 @@ incarg incremental-complete-word insert-composed-char insert-files insert-unicode-char keeper keymap+widget kill-word-match +match-word-context match-words-by-style narrow-to-region narrow-to-region-invisible predict-on quote-and-complete-word read-from-minibuffer diff --git a/Functions/Zle/match-word-context b/Functions/Zle/match-word-context new file mode 100644 index 000000000..da68b6c75 --- /dev/null +++ b/Functions/Zle/match-word-context @@ -0,0 +1,48 @@ +# See if we can extend the word context to something more specific. +# curcontext must be set to the base context by this point; it +# will be appended to directly. + +emulate -L zsh +setopt extendedglob + +local -a worcon bufwords +local pat tag lastword word +integer iword + +zstyle -a $curcontext word-context worcon || return 0 + +if (( ${#worcon} % 2 )); then + zle -M "Bad word-context style in context $curcontext" + return +fi + +bufwords=(${(z)LBUFFER}) +iword=${#bufwords} +lastword=${bufwords[-1]} +bufwords=(${(z)BUFFER}) + +if [[ $lastword = ${bufwords[iword]} ]]; then + # If the word immediately left of the cursor is complete, + # we're not on it. Either we're on unquoted whitespace, or + # the start of a new word. Test the latter. + if [[ -z $RBUFFER ]]; then + # Nothing there, so not in a word. + word='' + elif [[ $RBUFFER[1] = [[:space:]] ]]; then + # Whitespace, so not in a word. + word=' ' + else + # We want the next word along. + word=${bufwords[iword+1]} + fi +else + # We're on a word. + word=${bufwords[iword]} +fi + +for pat tag in "${worcon[@]}"; do + if [[ $word = ${~pat} ]]; then + curcontext+=":$tag" + return + fi +done diff --git a/Functions/Zle/match-words-by-style b/Functions/Zle/match-words-by-style index def43f2e9..ad74a984f 100644 --- a/Functions/Zle/match-words-by-style +++ b/Functions/Zle/match-words-by-style @@ -71,9 +71,10 @@ local wordstyle spacepat wordpat1 wordpat2 opt charskip wordchars wordclass local match mbegin mend pat1 pat2 word1 word2 ws1 ws2 ws3 skip local nwords MATCH MBEGIN MEND -if [[ -z $curcontext ]]; then - local curcontext=:zle:match-words-by-style -fi +local curcontext=${curcontext:-:zle:match-words-by-style} + +autoload -U match-word-context +match-word-context while getopts "w:s:c:C:" opt; do case $opt in @@ -108,27 +109,12 @@ case $wordstyle in # This splits the line into words as the shell understands them. bufwords=(${(z)LBUFFER}) nwords=${#bufwords} - # Work around bug: if stripping quotes failed, a bogus - # space is appended. Not a good test, since this may - # be a quoted space, but it's hard to get right. - wordpat1=${bufwords[-1]} - if [[ ${wordpat1[-1]} = ' ' ]]; then - wordpat1=${(q)wordpat1[1,-2]} - else - wordpat1="${(q)wordpat1}" - fi + wordpat1="${(q)bufwords[-1]}" # Take substring of RBUFFER to skip over $skip characters # from the cursor position. bufwords=(${(z)RBUFFER[1+$skip,-1]}) - # Work around bug again. - wordpat2=${bufwords[1]} - if [[ ${wordpat2[-1]} = ' ' ]] - then - wordpat2=${(q)wordpat2[1,-2]} - else - wordpat2="${(q)wordpat2}" - fi + wordpat2="${(q)bufwords[1]}" spacepat='[[:space:]]#' # Assume the words are at the top level, i.e. if we are inside -- cgit 1.4.1