1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-05-13 02:56:18 +02:00

35093: new zle widgets for Vim-style text objects

This commit is contained in:
Oliver Kiddle 2015-05-13 23:05:20 +02:00
parent f454ee26a8
commit d257f0143e
5 changed files with 217 additions and 0 deletions

View File

@ -1,3 +1,9 @@
2015-05-13 Oliver Kiddle <opk@zsh.org>
* 35093: NEWS, Functions/Zle/select-bracketed,
Functions/Zle/select-quoted, Functions/Zle/surround:
new zle widgets for Vim-style text objects
2015-05-13 Peter Stephenson <p.w.stephenson@ntlworld.com>
* 35114: Src/Modules/zutil.c: zformat -a multibyte char widths.

View File

@ -0,0 +1,56 @@
# Text object for matching characters between matching pairs of brackets
#
# So for example, given (( i+1 )), the vi command ci( will change
# all the text between matching colons.
#
# The following is an example of how to enable this:
# autoload -U select-bracketed
# zle -N select-bracketed
# for m in visual viopp; do
# for c in {a,i}${(s..)^:-'()[]{}<>bB'}; do
# bindkey -M $m $c select-bracketed
# done
# done
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
local lmatch=${matching[1 + (idx-1) & ~1]}
local rmatch=${matching[1 + (idx-1) | 1]}
local -i start=CURSOR+1 end=CURSOR+1 rfind=find
[[ $BUFFER[start] = "$rmatch" ]] && (( start--, end-- ))
if (( REGION_ACTIVE && MARK != CURSOR)); then
(( MARK < CURSOR && (start=end=MARK+1) ))
local -i origstart=start-1
[[ $style = i ]] && (( origstart-- ))
fi
while (( find )); do
for (( ; find && start; --start )); do
case $BUFFER[start] in
"$lmatch") (( find-- )) ;;
"$rmatch") (( find++ )) ;;
esac
done
(( find )) && return 1 # opening bracket not found
while (( rfind && end++ < $#BUFFER )); do
case $BUFFER[end] in
"$lmatch") (( rfind++ )) ;;
"$rmatch") (( rfind-- )) ;;
esac
done
(( rfind )) && return 1 # closing bracket not found
(( REGION_ACTIVE && MARK != CURSOR && start >= origstart &&
( find=rfind=${NUMERIC:-1} ) ))
done
[[ $style = i ]] && (( start++, end-- ))
(( REGION_ACTIVE = !!REGION_ACTIVE ))
[[ $KEYMAP = vicmd ]] && (( REGION_ACTIVE && end-- ))
MARK=$start
CURSOR=$end

View File

@ -0,0 +1,71 @@
# Text object for matching characters between a particular delimiter
#
# So for example, given "text", the vi command vi" will select
# all the text between the double quotes
#
# The following is an example of how to enable this:
# autoload -U select-quoted
# zle -N select-quoted
# for m in visual viopp; do
# for c in {a,i}{\',\",\`}; do
# bindkey -M $m $c select-quoted
# done
# done
setopt localoptions noksharrays
local matching=${${1:-$KEYS}[2]}
local -i start=CURSOR+2 end=CURSOR+2 found=0 alt=0 count=0
if ((REGION_ACTIVE )); then
if (( MARK < CURSOR )); then
start=MARK+2
else
end=MARK+2
fi
fi
[[ $BUFFER[CURSOR+1] = $matching && $BUFFER[CURSOR] != \\ ]] && count=1
while (( (count || ! alt) && --start )) && [[ $BUFFER[start] != $'\n' ]]; do
if [[ $BUFFER[start] = "$matching" ]]; then
if [[ $BUFFER[start-1] = \\ ]]; then
(( start-- ))
elif (( ! found )); then
found=start
else
(( ! alt )) && alt=start
(( count && ++count ))
fi
fi
done
for (( start=CURSOR+2; ! found && start+1 < $#BUFFER; start++ )); do
case $BUFFER[start] in
$'\n') return 1 ;;
\\) (( start++ )) ;;
"$matching")
(( end=start+1, found=start ))
;;
esac
done
[[ $BUFFER[end-1] = \\ ]] && (( end++ ))
until [[ $BUFFER[end] == "$matching" ]]; do
[[ $BUFFER[end] = \\ ]] && (( end++ ))
if [[ $BUFFER[end] = $'\n' ]] || (( ++end > $#BUFFER )); then
end=0
break
fi
done
if (( alt && (!end || count == 2) )); then
end=found
found=alt
fi
(( end )) || return 1
[[ ${${1:-$KEYS}[1]} = a ]] && (( found-- )) || (( end-- ))
(( REGION_ACTIVE = !!REGION_ACTIVE ))
[[ $KEYMAP = vicmd ]] && (( REGION_ACTIVE && end-- ))
MARK=found
CURSOR=end

75
Functions/Zle/surround Normal file
View File

@ -0,0 +1,75 @@
# Implementation of some functionality of the popular vim surround plugin.
# Allows "surroundings" to be changes: parentheses, brackets and quotes.
# To use
# autoload -Uz surround
# zle -N delete-surround surround
# zle -N add-surround surround
# zle -N change-surround surround
# bindkey -a cs change-surround
# bindkey -a ds delete-surround
# bindkey -a ys add-surround
# bindkey -M visual S add-surround
#
# This doesn't allow yss to operate on a line but VS will work
setopt localoptions noksharrays
autoload -Uz select-quoted select-bracketed
local before after
local -A matching
matching=( \( \) \{ \} \< \> \[ \] )
case $WIDGET in
change-*)
local MARK="$MARK" CURSOR="$CURSOR" call
read -k 1 before
if [[ ${(kvj::)matching} = *$before* ]]; then
call=select-bracketed
else
call=select-quoted
fi
read -k 1 after
$call "a$before" || return 1
before="$after"
if [[ -n $matching[$before] ]]; then
after=" $matching[$before]"
before+=' '
elif [[ -n $matching[(r)[$before:q]] ]]; then
before="${(k)matching[(r)[$before:q]]}"
fi
BUFFER[CURSOR]="$after"
BUFFER[MARK+1]="$before"
CURSOR=MARK
;;
delete-*)
local MARK="$MARK" CURSOR="$CURSOR" call
read -k 1 before
if [[ ${(kvj::)matching} = *$before* ]]; then
call=select-bracketed
else
call=select-quoted
fi
if $call "a$before"; then
BUFFER[CURSOR]=''
BUFFER[MARK+1]=''
CURSOR=MARK
fi
;;
add-*)
local save_cut="$CUTBUFFER"
zle .vi-change || return
local save_cur="$CURSOR"
zle .vi-cmd-mode
read -k 1 before
after="$before"
if [[ -n $matching[$before] ]]; then
after=" $matching[$before]"
before+=' '
elif [[ -n $matching[(r)[$before:q]] ]]; then
before="${(k)matching[(r)[$before:q]]}"
fi
CUTBUFFER="$before$CUTBUFFER$after"
zle .vi-put-after -n 1
CUTBUFFER="$save_cut" CURSOR="$save_cur"
;;
esac

9
NEWS
View File

@ -24,6 +24,15 @@ Changes from 5.0.7 to 5.0.8
as a reference to a variable, e.g. ${(ps.$sep.)foo} to split $foo
on a string given by $sep.
- The default binding of 'u' in vi command mode has changed to undo
multiple changes when invoked repeatedly. '^R' is now bound to redo
changes. To revert to toggling of the last edit use:
bindkey -a u vi-undo-change
- Compatibility with Vim has been improved for vi editing mode. Most
notably, Vim style text objects are supported and the region can be
manipulated with vi commands in the same manner as Vim's visual mode.
- Elements of the watch variable may now be patterns.
- The logic for retrying history locking has been improved.