diff options
Diffstat (limited to 'Functions/Zle/match-words-by-style')
-rw-r--r-- | Functions/Zle/match-words-by-style | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/Functions/Zle/match-words-by-style b/Functions/Zle/match-words-by-style new file mode 100644 index 000000000..9dcc165a9 --- /dev/null +++ b/Functions/Zle/match-words-by-style @@ -0,0 +1,167 @@ +# Match words by the style given below. The matching depends on the +# cursor position. The matched_words array is set to the matched portions +# separately. These look like: +# <stuff-at-start> <word-before-cursor> <whitespace-before-cursor> +# <whitespace-after-cursor> <word-after-cursor> <whitespace-after-word> +# <stuff-at-end> +# where the cursor position is always after the third item and `after' +# is to be interpreted as `after or on'. Some +# of the array elements will be empty; this depends on the style. +# For example +# foo bar rod stick +# ^ +# with the cursor where indicated whill with typical settings produce the +# elements `foo ', `bar', ` ', ` ', `rod', ` ' and `stick'. +# +# The style word-style can be set to indicate what a word is. +# The three possibilities are: +# +# shell Words are shell words, i.e. elements of a command line. +# whitespace Words are space delimited words; only space or tab characters +# are considered to terminated a word. +# normal (the default): the usual zle logic is applied, with all +# alphanumeric characters plus any characters in $WORDCHARS +# considered parts of a word. The style word-chars overrides +# the parameter. (Any currently undefined value will be +# treated as `normal', but this should not be relied upon.) +# specified Similar to normal, except that only the words given +# in the string (and not also alphanumeric characters) +# are to be considerd parts of words. +# unspecified The negation of `specified': the characters given +# are those that aren't to be considered parts of a word. +# They should probably include white space. +# +# In the case of the `normal' or `(un)specified', more control on the +# behaviour can be obtained by setting the style `word-chars' for the +# current context. The value is used to override $WORDCHARS locally. +# Hence, +# zstyle ':zle:transpose-words*' word-style normal +# zstyle ':zle:transpose-words*' word-chars '' +# will force bash-style word recognition, i.e only alphanumeric characters +# are considerd parts of a word. It is up to the function which calls +# match-words-by-style to set the context in the variable curcontext, +# else a default context will be used (not recommended). +# +# You can override the use of word-chars with the style word-class. +# This specifies the same information, but as a character class. +# The surrounding square brackets shouldn't be given, but anything +# which can appear inside is allowed. For example, +# zstyle ':zle:*' word-class '-:[:alnum:]' +# is valid. Note the usual care with `]' , `^' and `-' must be taken if +# they need to appear as individual characters rather than for grouping. +# +# The final style is `skip-chars'. This is an integer; that many +# characters counting the one under the cursor will be treated as +# whitespace regardless and added to the front of the fourth element of +# matched_words. The default is zero, i.e. the character under the cursor +# will appear in <whitespace-after-cursor> if it is whitespace, else in +# <word-after-cursor>. This style is mostly useful for forcing +# transposition to ignore the current character. + + +emulate -L zsh +setopt extendedglob + +local wordstyle spacepat wordpat1 wordpat2 opt charskip +local match mbegin mend pat1 pat2 word1 word2 ws1 ws2 ws3 skip +local MATCH MBEGIN MEND + +if [[ -z $curcontext ]]; then + local curcontext=:zle:match-words-by-style +fi + +zstyle -s $curcontext word-style wordstyle +zstyle -s $curcontext skip-chars skip +[[ -z $skip ]] && skip=0 + +case $wordstyle in + (shell) local bufwords + # This splits the line into words as the shell understands them. + bufwords=(${(z)LBUFFER}) + # 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 + + # 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 + spacepat='[[:space:]]#' + ;; + (*space) spacepat='[[:space:]]#' + wordpat1='[^[:space:]]##' + wordpat2=$wordpat1 + ;; + (*) local wc + # See if there is a character class. + if zstyle -s $curcontext word-class wc; then + # Treat as a character class: do minimal quoting. + wc=${wc//(#m)[\'\"\`\$\(\)\^]/\\$MATCH} + else + # See if there is a local version of $WORDCHARS. + zstyle -s $curcontext word-chars wc || + wc=$WORDCHARS + if [[ $wc = (#b)(?*)-(*) ]]; then + # We need to bring any `-' to the front to avoid confusing + # character classes... we get away with `]' since in zsh + # this isn't a pattern character if it's quoted. + wc=-$match[1]$match[2] + fi + wc="${(q)wc}" + fi + # Quote $wc where necessary, because we don't want those + # characters to be considered as pattern characters later on. + if [[ $wordstyle = *specified ]]; then + if [[ $wordstyle != un* ]]; then + # The given set of characters are the word characters, nothing else + wordpat1="[${wc}]##" + # anything else is a space. + spacepat="[^${wc}]#" + else + # The other way round. + wordpat1="[^${wc}]##" + spacepat="[${wc}]#" + fi + else + # Normal: similar, but add alphanumerics. + wordpat1="[${wc}[:alnum:]]##" + spacepat="[^${wc}[:alnum:]]#" + fi + wordpat2=$wordpat1 + ;; +esac + +# The eval makes any special characters in the parameters active. +# In particular, we need the surrounding `[' s to be `real'. +# This is why we quoted the wordpats in the `shell' option, where +# they have to be treated as literal strings at this point. +match=() +eval pat1='${LBUFFER%%(#b)('${wordpat1}')('${spacepat}')}' +word1=$match[1] +ws1=$match[2] + +match=() +charskip= +repeat $skip charskip+=\? + +eval pat2='${RBUFFER##(#b)('${charskip}${spacepat}')('\ +${wordpat2}')('${spacepat}')}' + +ws2=$match[1] +word2=$match[2] +ws3=$match[3] + +matched_words=("$pat1" "$word1" "$ws1" "$ws2" "$word2" "$ws3" "$pat2") |