summaryrefslogtreecommitdiff
path: root/Functions/Zle
diff options
context:
space:
mode:
Diffstat (limited to 'Functions/Zle')
-rw-r--r--Functions/Zle/bracketed-paste-magic54
-rw-r--r--Functions/Zle/bracketed-paste-url-magic4
-rw-r--r--Functions/Zle/delete-whole-word-match15
-rw-r--r--Functions/Zle/expand-absolute-path2
-rw-r--r--Functions/Zle/history-beginning-search-menu2
-rw-r--r--Functions/Zle/match-words-by-style53
-rw-r--r--Functions/Zle/select-bracketed2
-rw-r--r--Functions/Zle/select-word-match120
-rw-r--r--Functions/Zle/surround7
-rw-r--r--Functions/Zle/vi-pipe39
-rw-r--r--Functions/Zle/zcalc-auto-insert3
11 files changed, 249 insertions, 52 deletions
diff --git a/Functions/Zle/bracketed-paste-magic b/Functions/Zle/bracketed-paste-magic
index 2b2bc630d..fb584d595 100644
--- a/Functions/Zle/bracketed-paste-magic
+++ b/Functions/Zle/bracketed-paste-magic
@@ -20,7 +20,7 @@
# active-widgets
# Looked up in the context :bracketed-paste-magic to obtain a list of
# patterns that match widget names that should be activated during the
-# paste. All other key sequences are processed as self-insert-unmeta.
+# paste. All other key sequences are processed as "zle .self-insert".
# The default is 'self-*' so any user-defined widgets named with that
# prefix are active along with the builtin self-insert. If this style is
# not set (note: it must be explicitly deleted after loading this
@@ -31,7 +31,7 @@
#
# inactive-keys
# This is the inverse of active-widgets, it lists key sequences that
-# always use self-insert-unmeta even when bound to an active-widget.
+# always use "zle .self-insert" even when bound to an active-widget.
# Note that this is a list of literal key sequences, not patterns.
# This style is in context :bracketed-paste-magic and has no default.
#
@@ -145,27 +145,26 @@ bracketed-paste-magic() {
done
fi
- # Save context, create a clean slate for the paste
- integer bpm_mark=$MARK bpm_cursor=$CURSOR bpm_region=$REGION_ACTIVE
- integer bpm_numeric=${NUMERIC:-1}
- local bpm_buffer=$BUFFER
- fc -p -a /dev/null 0 0
- BUFFER=
-
zstyle -a :bracketed-paste-magic inactive-keys bpm_inactive
if zstyle -s :bracketed-paste-magic active-widgets bpm_active '|'; then
- # There are active widgets. Reprocess $PASTED as keystrokes.
- NUMERIC=1
- zle -U - $PASTED
-
+ # Save context, create a clean slate for the paste
+ integer bpm_mark=$MARK bpm_region=$REGION_ACTIVE
+ integer bpm_numeric=${NUMERIC:-1}
+ integer bpm_limit=$UNDO_LIMIT_NO bpm_undo=$UNDO_CHANGE_NO
+ BUFFER=
+ CURSOR=1
+ zle .split-undo
+ UNDO_LIMIT_NO=$UNDO_CHANGE_NO
+ fc -p -a /dev/null 0 0
if [[ $bmp_keymap = vicmd ]]; then
zle -K viins
fi
+ # There are active widgets. Reprocess $PASTED as keystrokes.
+ NUMERIC=1
+ zle -U - "$PASTED"
+
# Just in case there are active undo widgets
- zle .split-undo
- integer bpm_limit=$UNDO_LIMIT_NO bpm_undo=$UNDO_CHANGE_NO
- UNDO_LIMIT_NO=$UNDO_CHANGE_NO
while [[ -n $PASTED ]] && zle .read-command; do
PASTED=${PASTED#$KEYS}
@@ -175,7 +174,7 @@ bracketed-paste-magic() {
case $REPLY in
(${~bpm_active}) function () {
emulate -L $bpm_emulate; set -$bpm_opts
- zle $REPLY
+ zle $REPLY -w
};;
(*) zle .self-insert;;
esac
@@ -183,21 +182,16 @@ bracketed-paste-magic() {
done
PASTED=$BUFFER
- # Reset the undo state
- zle undo $bpm_undo
- UNDO_LIMIT_NO=$bpm_limit
-
+ # Restore state
zle -K $bpm_keymap
+ fc -P
+ MARK=$bpm_mark
+ REGION_ACTIVE=$bpm_region
+ NUMERIC=$bpm_numeric
+ zle .undo $bpm_undo
+ UNDO_LIMIT_NO=$bpm_limit
fi
- # Restore state
- BUFFER=$bpm_buffer
- MARK=$bpm_mark
- CURSOR=$bpm_cursor
- REGION_ACTIVE=$bpm_region
- NUMERIC=$bpm_numeric
- fc -P
-
# PASTED has been updated, run the paste-finish functions
if zstyle -a :bracketed-paste-magic paste-finish bpm_hooks; then
for bpm_func in $bpm_hooks; do
@@ -212,7 +206,7 @@ bracketed-paste-magic() {
# Reprocess $PASTED as an actual paste this time
zle -U - $PASTED$'\e[201~' # append paste-end marker
- zle .bracketed-paste
+ zle .bracketed-paste -- "$@"
zle .split-undo
# Arrange to display highlighting if necessary
diff --git a/Functions/Zle/bracketed-paste-url-magic b/Functions/Zle/bracketed-paste-url-magic
index 06dee2657..b894696bb 100644
--- a/Functions/Zle/bracketed-paste-url-magic
+++ b/Functions/Zle/bracketed-paste-url-magic
@@ -19,7 +19,7 @@
# The default can be seen just below.
local -a schema
-zstyle -a :bracketed-paste-url-magic schema schema || schema=(http https ftp ftps file ssh sftp)
+zstyle -a :bracketed-paste-url-magic schema schema || schema=(http:// https:// ftp:// ftps:// file:// ssh:// sftp:// magnet:)
local wantquote=${NUMERIC:-0}
local content
@@ -28,7 +28,7 @@ local start=$#LBUFFER
zle .$WIDGET -N content
if (( $wantquote == 0 )); then
- if [[ $content = (${(~j:|:)schema})://* ]]; then
+ if [[ $content = (${(~j:|:)schema})* ]]; then
wantquote=1
fi
fi
diff --git a/Functions/Zle/delete-whole-word-match b/Functions/Zle/delete-whole-word-match
index aece86065..3d52dd3d7 100644
--- a/Functions/Zle/delete-whole-word-match
+++ b/Functions/Zle/delete-whole-word-match
@@ -12,30 +12,29 @@ emulate -L zsh
setopt extendedglob
local curcontext=:zle:$WIDGET
-local -a matched_words
+local -A matched_words
# Start and end of range of characters to remove.
integer pos1 pos2
autoload -Uz match-words-by-style
match-words-by-style
-if [[ -n "${matched_words[3]}" ]]; then
- # There's whitespace before the cursor, so the word we are deleting
- # starts at the cursor position.
+if (( ${matched_words[is-word-start]} )); then
+ # The word we are deleting starts at the cursor position.
pos1=$CURSOR
else
- # No whitespace before us, so delete any wordcharacters there.
- pos1="${#matched_words[1]}"
+ # Not, so delete any wordcharacters before, too
+ pos1="${#matched_words[start]}"
fi
-if [[ -n "${matched_words[4]}" ]]; then
+if [[ -n "${matched_words[ws-after-cursor]}" ]]; then
# There's whitespace at the cursor position, so only delete
# up to the cursor position.
(( pos2 = CURSOR + 1 ))
else
# No whitespace at the cursor position, so delete the
# current character and any following wordcharacters.
- (( pos2 = CURSOR + ${#matched_words[5]} + 1 ))
+ (( pos2 = CURSOR + ${#matched_words[word-after-cursor]} + 1 ))
fi
# Move the cursor then delete the block in one go for the
diff --git a/Functions/Zle/expand-absolute-path b/Functions/Zle/expand-absolute-path
index b85757600..4887f3c60 100644
--- a/Functions/Zle/expand-absolute-path
+++ b/Functions/Zle/expand-absolute-path
@@ -10,7 +10,7 @@ autoload -Uz modify-current-argument
if (( ! ${+functions[glob-expand-absolute-path]} )); then
glob-expand-absolute-path() {
local -a files
- files=(${~1}(N:A))
+ files=(${~1}(N:P))
(( ${#files} )) || return
REPLY=${(D)files[1]}
}
diff --git a/Functions/Zle/history-beginning-search-menu b/Functions/Zle/history-beginning-search-menu
index 105518102..0e1bbc734 100644
--- a/Functions/Zle/history-beginning-search-menu
+++ b/Functions/Zle/history-beginning-search-menu
@@ -112,7 +112,7 @@ fi
# go to the last one. This allows accept-line-and-down-history etc.
# to work.
local -a lines
-local matchq=${matches[$chars]//(#m)[\][()\\*?#<>~^]/\\$MATCH}
+local matchq=${matches[$chars]//(#m)[\][|()\\*?#<>~^]/\\$MATCH}
lines=(${(kon)history[(R)$matchq]})
HISTNO=$lines[-1]
diff --git a/Functions/Zle/match-words-by-style b/Functions/Zle/match-words-by-style
index 54e019d23..fc59c2764 100644
--- a/Functions/Zle/match-words-by-style
+++ b/Functions/Zle/match-words-by-style
@@ -5,8 +5,16 @@
# <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.
+# is to be interpreted as `after or on'.
+#
+# matched_words may be an associative array, in which case the
+# values above are now given by the elements named start, word-before-cursor,
+# ws-before-cursor, ws-after-cursor, word-after-cursor, ws-after-word,
+# end. In addition, the element is-word-start is 1 if the cursor
+# is on the start of a word; this is non-trivial in the case of subword
+# (camel case) matching as there may be no white space to test.
+#
+# Some of the array elements will be empty; this depends on the style.
# For example
# foo bar rod stick
# ^
@@ -202,7 +210,7 @@ if [[ $wordstyle = *subword* ]]; then
# 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
+ # isn't an upper case character instead of a lower case
# character.
# Here the initial "*" will match greedily, so we get the
# last such match, as we want.
@@ -224,11 +232,18 @@ charskip=${(l:skip::?:)}
eval pat2='${RBUFFER##(#b)('${charskip}${spacepat}')('\
${wordpat2}')('${spacepat}')}'
+if [[ -n $match[2] ]]; then
+ ws2=$match[1]
+ word2=$match[2]
+ ws3=$match[3]
+else
+ # No more words, so anything left is white space after cursor.
+ ws2=$RBUFFER
+ pat2=
+fi
-ws2=$match[1]
-word2=$match[2]
-ws3=$match[3]
-
+integer wordstart
+[[ ( -n $ws1 || -n $ws2 ) && -n $word2 ]] && wordstart=1
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)?
@@ -237,12 +252,19 @@ if [[ $wordstyle = *subword* ]]; then
-n $match[2] ]]; then
# Yes, so the last one is new word boundary.
(( epos = ${#match[1]} - 1 ))
+ # Otherwise, are we in the middle of a word?
+ # In other, er, words, we've got something on the left with no
+ # white space following and something that doesn't start a word here.
+ elif [[ -n $word1 && -z $ws1 && -z $ws2 && \
+ $word2 = (#b)([^${~subwordrange}]##)* ]]; then
+ (( epos = ${#match[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)(?[^${~subwordrange}]##)[${~subwordrange}]* ]]; then
(( epos = ${#match[1]} ))
+ (( wordstart = 1 ))
else
(( epos = 0 ))
fi
@@ -256,4 +278,19 @@ if [[ $wordstyle = *subword* ]]; then
fi
fi
-matched_words=("$pat1" "$word1" "$ws1" "$ws2" "$word2" "$ws3" "$pat2")
+# matched_words should be local to caller.
+# Just fix type here.
+if [[ ${(t)matched_words} = *association* ]]; then
+ matched_words=(
+ start "$pat1"
+ word-before-cursor "$word1"
+ ws-before-cursor "$ws1"
+ ws-after-cursor "$ws2"
+ word-after-cursor "$word2"
+ ws-after-word "$ws3"
+ end "$pat2"
+ is-word-start $wordstart
+ )
+else
+ matched_words=("$pat1" "$word1" "$ws1" "$ws2" "$word2" "$ws3" "$pat2")
+fi
diff --git a/Functions/Zle/select-bracketed b/Functions/Zle/select-bracketed
index 00f51be2c..d467bb804 100644
--- a/Functions/Zle/select-bracketed
+++ b/Functions/Zle/select-bracketed
@@ -12,6 +12,8 @@
# done
# done
+setopt localoptions noksharrays
+
local style=${${1:-$KEYS}[1]} matching="(){}[]<>bbBB"
local -i find=${NUMERIC:-1} idx=${matching[(I)[${${1:-$KEYS}[2]}]]}%9
(( idx )) || return 1 # no corresponding closing bracket
diff --git a/Functions/Zle/select-word-match b/Functions/Zle/select-word-match
new file mode 100644
index 000000000..8440852ab
--- /dev/null
+++ b/Functions/Zle/select-word-match
@@ -0,0 +1,120 @@
+# Select the entire word around the cursor. Intended for use as
+# a vim-style text object in vi mode but with customisable
+# word boundaries.
+#
+# For example:
+# autoload -U select-word-match
+# zle -N select-in-camel select-word-match
+# bindkey -M viopp ic select-in-camel
+# zstyle ':zle:*-camel' word-style normal-subword
+
+emulate -L zsh
+setopt extendedglob
+
+local curcontext=:zle:$WIDGET
+local -A matched_words
+# Start and end of range of characters
+integer pos1 pos2 num=${NUMERIC:-1}
+local style word
+
+# choose between inner word or a word style of widget
+for style in $1 ${${WIDGET#*-}[1]} $KEYS[1] "i"; do
+ [[ $style = [ai] ]] && break
+done
+
+autoload -Uz match-words-by-style
+
+while (( num-- )); do
+ if (( MARK > CURSOR )); then
+ # if cursor is at the start of the selection, just move back a word
+ match-words-by-style
+ if [[ $style = i && -n $matched_words[ws-before-cursor] ]]; then
+ word=$matched_words[ws-before-cursor]
+ else
+ word=$matched_words[word-before-cursor]$matched_words[ws-before-cursor]
+ fi
+ if [[ -n $word ]]; then
+ (( CURSOR -= ${#word} ))
+ else
+ return 1
+ fi
+ elif (( MARK >= 0 && MARK < CURSOR )); then
+ # cursor at the end, move forward a word
+ (( CURSOR+1 == $#BUFFER )) && return 1
+ (( CURSOR++ ))
+ match-words-by-style
+ if [[ -n $matched_words[ws-after-cursor] ]]; then
+ if [[ $style = i ]]; then
+ # just skip the whitespace
+ word=$matched_words[ws-after-cursor]
+ else
+ # skip the whitespace plus word
+ word=$matched_words[ws-after-cursor]$matched_words[word-after-cursor]
+ fi
+ else
+ if [[ $style = i ]]; then
+ # skip the word
+ word=$matched_words[word-after-cursor]
+ else
+ # skip word and following whitespace
+ word=$matched_words[word-after-cursor]$matched_words[ws-after-word]
+ fi
+ fi
+ (( CURSOR += ${#word} - 1 ))
+ else
+ match-words-by-style
+
+ if (( ${matched_words[is-word-start]} )); then
+ # The word we are selecting starts at the cursor position.
+ pos1=$CURSOR
+ else
+ # No whitespace before us, so select any wordcharacters there.
+ pos1="${#matched_words[start]}"
+ fi
+
+ if [[ -n "${matched_words[ws-after-cursor]}" ]]; then
+ if [[ -n "${matched_words[ws-before-cursor]}" ]] || (( CURSOR == 0 )); then
+ # whitespace either side, select it
+ (( pos1 = CURSOR - ${#matched_words[ws-before-cursor]} ))
+ (( pos2 = CURSOR + ${#matched_words[ws-after-cursor]} ))
+ else
+ # There's whitespace at the cursor position, so only select
+ # up to the cursor position.
+ (( pos2 = CURSOR + 1 ))
+ fi
+ else
+ # No whitespace at the cursor position, so select the
+ # current character and any following wordcharacters.
+ (( pos2 = CURSOR + ${#matched_words[word-after-cursor]} ))
+ fi
+
+ if [[ $style = a ]]; then
+ if [[ -n "${matched_words[ws-after-cursor]}" && ( -n "${matched_words[ws-before-cursor]}" || CURSOR -eq 0 ) ]]; then
+ # in the middle of whitespace so grab a word
+ if [[ -n "${matched_words[word-after-cursor]}" ]]; then
+ (( pos2 += ${#matched_words[word-after-cursor]} )) # preferably the one after
+ else
+ (( pos1 -= ${#matched_words[word-before-cursor]} )) # otherwise the one before
+ fi
+ elif [[ -n "${matched_words[ws-after-word]}" ]]; then
+ (( pos2 += ${#matched_words[ws-after-word]} ))
+ elif [[ -n "${matched_words[ws-before-cursor]}" ]]; then
+ # couldn't grab whitespace forwards so try backwards
+ (( pos1 -= ${#matched_words[ws-before-cursor]} ))
+ elif (( pos1 > 0 )); then
+ # There might have been whitespace before the word
+ (( CURSOR = pos1 ))
+ match-words-by-style
+ if [[ -n "${matched_words[ws-before-cursor]}" ]]; then
+ (( pos1 -= ${#matched_words[ws-before-cursor]} ))
+ fi
+ fi
+ fi
+
+ (( MARK = pos1, CURSOR = pos2-1 ))
+ fi
+done
+
+if [[ $KEYMAP == vicmd ]] && (( !REGION_ACTIVE )); then
+ (( CURSOR++ )) # Need to include cursor position for operators
+fi
diff --git a/Functions/Zle/surround b/Functions/Zle/surround
index b7be30b75..b51b77c04 100644
--- a/Functions/Zle/surround
+++ b/Functions/Zle/surround
@@ -19,6 +19,7 @@ local before after
local -A matching
matching=( \( \) \{ \} \< \> \[ \] )
+zle -f vichange
case $WIDGET in
change-*)
local MARK="$MARK" CURSOR="$CURSOR" call
@@ -69,7 +70,11 @@ case $WIDGET in
before="${(k)matching[(r)[$before:q]]}"
fi
CUTBUFFER="$before$CUTBUFFER$after"
- zle .vi-put-after -n 1
+ if [[ CURSOR -eq 0 || $BUFFER[CURSOR] = $'\n' ]]; then
+ zle .vi-put-before -n 1
+ else
+ zle .vi-put-after -n 1
+ fi
CUTBUFFER="$save_cut" CURSOR="$save_cur"
;;
esac
diff --git a/Functions/Zle/vi-pipe b/Functions/Zle/vi-pipe
new file mode 100644
index 000000000..1729cb6e1
--- /dev/null
+++ b/Functions/Zle/vi-pipe
@@ -0,0 +1,39 @@
+# Example of a widget that takes a vi motion
+
+# Filter part of buffer corresponding to a vi motion through an external
+# program.
+
+# To enable with vi compatible bindings use:
+# autoload -Uz vi-pipe
+# bindkey -a '!' vi-pipe
+
+setopt localoptions noksharrays
+
+autoload -Uz read-from-minibuffer
+local _save_cut="$CUTBUFFER" REPLY
+
+# mark this widget as a vi change so it can be repeated as a whole
+zle -f vichange
+
+# force movement to default to line mode
+(( REGION_ACTIVE )) || zle -U V
+# Use the standard vi-change to accept a vi motion.
+zle .vi-change || return
+read-from-minibuffer "!"
+zle .vi-cmd-mode
+local _save_cur=$CURSOR
+
+# cut buffer contains the deleted text and can be modified
+CUTBUFFER=$(eval "$REPLY" <<<"$CUTBUFFER")
+
+# put the modified text back in position.
+if [[ CURSOR -eq 0 || $BUFFER[CURSOR] = $'\n' ]]; then
+ # at the beginning of a line, vi-delete won't have moved the cursor
+ # back to a previous line
+ zle .vi-put-before -n 1
+else
+ zle .vi-put-after -n 1
+fi
+
+# restore cut buffer and cursor to the start of the range
+CUTBUFFER="$_save_cut" CURSOR="$_save_cur"
diff --git a/Functions/Zle/zcalc-auto-insert b/Functions/Zle/zcalc-auto-insert
index c9a5c8867..e1affd1c3 100644
--- a/Functions/Zle/zcalc-auto-insert
+++ b/Functions/Zle/zcalc-auto-insert
@@ -1,6 +1,7 @@
# Bind to a binary operator keystroke for use with zcalc
+# Not useful in RPN mode.
-if [[ -n $ZCALC_ACTIVE ]]; then
+if [[ -n $ZCALC_ACTIVE && $ZCALC_ACTIVE != rpn ]]; then
if [[ $CURSOR -eq 0 || $LBUFFER[-1] = "(" ]]; then
LBUFFER+=${ZCALC_AUTO_INSERT_PREFIX:-"ans "}
fi