summaryrefslogtreecommitdiff
path: root/Functions
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2003-03-28 11:34:07 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2003-03-28 11:34:07 +0000
commit1e57c42f470bdd2ab6179ec44dae96fd3377a1dd (patch)
tree5f9c38c21bcbbcba7b7524f9df7e4f99b8344424 /Functions
parent2941469f616202f51da7ba9ceafa3f419f34573b (diff)
downloadzsh-1e57c42f470bdd2ab6179ec44dae96fd3377a1dd.tar.gz
zsh-1e57c42f470bdd2ab6179ec44dae96fd3377a1dd.zip
18394: New word movement and editing widgets.
Diffstat (limited to 'Functions')
-rw-r--r--Functions/Zle/backward-kill-word-match36
-rw-r--r--Functions/Zle/backward-word-match29
-rw-r--r--Functions/Zle/capitalize-word-match23
-rw-r--r--Functions/Zle/down-case-word-match23
-rw-r--r--Functions/Zle/forward-word-match39
-rw-r--r--Functions/Zle/kill-word-match36
-rw-r--r--Functions/Zle/match-words-by-style167
-rw-r--r--Functions/Zle/read-from-minibuffer32
-rw-r--r--Functions/Zle/select-word-style88
-rw-r--r--Functions/Zle/transpose-words-match31
-rw-r--r--Functions/Zle/up-case-word-match23
11 files changed, 523 insertions, 4 deletions
diff --git a/Functions/Zle/backward-kill-word-match b/Functions/Zle/backward-kill-word-match
new file mode 100644
index 000000000..77ad7bf1a
--- /dev/null
+++ b/Functions/Zle/backward-kill-word-match
@@ -0,0 +1,36 @@
+emulate -L zsh
+setopt extendedglob
+
+autoload match-words-by-style
+
+local curcontext=":zle:$WIDGET" word done
+local -a matched_words
+integer count=${NUMERIC:-1}
+
+if (( count < 0 )); then
+ (( NUMERIC = -count ))
+ zle ${WIDGET##backward-}
+ return
+fi
+
+while (( count-- )); do
+
+ match-words-by-style
+
+ word="$matched_words[2]$matched_words[3]"
+
+ if [[ -n $word ]]; then
+ if [[ -n $done || $LASTWIDGET = *kill* ]]; then
+ CUTBUFFER="$word$CUTBUFFER"
+ else
+ killring=("$CUTBUFFER" "${(@)killring[1,-2]}")
+ CUTBUFFER=$word
+ fi
+ LBUFFER=$matched_words[1]
+ else
+ return 1
+ fi
+ done=1
+done
+
+return 0
diff --git a/Functions/Zle/backward-word-match b/Functions/Zle/backward-word-match
new file mode 100644
index 000000000..bda10d1c4
--- /dev/null
+++ b/Functions/Zle/backward-word-match
@@ -0,0 +1,29 @@
+emulate -L zsh
+setopt extendedglob
+
+autoload match-words-by-style
+
+local curcontext=":zle:$WIDGET" word
+local -a matched_words
+integer count=${NUMERIC:-1}
+
+if (( count < 0 )); then
+ (( NUMERIC = - count ))
+ zle ${WIDGET/backward/forward}
+ return
+fi
+
+while (( count-- )); do
+
+ match-words-by-style
+
+ word=$matched_words[2]$matched_words[3]
+
+ if [[ -n $word ]]; then
+ (( CURSOR -= ${#word} ))
+ else
+ return 1
+ fi
+done
+
+return 0
diff --git a/Functions/Zle/capitalize-word-match b/Functions/Zle/capitalize-word-match
new file mode 100644
index 000000000..aa25b8e02
--- /dev/null
+++ b/Functions/Zle/capitalize-word-match
@@ -0,0 +1,23 @@
+emulate -L zsh
+setopt extendedglob
+
+autoload match-words-by-style
+
+local curcontext=":zle:$WIDGET" word
+local -a matched_words
+integer count=${NUMERIC:-1}
+
+while (( count-- > 0 )); do
+ match-words-by-style
+
+ word=${(j..)matched_words[4,5]}
+
+ if [[ -n $word ]]; then
+ LBUFFER+=${(C)word}
+ RBUFFER=${(j..)matched_words[6,7]}
+ else
+ return 1
+ fi
+done
+
+return 0
diff --git a/Functions/Zle/down-case-word-match b/Functions/Zle/down-case-word-match
new file mode 100644
index 000000000..87d543f8d
--- /dev/null
+++ b/Functions/Zle/down-case-word-match
@@ -0,0 +1,23 @@
+emulate -L zsh
+setopt extendedglob
+
+autoload match-words-by-style
+
+local curcontext=":zle:$WIDGET" word
+local -a matched_words
+integer count=${NUMERIC:-1}
+
+while (( count-- > 0 )); do
+ match-words-by-style
+
+ word=${(j..)matched_words[4,5]}
+
+ if [[ -n word ]]; then
+ LBUFFER+=${(L)word}
+ RBUFFER=${(j..)matched_words[6,7]}
+ else
+ return 1
+ fi
+done
+
+return 0
diff --git a/Functions/Zle/forward-word-match b/Functions/Zle/forward-word-match
new file mode 100644
index 000000000..65bed784d
--- /dev/null
+++ b/Functions/Zle/forward-word-match
@@ -0,0 +1,39 @@
+emulate -L zsh
+setopt extendedglob
+
+autoload match-words-by-style
+
+local curcontext=":zle:$WIDGET" word
+local -a matched_words
+integer count=${NUMERIC:-1}
+
+if (( count < 0 )); then
+ (( NUMERIC = -count ))
+ zle ${WIDGET/forward/backward}
+ return
+fi
+
+while (( count-- )); do
+
+ match-words-by-style
+
+ # For some reason forward-word doesn't work like the other word
+ # word commnds; it skips whitespace only after any matched word
+ # characters.
+
+ if [[ -n $matched_words[4] ]]; then
+ # just skip the whitespace
+ word=$matched_words[4]
+ else
+ # skip the word and trailing whitespace
+ word=$matched_words[5]$matched_words[6]
+ fi
+
+ if [[ -n $word ]]; then
+ (( CURSOR += ${#word} ))
+ else
+ return 1
+ fi
+done
+
+return 0
diff --git a/Functions/Zle/kill-word-match b/Functions/Zle/kill-word-match
new file mode 100644
index 000000000..9d21c4a15
--- /dev/null
+++ b/Functions/Zle/kill-word-match
@@ -0,0 +1,36 @@
+emulate -L zsh
+setopt extendedglob
+
+autoload match-words-by-style
+
+local curcontext=":zle:$WIDGET" word done
+local -a matched_words
+integer count=${NUMERIC:-1}
+
+if (( count < 0 )); then
+ (( NUMERIC = -count ))
+ zle backward-$WIDGET
+ return
+fi
+
+while (( count-- )); do
+
+ match-words-by-style
+
+ word="${(j..)matched_words[4,5]}"
+
+ if [[ -n $word ]]; then
+ if [[ -n $done || $LASTWIDGET = *kill* ]]; then
+ CUTBUFFER="$CUTBUFFER$word"
+ else
+ killring=("$CUTBUFFER" "${(@)killring[1,-2]}")
+ CUTBUFFER=$word
+ fi
+ RBUFFER=$matched_words[6]
+ else
+ return 1
+ fi
+ done=1
+done
+
+return 0
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")
diff --git a/Functions/Zle/read-from-minibuffer b/Functions/Zle/read-from-minibuffer
index 93eec42a5..6af7f2a39 100644
--- a/Functions/Zle/read-from-minibuffer
+++ b/Functions/Zle/read-from-minibuffer
@@ -1,3 +1,22 @@
+emulate -L zsh
+setopt extendedglob
+
+local opt keys
+integer stat
+
+while getopts "k:" opt; do
+ case $opt in
+ (k)
+ keys=$OPTARG
+ ;;
+
+ (*)
+ return 1
+ ;;
+ esac
+done
+(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
+
local savelbuffer=$LBUFFER saverbuffer=$RBUFFER
local savepredisplay=$PREDISPLAY savepostdisplay=$POSTDISPLAY
@@ -7,10 +26,15 @@ PREDISPLAY="$PREDISPLAY$savelbuffer$saverbuffer$POSTDISPLAY
${1:-? }"
POSTDISPLAY=
-zle recursive-edit
-integer stat=$?
-
-(( stat )) || REPLY=$BUFFER
+if [[ -n $keys ]]; then
+ zle -R
+ read -k $keys
+ stat=$?
+else
+ zle recursive-edit
+ stat=$?
+ (( stat )) || REPLY=$BUFFER
+fi
LBUFFER=$savelbuffer
RBUFFER=$saverbuffer
diff --git a/Functions/Zle/select-word-style b/Functions/Zle/select-word-style
new file mode 100644
index 000000000..288517ef1
--- /dev/null
+++ b/Functions/Zle/select-word-style
@@ -0,0 +1,88 @@
+emulate -L zsh
+setopt extendedglob
+
+local -a word_functions
+
+word_functions=(backward-kill-word backward-word
+ capitalize-word down-case-word
+ forward-word kill-word
+ transpose-words up-case-word)
+
+[[ -z $1 ]] && autoload read-from-minibuffer
+
+local REPLY detail f
+
+if ! zle -l $word_functions[1]; then
+ for f in $word_functions; do
+ autoload -U $f-match
+ zle -N $f $f-match
+ done
+fi
+
+
+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 (N)one (A)bort
+${detail}? " || return 1
+ else
+ REPLY=$1
+ fi
+
+ detail=
+
+ case $REPLY in
+ (b*)
+ # bash style
+ zstyle ':zle:*' word-style standard
+ zstyle ':zle:*' word-chars ''
+ ;;
+
+ (n*)
+ # normal zsh style
+ zstyle ':zle:*' word-style standard
+ zstyle ':zle:*' word-chars "$WORDCHARS"
+ ;;
+
+ (s*)
+ # shell command arguments or special tokens
+ zstyle ':zle:*' word-style shell
+ ;;
+
+ (w*)
+ # whitespace-delimited
+ zstyle ':zle:*' word-style space
+ ;;
+
+ (d*)
+ # default: could also return widgets to builtins here
+ zstyle -d ':zle:*' word-style
+ zstyle -d ':zle:*' word-chars
+ ;;
+
+ (q*)
+ # quit without setting
+ return 1
+ ;;
+
+ (*)
+ detail="\
+(b)ash: Word characters are alphanumerics only
+(n)ormal: Word characters are alphanumerics plus \$WORDCHARS
+(s)hell: Words are command arguments using shell syntax
+(w)hitespace: Words are whitespace-delimited
+(d)efault: Use default, no special handling (usually same as \`n')
+(q)uit: Quit without setting a new style
+"
+ if [[ -z $WIDGET || -n $1 ]]; then
+ print "Usage: $0 word-style
+where word-style is one of the characters in parentheses:
+$detail" >&2
+ return 1
+ fi
+ continue
+ ;;
+ esac
+ return
+done
diff --git a/Functions/Zle/transpose-words-match b/Functions/Zle/transpose-words-match
new file mode 100644
index 000000000..52891b6ac
--- /dev/null
+++ b/Functions/Zle/transpose-words-match
@@ -0,0 +1,31 @@
+# Transpose words, matching the words using match-words-by-style, q.v.
+# The group of word characters preceeding the cursor (not necessarily
+# immediately) are transposed with the group of word characters following
+# the cursor (again, not necessarily immediately).
+#
+# Note the style skip-chars, used in the context of the current widget.
+# This gives a number of character starting from the cursor position
+# which are never considered part of a word and hence are always left
+# alone. The default is 0 and typically the only useful alternative
+# is one. This would have the effect that `fooXbar' with the cursor
+# on X would be turned into `barXfoo' with the cursor still on the X,
+# regardless of what the character X is.
+
+autoload match-words-by-style
+
+local curcontext=":zle:$WIDGET" skip
+local -a matched_words
+integer count=${NUMERIC:-1}
+
+while (( count-- > 0 )); do
+ match-words-by-style
+
+ [[ -z "$matched_words[2]$matched_words[5]" ]] && return 1
+
+ LBUFFER="$matched_words[1]$matched_words[5]${(j..)matched_words[3,4]}\
+$matched_words[2]"
+ RBUFFER="${(j..)matched_words[6,7]}"
+
+done
+
+return 0
diff --git a/Functions/Zle/up-case-word-match b/Functions/Zle/up-case-word-match
new file mode 100644
index 000000000..781290332
--- /dev/null
+++ b/Functions/Zle/up-case-word-match
@@ -0,0 +1,23 @@
+emulate -L zsh
+setopt extendedglob
+
+autoload match-words-by-style
+
+local curcontext=":zle:$WIDGET" word
+local -a matched_words
+integer count=${NUMERIC:-1}
+
+while (( count-- > 0 )); do
+ match-words-by-style
+
+ word=${(j..)matched_words[4,5]}
+
+ if [[ -n $word ]]; then
+ LBUFFER+=${(U)word}
+ RBUFFER=${(j..)matched_words[6,7]}
+ else
+ return 1
+ fi
+done
+
+return 0