From 86b8b5eaa346583300fa6f14fe1d0fe5beb096ba Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 24 Jun 2008 11:18:39 +0000 Subject: users/12987: add subword capability to word-style --- Functions/Zle/match-words-by-style | 56 +++++++++++++++++++++++++++++++++++--- Functions/Zle/select-word-style | 28 ++++++++++++------- 2 files changed, 70 insertions(+), 14 deletions(-) (limited to 'Functions') diff --git a/Functions/Zle/match-words-by-style b/Functions/Zle/match-words-by-style index ad74a984f..1597aa694 100644 --- a/Functions/Zle/match-words-by-style +++ b/Functions/Zle/match-words-by-style @@ -105,7 +105,7 @@ done [[ -z $skip ]] && skip=0 case $wordstyle in - (shell) local bufwords + (*shell*) local bufwords # This splits the line into words as the shell understands them. bufwords=(${(z)LBUFFER}) nwords=${#bufwords} @@ -133,7 +133,7 @@ case $wordstyle in wordpat2=${(q)wordpat2} fi ;; - (*space) spacepat='[[:space:]]#' + (*space*) spacepat='[[:space:]]#' wordpat1='[^[:space:]]##' wordpat2=$wordpat1 ;; @@ -160,8 +160,8 @@ case $wordstyle in 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 + if [[ $wordstyle = *specified* ]]; then + if [[ $wordstyle != *unspecified* ]]; then # The given set of characters are the word characters, nothing else wordpat1="[${wc}]##" # anything else is a space. @@ -189,6 +189,28 @@ eval pat1='${LBUFFER%%(#b)('${wordpat1}')('${spacepat}')}' word1=$match[1] ws1=$match[2] +if [[ $wordstyle = *subword* ]]; then + # The rule here is that a word boundary may be an upper case letter + # followed by a lower case letter, or an upper case letter at + # the start of a group of upper case letters. To make + # it easier to be consistent, we just use anything that + # isn't an upper case characer instead of a lower case + # character. + # Here the initial "*" will match greedily, so we get the + # last such match, as we want. + integer epos + if [[ $word1 = (#b)(*)([[:upper:]][^[:upper:]]*) ]]; then + (( epos = ${#match[1]} )) + fi + if [[ $word1 = (#b)(*[^[:upper:]])([[:upper:]]*) ]]; then + (( ${#match[1]} > epos )) && (( epos = ${#match[1]} )) + fi + if (( epos > 0 )); then + pat1+=$word1[1,epos] + word1=$word1[epos+1,-1] + fi +fi + match=() charskip= repeat $skip charskip+=\? @@ -200,4 +222,30 @@ ws2=$match[1] word2=$match[2] ws3=$match[3] +if [[ $wordstyle = *subword* ]]; then + # Do we have a group of upper case characters at the start + # of word2 (that don't form the entire word)? + # Again, rely on greedy matching of first pattern. + if [[ $word2 = (#b)([[:upper:]][[:upper:]]##)(*) && -n $match[2] ]]; then + # Yes, so the last one is new word boundary. + (( epos = ${#match[1]} - 1 )) + # Otherwise, do we have upper followed by non-upper not + # at the start? Ignore the initial character, we already + # know it's a word boundary so it can be an upper case character + # if it wants. + elif [[ $word2 = (#b)(?[^[:upper:]]##)[[:upper:]]* ]]; then + (( epos = ${#match[1]} )) + else + (( epos = 0 )) + fi + if (( epos )); then + # Careful: if we matched a subword there's no whitespace immediately + # after the matched word, so ws3 should be empty and any existing + # value tacked onto pat2. + pat2="${word2[epos+1,-1]}$ws3$pat2" + ws3= + word2=$word2[1,epos] + fi +fi + matched_words=("$pat1" "$word1" "$ws1" "$ws2" "$word2" "$ws3" "$pat2") diff --git a/Functions/Zle/select-word-style b/Functions/Zle/select-word-style index afea5b193..9c0fdb5cc 100644 --- a/Functions/Zle/select-word-style +++ b/Functions/Zle/select-word-style @@ -10,7 +10,7 @@ word_functions=(backward-kill-word backward-word [[ -z $1 ]] && autoload read-from-minibuffer -local REPLY detail f +local REPLY detail f wordstyle if ! zle -l $word_functions[1]; then for f in $word_functions; do @@ -25,6 +25,7 @@ while true; do if [[ -n $WIDGET && -z $1 ]]; then read-from-minibuffer -k1 "Word styles (hit return for more detail): (b)ash (n)ormal (s)hell (w)hitespace (d)efault (q)uit +(B), (N), (S), (W) as above with subword matching ${detail}? " || return 1 else REPLY=$1 @@ -33,31 +34,31 @@ ${detail}? " || return 1 detail= case $REPLY in - (b*) + ([bB]*) # bash style - zstyle ':zle:*' word-style standard + wordstyle=standard zstyle ':zle:*' word-chars '' ;; - (n*) + ([nN]*) # normal zsh style - zstyle ':zle:*' word-style standard + wordstyle=standard zstyle ':zle:*' word-chars "$WORDCHARS" ;; - (s*) + ([sS]*) # shell command arguments or special tokens - zstyle ':zle:*' word-style shell + wordstyle=shell ;; - (w*) + ([wW]*) # whitespace-delimited - zstyle ':zle:*' word-style space + wordstyle=space ;; (d*) # default: could also return widgets to builtins here - zstyle -d ':zle:*' word-style + wordstyle= zstyle -d ':zle:*' word-chars ;; @@ -84,5 +85,12 @@ $detail" >&2 continue ;; esac + + if [[ -n $wordstyle ]]; then + if [[ $REPLY = [[:upper:]]* ]]; then + wordstyle+=-subword + fi + zstyle ':zle:*' word-style $wordstyle + fi return done -- cgit 1.4.1